C++ Logo


Advanced search

Re: [ub] type punning through congruent base class?

From: Gabriel Dos Reis <gdr_at_[hidden]>
Date: Thu, 16 Jan 2014 20:53:54 +0000
| -----Original Message-----
| From: ub-bounces_at_[hidden] [mailto:ub-bounces_at_[hidden]] On
| Behalf Of James Dennett
| Sent: Thursday, January 16, 2014 12:01 PM
| To: WG21 UB study group
| Cc: Bjarne Stroustrup
| Subject: Re: [ub] type punning through congruent base class?
| On Thu, Jan 16, 2014 at 11:44 AM, Herb Sutter <hsutter_at_[hidden]>
| 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?

This is the first time you are mentioning and I feel like I was following the discussion, yet I've read anything to that effect.

I think it is also important to look at what the C standards actually say on this matter (e.g. object lifetime) before concluding that there is an effort to utterly break compatibility with C.

Both languages have a notion of 'lifetime' that they more or less define accurately or completely. It is not clear that C could just adopt C++'s notion and be OK or that C++ could just adopt C's and be OK. And in fact, neither did. What they have done is to translate some perception of what they want into their own models. So, when we make claim that there is attempt to break C compatibility, we might want to be more precise about the part of the translation we are worried about.

C's object model is based on a certain notion of lifetime (with some *expected* guarantees, that isn't obvious are held) and notion "effective type". C++ doesn't use effective type; rather it uses the notion of 'dynamic type' which is tightly coupled with the notion of constructor (which C does not have.)

| 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.

Could you walk us through the C standards and explain what you believe this program fragment is supposed to do and what actually is at the address pointed by p?
I think that will be a very illuminating exercise -- and would possibly help clear some confusions.

| When compiled as C++, no constructor is called here either. And we've
| allowed that.

We have to allow something and define something. What I feel strongly about is the current interpretation that once a blob of memory is obtained with a given alignment and size, then an object's life time has begun. I don't think that is OK.

Even if we take the C model, it is not clear what is there. We can infer that after the statement 'p->x = 17;' the storage at address '&p-x' has effective type 'int', but that does not say much about the rest. I -suspect- C is OK with that because fundamentally, its object model is structural.

| 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.

really? Which parts of the C standards support that?

| 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.

I think we may be getting ahead of ourselves a little bit here.

-- Gaby

Received on 2014-01-16 21:54:05