C++ Logo


Advanced search

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

From: Richard Smith <richardsmith_at_[hidden]>
Date: Thu, 16 Jan 2014 13:48:18 -0800
On 16 January 2014 13:10, Herb Sutter <hsutter_at_[hidden]> wrote:

> > > | > Well, as far as I understand, trivial constructors might not be
> called at all.
> > > |
> > > | Maybe "might not be called" is part of the bug then. Isn't the right
> > > | model that trivial ctors are called, but "might do nothing"?
> > >
> > > Yes, agreed.
> >
> > That may be part of a proposed model, but it's not part of the existing
> model,
> > which (for compatibility) is based on C's model, where fields of a
> (necessarily
> > trivially-constructible) struct can be written to as soon as suitable
> memory for
> > that struct is obtained.
> Ah, I see the problem, thanks James and Daveed. Let me try to summarize
> what I've learned so far.
> In C++, "storage" and "lifetime" don't mean the same thing for a
> non-trivially-constructible type.
> But in C the word "lifetime" has a different meaning than C++. I have C99
> handy, but it should be the same in C11, and "lifetime" and "storage
> duration" are the same thing in C:
> 6.2.4/1: An object has a storage duration that determines its
> lifetime. There are three storage durations: static, automatic, and
> allocated. Allocated storage is described in 7.20.3.
> 6.2.4/2: The lifetime of an object is the portion of program
> execution during which storage is guaranteed to be reserved for it.
> 7.20.3: The order and contiguity of storage allocated by
> successive calls to the calloc, malloc, and realloc functions is
> unspecified. The pointer returned if the allocation succeeds is suitably
> aligned so that it may be assigned to a pointer to any type of object and
> then used to access such an object or an array of such objects in the space
> allocated (until the space is explicitly deallocated). The lifetime of an
> allocated object extends from the allocation until the deallocation. Each
> such allocation shall yield a pointer to an object disjoint from any other
> object. The pointer returned points to the start (lowest byte address) of
> the allocated space.
> But one thing that follows here is that in C, "the object" is the raw
> memory. Right? This follows from the above three quotes.
> So is that different in C++?

There's one other rule that I'd overlooked in my prior messages.
[intro.object]/1 presents this beautiful model: "An object is a region of
storage. [...] An object is created by a definition (3.1), by a
new-expression (5.3.4) or by the implementation (12.2) when needed.[...] An
object has a storage duration (3.7) which influences its lifetime (3.8). An
object has a type (3.9)."

Trouble is, this model gives a vast quantity of real-world C++ code
undefined behavior, including any C-like code that uses the 'malloc'
technique described in this thread. This breaks compatibility with C and
with real-world C++ so thoroughly that I think it's not a tenable position,
and that the rule must be revised. Prior to this thread, I had assumed that
we would easily reach consensus on that, but it seems that's not the case.

As Daveed pointed out:
> > > Am I missing something?
> >
> > I think so: 3.8/1 also says that the lifetime of an object ends if its
> storage is
> > reused
> "...or released" -- okay. I always thought reused meant deallocated and
> reallocated, but since it says "reused or released" it does seem to follow
> that reused means what Daveed said:
> > . So when you write to *ps, you've terminated the lifetime of *pb.
> OK, that's C++. The word "reused" doesn't appear anywhere in the C99
> standard at least.
> Trying to summarize:
> So was the goal of the 3.8/1 wording of "reuse" to acknowledge (and be
> compatible with) the C memory-scribbling, while still being able to say
> that even for raw storage and PODs a given piece of storage has a
> well-defined type at any given point in time (namely the one it was last
> written to as)? And does "reused" clearly say that "written-to" part if
> that's the intent?
> And so for raw memory and PODs, storage as a type T begins when you read
> or write it as a T, and ends when you read or write as some other type U,
> as long as T and U are PODs that fit in the storage (incl. size and
> alignment)?
> And dare I ask: Um, what about using part of the same allocated buffer to
> hold a T and another part to hold a U, such as malloc(1000) and read/write
> an int at offset 10 and read/write a short at offset 314 -- they're the
> same allocation, so do we even have any way to talk about that?
> Herb
> _______________________________________________
> ub mailing list
> ub_at_[hidden]
> http://www.open-std.org/mailman/listinfo/ub

Received on 2014-01-16 22:48:20