[ub] type punning through congruent base class?

James Dennett jdennett at google.com
Thu Jan 16 21:01:26 CET 2014


On Thu, Jan 16, 2014 at 11:44 AM, Herb Sutter <hsutter at microsoft.com> wrote:
>> |   struct B { int x; };  // 1
>> |   void* p = malloc(sizeof(B)); // 2
>> |   B* pb = static_cast<B*>(p); //3
>> |   pb->x = 17; // 4
>> |
>> | I take it as obvious that the lifetime of an object of type B has
>> | begun somewhere in this code snippet. Now the question is: which
>> | specific line begins that lifetime? As you say, casting a pointer
>> | doesn't begin or end a lifetime; I think we can rule out line 3 as the
>> | one that begins the lifetime of that B object. Line 1 doesn't look too
>> promising either.
>>
>> Well, in fact I don't take it obvious that the lifetime of an object has even
>> begun!
>> I don't even see that or object has been constructed or initialized.
>
> Agreed. I would expect line 4 to be at least unspecified behavior and probably undefined behavior.

I feel like I must have missed part of the conversation.

We want to utterly break compatibility with C (and C-like C++ code) here?

struct B { int x };
struct B* p = (B*) malloc(sizeof(B));
p->x = 17;

This (modulo the cast) has been how C has handled dynamic allocation
of structs approximately forever.  There are no constructors in C,
structs don't get initialized, their fields just get assigned to.
When compiled as C++, no constructor is called here either.  And we've
allowed that.

The issue we're dealing with here is that C allowed writing to a
suitably-aligned chunk of memory (from malloc(), at least) as if it
were an object.  There is no process whereby the storage _becomes_ an
object.  You just use it.

We can't adopt a stricter model without breaking existing code.  I'm
fine with breaking existing code, except that I suspect we'd break so
much that it would never all get fixed, and it's a silent breaking
change in many cases.

-- James


More information about the ub mailing list