This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
std::start_lifetime_as inadvertently has undefined behavior due to use of std::bit_castSection: 20.2.6 [obj.lifetime] Status: New Submitter: Jan Schultke Opened: 2024-10-23 Last modified: 2025-10-22
Priority: 3
View other active issues in [obj.lifetime].
View all other issues in [obj.lifetime].
View all issues with New status.
Discussion:
Consider the motivating example from P2590R2: Explicit lifetime management:
struct X { int a, b; };
X* make_x() {
X* p = std::start_lifetime_as<X>(myMalloc(sizeof(struct X));
p->a = 1;
p->b = 2;
return p;
}
Assuming that myMalloc does not initialize the bytes of storage, this example has undefined behavior because
the value of the resulting object of trivially copyable type X is determined as if by calling
std::bit_cast<X>(a) for the implicitly-created object a of type X
(20.2.6 [obj.lifetime] paragraph 3), whose object representation is filled with indeterminate bytes
obtained from myMalloc. Such a call to std::bit_cast has undefined behavior because std::bit_cast
does not tolerate the creation of an int where bits in the value representation are indeterminate
(22.11.3 [bit.cast] paragraph 2), and such an int is the smallest enclosing object of some of the
indeterminate bits.
[2025-10-22; Reflector poll.]
Set priority to 3 after reflector poll.
"NAD, it says the storage is not accessed, so no UB from reading indeterminate bits."
"The UB comes from bit_cast's Preconditions, not from reading an indeterminate value."
Core should review any change here.
Proposed resolution:
This wording is relative to N4993.
Modify 20.2.6 [obj.lifetime] as indicated:
[Drafting note: The proposed resolution does not alter the behavior for erroneous bits. Therefore, a call to
std::start_lifetime_asmay have erroneous behavior when used on storage with indeterminate bits, despite not accessing that storage. An alternative resolution would be to produce objects whose value is erroneous.]
template<class T> T* start_lifetime_as(void* p) noexcept; template<class T> const T* start_lifetime_as(const void* p) noexcept; template<class T> volatile T* start_lifetime_as(volatile void* p) noexcept; template<class T> const volatile T* start_lifetime_as(const volatile void* p) noexcept;-1- Mandates: […]
-2- Preconditions: […] -3- Effects: Implicitly creates objects (6.8.2 [intro.object]) within the denoted region consisting of an objectaof typeTwhose address isp, and objects nested withina, as follows: The object representation ofais the contents of the storage prior to the call tostart_lifetime_as. The value of each created objectoof trivially copyable type (6.9.1 [basic.types.general])Uis determined in the same manner as for a call tobit_cast<U>(E)(22.11.3 [bit.cast]), whereEis an lvalue of typeUdenotingo, except that the storage is not accessed . The value of any other created object is unspecified.