std::launder and reachable bytes

251 views
Skip to first unread message

Language Lawyer

unread,
Jul 28, 2018, 11:49:42 AM7/28/18
to std-dis...@isocpp.org
I'm trying to understand the consequences of the std::launder Requierments, namely "All bytes of storage that would be reachable through the result are reachable through p".
Remarks explain when a byte of storage is reachable through a pointer:
"A byte of storage is reachable through a pointer value that points to an object Y if it is within the storage occupied by Y, an object that is pointer-interconvertible with Y, or the immediately-enclosing array object if Y is an array element."

It is well-known that an array object and its first element are not pointer-interconvertible, so that reinterpret_cast from one type to another doesn't change pointer's value. But it seems that it is possible to use std::launder to get the pointer with desired value in some cases.

For example
int a[2];
int* p = a; // pointer to the first element
reinterpret_cast<int(*)[2]>(p); // does not change the value
std::launder(reinterpret_cast<int(*)[2]>(p)); // gives a pointer pointing to the array `a`

It is possible to use std::launder here because all bytes that are reachable through the result (within the storage) are reachable through the argument (bytes belong to the immediately-enclosing array object).

But in the following code
int aa[2][2];
auto& a = aa[0];
int* p = a;
std::launder(reinterpret_cast<int(*)[2]>(p)); // looks like UB

std::launder is not applicable. All bytes of the 2d-array's `aa` storage are reachable through the pointer to its initial element, the `int[2]` subarray, but are not reachable through the pointer `p` pointing to the initial element of the initial `int[2]` subarray.

It feels a little bit strange how we lost the ability to get from the pointer to the initial array element to the pointer to its immediately-enclosing array object when this array object became a subobject of another object. The same thing will happen if we make the array object the first member of a structure, but not happen if we make it the second (third etc.) member.

Is it intentional? Why?

Language Lawyer

unread,
Aug 15, 2018, 11:21:25 AM8/15/18
to std-dis...@isocpp.org
Well, the intent is clear (for me): to support implementations with pointer bounds checking.
If the bounds were shrunk as a result of some cast operation, it is not possible to widen them back later.

The rules about reachability were added in P0137R1, but the motivation of such a change does not appear to be listed in the "Changes since R0" section of the paper.
Reply all
Reply to author
Forward
0 new messages