[ub] data overlays: reinterpret_cast vs placement new

Johannes Schaub schaub.johannes at googlemail.com
Sun Mar 23 14:48:36 CET 2014


David Krauss wrote:

> 
> On 2014–03–20, at 5:25 AM, Jens Maurer <Jens.Maurer at gmx.net> wrote:
> 
>> On 03/18/2014 06:06 AM, David Krauss wrote:
>>> uint32_t datum = * (net_word< uint32_t > *) buf_ptr;
>> 
>> What's "buf_ptr”?
> 
> A blob of data with no dynamic type. It’s supposed to be idiomatic,
> cast-happy C using a memory overlay struct.
> 

The Standard is not exceptionally clear what the difference between an 
object whose lifetime hasn't started yet and an object that doesn't exist at 
all is. As far as I am aware, such a difference only exists for class type 
objects (during destruction and construction in constructors and 
destructors). 

In your case there was no construction of the class type 
"net_word<uint32_t>", therefor lifetime could not start. Hence I think that 
3.8p6 applies which renders your program undefined because " the glvalue is 
used to access a non-static data member or call a non-static member function 
of the object, or" (you are calling a conversion function). 

Regarding the start of lifetime of the net_word object, i think the lifetime 
begins when you complete the invocation of the constructor of "net_word< 
uint32_t >". 3.8p1 says something else, but it has previously been shown 
that this rule is defective (because it allows infinitely many objects whose 
sizeof and alignments are compatible be at the same memory location at the 
same time). Therefor I assume that this paragraph still does not reflect the 
actual intent, for types like int and float but also for class types with 
trivial constructors. 

>>> Is it any safer to jump through a little hoop with placement new?
>>> 
>>> uint32_t datum = * new( buf_ptr ) net_word< uint32_t >;
>> 
>> This destroys the previous contents of *buf_ptr, from a
>> specification point-of-view.
> 
> It runs the constructor of a trivially-constructible class, which does
> nothing and has no particular significance. The object lifetime already
> began when “storage with the proper alignment and size for type T is
> obtained,” which occurred when the data blob was allocated.
> 

Your code renders the value of the data member array indeterminate, by 
5.3.1p17 (default initialization happens), 12.6.2p8 (the member array is 
default initialized), 5.3.4p1 (storage duration is dynamic) and 8.5p12 (the 
member array has indeterminate value). 

I'm not sure what rule to apply to infer that when memcpy'ing that array 
into a uint32_t, that this uint32_t then also contains an undeterminate 
value. The paragraphs 3.9p2 and 3.9p3 both assume that you previously had 
another uint32_t object that you grabbed the bytes from that make up the 
array.

In case nothing else covers it yet, should 3.9p2 say that when the array has 
an indeterminate value (disregarding of whether the array has been copied to 
from another object), that the target object copied to also has an 
indeterminate value?





More information about the ub mailing list