Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

implicit object creation by unsigned char[] - Is it legal to reinterpret_cast to implicit object? (P0593)

In the paper P0593R6, implicit object creation was introduced, which is now in the C++20 standard (and If I'm not mistaken, it's also supposed to apply retroactively to older standards).

As the paper says here, this is meant to allow code such as:

unique_ptr<char[]> Stream::read() {
  // ... determine data size ...
  unique_ptr<char[]> buffer(new char[N]);
  // ... copy data into buffer ...
  return buffer;
}

void process(Stream *stream) {
  unique_ptr<char[]> buffer = stream->read();
  if (buffer[0] == FOO)
    process_foo(reinterpret_cast<Foo*>(buffer.get())); // #1
  else
    process_bar(reinterpret_cast<Bar*>(buffer.get())); // #2
}

This is taken from Practical Examples section of the paper, and is also given as a motivating example here

The point of the proposal (which is now included in the standard) is the following: Normally, this would be UB, because objects of type Foo or Bar have never been created. The new implicit object creation defines that these objects are now implicitly created, if that would make the behavior defined.

My question about this code snipped is, how is the reinterpret_cast here sufficient to get a pointer the implicitly created object? Why is the behavior of this code not still potentially UB?

reinterpret_cast here does not create a pointer to an object of such type, because these objects, even if they were created, are not pointer-interconvertible with the first element of buffer. That means that the resulting pointer's value is still that of a pointer to the first element of the array, not to a Foo, even though its pointer type is now changed.

I suppose that using std::launder here might make it legal, although I am not sure, but it's not used in the proposal. Is this an oversight in the paper or am I mistaken?

For reference: I am basing this on the effects of reinterpret_cast described in these two sections:

https://eel.is/c++draft/expr.reinterpret.cast#7

https://eel.is/c++draft/expr.static.cast#14

Update:

I think another way to phrase this problem is: How can we be sure that reinterpret_cast(&a[0]) can give us a pointer to b, given that a "provides storage for" b?

I have found this (japanese-language) comment on a github issue of the japanese-language cppreference project whose author seems to have stumbled on the same issue, and noticed how it's related to P1839 which addressed the reverse-direction (getting byte representation from an object) by changing pointer-interconvertibility.

like image 414
JMC Avatar asked Jan 21 '26 14:01

JMC


1 Answers

Creating an object (implicitly or not) within an array ends the lifetime of any overlapping array elements (even if the array itself provides storage for the object), per [basic.life]/1.5. The if condition reads the value of buffer[0], which requires it to be within lifetime ([basic.life]/7.1). Based on this, we can already conclude that no form of IOC in Stream::read() could have created an object at buffer.get(), because doing so would not "result in the program having defined behavior" ([intro.object]/10).

But even ignoring that (let's assume the read is intended to be valid even with a Foo/Bar object at that location, per the currently non-existent 'reading object representation' rule), you are correct that reinterpret_cast alone is not sufficient to obtain a pointer to the implicitly created object: new char[N] produces a pointer to the first element of the allocated array ([expr.new]/10), which is not pointer-interconvertible with the desired object ([basic.compound]/4). std::launder would be needed for this purpose ([ptr.launder]).

So yes, this seems like a mistake in the paper.

In fact, the same code snippet appears as a motivating example in the follow-up paper P2590 (section 1.2), and this time the attached explanation does mention std::launder (and also creates the object after checking the initial byte).

like image 117
duck Avatar answered Jan 24 '26 16:01

duck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!