Topic: Implicit Copy Constructor Bug?
Author: jkanze@otelo.ibmmail.com
Date: 1998/04/17 Raw View
In article <6h3k7g$dl5@netlab.cs.rpi.edu>,
jpotter@falcon.lhup.edu (John Potter) wrote:
>
> Jim.Melton@lmco.com (Jim Melton) wrote:
>
> : In article <6gmuaq$7cb@netlab.cs.rpi.edu>, khopps@Adobe.COM wrote:
>
> : > As I read the WP, the implicit copy constructor is supposed to do a
> : > memberwise copy.
> : >
> : > My question is, is an implementation allowed to touch bytes in the
> : > struct which are not named? Should the following be guaranteed to
work,
> : > assuming you get past the first assert?
>
> : Why should it? The code does exactly what the standard said it should:
> : memberwise copy of the class members.
>
> Not exactly.
>
> : Given different alignment restrictions of different hardware
> : architectures, how can the standard say *anything* about what happens to
> : (or even if there is any) padding?
>
> Kevin thinks that it does say something.
>
> : > struct Thing
> : > {
>
> // Let's add some things and see what happens
> Thing () { }
> Thing (Thing const& src) : i(src.i), c(src.c) { }
> // This copy ctor is what the standard mandates, I think.
>
> : > int i;
> : > char c;
> : > };
> : >
> : > int main()
> : > {
> : > assert(sizeof(Thing) == 2*sizeof(int));
> : > int aBuf[2];
> : > int bBuf[2];
> : > aBuf[0] = aBuf[1] = 0xffffffff;
> : > bBuf[0] = bBuf[1] = 0;
> : > Thing* ap = new(aBuf) Thing;
> : > ap->i = 0;
> : > ap->c = 0;
> : > assert(aBuf[1] != 0);
> : > Thing* bp = new(bBuf) Thing(*ap);
> : > assert(bBuf[0] == 0 && bBuf[1] == 0); // VC++ 5.0 aborts here
> : > return 0;
> : > }
> : >
> : > Sure enough, bBuf[1]==0xffffff00.
>
> : Without compiling this, assuming similar behavior, on my system bBuf[1]
> : would be 0x00ffffff. What assumptions can you make about that?
>
> Any of 0x00ffffff, 0xff00ffff, 0xffff00ff, 0xffffff00 would be allowed
> on either big or little endian machines if the implementation is
> allowed to touch padding.
Anything is allowed in the padding. The standard also makes no
guarantees as to the location of the padding, although in this
case, it is hard to imagine an implementation putting it anywhere
but at the end.
There is one interesting question here, however: can a program
count on the previous contents of a buffer passed to placement new.
I don't believe so, but I'm not sure.
> : Your "poor man's union" construct seems designed with one purpose in
mind:
> : to trick the compiler. You succeeded. Why do you want to do such a thing?
> : How can any (non-member, non-friend) code which relies on the internal
> : *compiler* representation of an object be anything other than flawed from
> : the beginning?
>
> Your practical answer is appropriate for clc++m; however, I think
> Kevin is asking a standards question which belongs in csc++. I have
> crossposted and set followups to csc++.
>
> With the above additions, Kevin's program does not abort. With only
> the default ctor, it aborts. Are his and my (bigendian) compilers
> conformant is the real question.
Yes. At least from these programs. You invoke undefined behavior,
since you access data through a type different from which it was
created. Once you call the constructor of Thing on bBuf, any access
to bBuf other than as a Thing is undefined behavior, and no access
to it as a Thing can determine the value of the padding bytes. So
the compiler is free to do with them what it wants.
The only point I see as uncertain is when exactly the previous contents
of bBuf cease to be guaranteed. Suppose, for example, that a compiler
generates code which systematically sets all "undefined" bytes to 0xd5.
(This is useful for debugging, for example, to detect if you accidentally
are counting on specific undefined values.) With normal new, I see no
problem; the code can be in the operator new function. But suppose that
I define my own placement new, e.g.:
enum MyNew { myNew } ;
void* operator new( size_t howMuch , void* where , MyNew ) ;
When can the compiler legally change the values: before the physical
call to this operator new function, or only after (or neither -- suppose
that I know that where always points to static memory that has been
zero initialized, and that this is the only operator new used for the
class).
(Note that I must use a special placement new for this operation, since
the semantics of the normal placement operator new function are strictly
defined by the standard, and they don't depend on the previous contents.)
Of course, this question is irrelevant to the initial problem; once
the constructor for Thing has been called, the memory in the range
[bBuf...bBuf+sizeof( Thing )) is a Thing, and accessing it in any
other way is undefined behavior.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
+49 (0)69 66 45 33 10 mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient e objet --
-- Beratung in objektorientierter Datenverarbeitung
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/ Now offering spam-free web-based newsreading
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1998/04/20 Raw View
[given...]
> > : > struct Thing
> > : > {
> > : > int i;
> > : > char c;
> > : > };
jkanze@otelo.ibmmail.com wrote:
>
> Anything is allowed in the padding. The standard also makes no
> guarantees as to the location of the padding, although in this
> case, it is hard to imagine an implementation putting it anywhere
> but at the end.
I could imagine a big-endian system inserting padding before the
character, and any system initializing the padding with zeroes. Since a
strictly conforming program can't get at the padding, the compiler could
then make most accesses to the character with word operations (with no
sign extension, of course) instead of byte operations. This would work
especially well for unsigned chars, and I believe that it's a conforming
optimization.
The compiler would need to be careful with some operations (like
shifts), but it could be a win overall.
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds
My reply address is correct as-is. The courtesy of providing a correct
reply address is more important to me than time spent deleting spam.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1998/04/16 Raw View
Jim.Melton@lmco.com (Jim Melton) wrote:
: In article <6gmuaq$7cb@netlab.cs.rpi.edu>, khopps@Adobe.COM wrote:
: > As I read the WP, the implicit copy constructor is supposed to do a
: > memberwise copy.
: >
: > My question is, is an implementation allowed to touch bytes in the
: > struct which are not named? Should the following be guaranteed to work,
: > assuming you get past the first assert?
: Why should it? The code does exactly what the standard said it should:
: memberwise copy of the class members.
Not exactly.
: Given different alignment restrictions of different hardware
: architectures, how can the standard say *anything* about what happens to
: (or even if there is any) padding?
Kevin thinks that it does say something.
: > struct Thing
: > {
// Let's add some things and see what happens
Thing () { }
Thing (Thing const& src) : i(src.i), c(src.c) { }
// This copy ctor is what the standard mandates, I think.
: > int i;
: > char c;
: > };
: >
: > int main()
: > {
: > assert(sizeof(Thing) == 2*sizeof(int));
: > int aBuf[2];
: > int bBuf[2];
: > aBuf[0] = aBuf[1] = 0xffffffff;
: > bBuf[0] = bBuf[1] = 0;
: > Thing* ap = new(aBuf) Thing;
: > ap->i = 0;
: > ap->c = 0;
: > assert(aBuf[1] != 0);
: > Thing* bp = new(bBuf) Thing(*ap);
: > assert(bBuf[0] == 0 && bBuf[1] == 0); // VC++ 5.0 aborts here
: > return 0;
: > }
: >
: > Sure enough, bBuf[1]==0xffffff00.
: Without compiling this, assuming similar behavior, on my system bBuf[1]
: would be 0x00ffffff. What assumptions can you make about that?
Any of 0x00ffffff, 0xff00ffff, 0xffff00ff, 0xffffff00 would be allowed
on either big or little endian machines if the implementation is
allowed to touch padding.
: Your "poor man's union" construct seems designed with one purpose in mind:
: to trick the compiler. You succeeded. Why do you want to do such a thing?
: How can any (non-member, non-friend) code which relies on the internal
: *compiler* representation of an object be anything other than flawed from
: the beginning?
Your practical answer is appropriate for clc++m; however, I think
Kevin is asking a standards question which belongs in csc++. I have
crossposted and set followups to csc++.
With the above additions, Kevin's program does not abort. With only
the default ctor, it aborts. Are his and my (bigendian) compilers
conformant is the real question.
The same applies to the copy assignment operator.
I can imagine that the observed behavior is allowed, but have not been
able to find a reference. I do find it frustrating when a program
performs differently when I write a ctor which matches what the
standard says must be implicetly created and when I allow the
implementation to do it.
John
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng (Steve Clamage)
Date: 1998/04/16 Raw View
In article dl5@netlab.cs.rpi.edu, jpotter@falcon.lhup.edu (John Potter) writes:
>Jim.Melton@lmco.com (Jim Melton) wrote:
>
>: In article <6gmuaq$7cb@netlab.cs.rpi.edu>, khopps@Adobe.COM wrote:
>
>: > As I read the WP, the implicit copy constructor is supposed to do a
>: > memberwise copy.
>: >
>: > My question is, is an implementation allowed to touch bytes in the
>: > struct which are not named? Should the following be guaranteed to work,
>: > assuming you get past the first assert?
>
>: Why should it? The code does exactly what the standard said it should:
>: memberwise copy of the class members.
>
>Not exactly.
>
>: Given different alignment restrictions of different hardware
>: architectures, how can the standard say *anything* about what happens to
>: (or even if there is any) padding?
>
>Kevin thinks that it does say something.
But no standard-conforming program can tell whether the padding
bytes are touched. To access the padding bytes, if there are any,
you need to perform type punning. Depending on how you do the
punning, you get either undefined or implementation-dependent
behavior.
>: > struct Thing
>: > {
>
>// Let's add some things and see what happens
> Thing () { }
> Thing (Thing const& src) : i(src.i), c(src.c) { }
>// This copy ctor is what the standard mandates, I think.
>
>: > int i;
>: > char c;
>: > };
>: >
>: > int main()
>: > {
>: > assert(sizeof(Thing) == 2*sizeof(int));
>: > int aBuf[2];
>: > int bBuf[2];
>: > aBuf[0] = aBuf[1] = 0xffffffff;
>: > bBuf[0] = bBuf[1] = 0;
>: > Thing* ap = new(aBuf) Thing;
>: > ap->i = 0;
>: > ap->c = 0;
>: > assert(aBuf[1] != 0);
>: > Thing* bp = new(bBuf) Thing(*ap);
>: > assert(bBuf[0] == 0 && bBuf[1] == 0); // VC++ 5.0 aborts here
>: > return 0;
>: > }
This code has undefined results, because a Thing is created,
but accessed as "array of int". You are not entitled to assume
that either of the last two asserts will pass or fail.
As far as I can tell, the standard is silent about what happens to
padding bits during copies and initialization, and the implementation
doesn't have to tell you whether they are touched. (If you use
bitfields, you can get bits as padding.)
Portable code should assume that padding bits always have unknown values.
---
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]