Date: Wed, 17 Dec 2025 09:46:34 +0000
> Can you restate this in terms of the C++ standard, e.g. potentially overlapping subjects?
It’s unnecessarily complicated for something that is fundamentally simple.
> This doesn't seem relevant to the original mail.
It is as relevant as it could possibly get in this situation.
You can’t sit on your “chair” and eat at your “table”, when they are both the same thing.
You can either use it as a chair or as a table, but not both at the same time. And if you try it anyway bad things will happen.
This should be simple enough to understand.
You can re-use addresses to do different things, you have language constructs that helps you do that.
But it doesn’t mean that every possible of combination of what you could do with these things results in a well-formed application.
This is a clear example of that for this same reason.
And this is not helped by the fact that available documentation such as this: https://en.cppreference.com/w/cpp/utility/launder.html
Shows an “example usage” of the feature, that is not just UB, it should just be straight out ill formed because the lifetime of the laundered object is never over when it is repurposed and laundered, but the compiler doesn’t care.
The compiler will let you do it (use the same thing both as the table and a distinct chair) but it doesn’t mean it is correct.
From: Jonathan Wakely <cxx_at_[hidden]>
Sent: Wednesday, December 17, 2025 10:11
To: C++ Proposals <std-proposals_at_[hidden]>
Cc: Tiago Freire <tmiguelf_at_hotmail.com>
Subject: Re: [std-proposals] std::launder when multiple objects of the same type exist at the same address
On Wed, 17 Dec 2025, 08:35 Tiago Freire via Std-Proposals, <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>> wrote:
It is physically impossible for 2 distinct object to share the same address at the same time unless they have 0 size (i.e. unless there is no object, at which point address is irrelevant).
Can you restate this in terms of the C++ standard, e.g. potentially overlapping subjects?
You can have 2 distinct pointers to the same address, pointing to the same object, but where the pointers can misrepresent the type of the object.
An object is an abstract representation of a "thing", while the "pointer type" is just a hint of what that "thing is".
I can have a "chair" and place a label on it calling a "table", I can even put a vase on top of this thing that I've labeled "table", I can invite guests to have dinner using this "table", but it is still a chair, and you certainly don't have both a distinct "table" and a "chair".
This doesn't seem relevant to the original mail.
-----Original Message-----
From: Std-Proposals <std-proposals-bounces_at_[hidden]<mailto:std-proposals-bounces_at_[hidden]>> On Behalf Of Halalaluyafail3 via Std-Proposals
Sent: Wednesday, December 17, 2025 02:40
To: Halalaluyafail3 via Std-Proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>>
Cc: Halalaluyafail3 <luigighiron_at_gmail.com<mailto:luigighiron_at_[hidden]>>
Subject: [std-proposals] std::launder when multiple objects of the same type exist at the same address
N5032 Section 17.6.5 [ptr.launder] Paragraphs 2 and 3:
> Preconditions: p represents the address A of a byte in memory. An
> object X that is within its lifetime (6.8.4) and whose type is similar
> (7.3.6) to T is located at the address A. All bytes of storage that
> would be reachable through
> (6.9.4) the result are reachable through p.
>
> Returns: A value of type T* that points to X.
This section seems to assume that at most one possible X can exist. However, it appears possible to construct two objects in a way that they could both be that
X:
struct S{
unsigned char x[4];
};
static_assert(sizeof(S)==4);
S s;
S*p=::new((void*)s.x)S;
std::launder((S*)s.x)->~S();
s.~S();
All pointers involved here can reach all 4 bytes of s, so reachability doesn't affect anything. s is an object of type S which exists at some address A. An array s.x spanning all of the bytes of s exists as a subobject of s. s.x must have the same address as s because it occupies the same storage, and because of pointer-interconvertibility. Then, another object of type S is created in s.x where s.x provides storage for it. This new object *p occupies the same storage as s.x, so it must have the same address as s.x and s. So there are two objects s and *p which both have the same address, same type, same reachable bytes, and are both within their lifetime.
Given this, it is unclear what std::launder((S*)s.x) points to. (S*)s.x points to the same address as both s and *p, and both objects meet the requirements to be X. Here is an example that demonstrates each case individually:
//same S as before
alignas(S)unsigned char a[4];
::new((void*)a)S;
std::launder((S*)a)->~S();
S b;
std::launder((S*)b.x)->~S();
std::launder((S*)s.x) could be either case, so is s.~S() defined (launder results in p) or undefined (launder results in &s)?
See also GCC bug 121180, this issue can arise from types such as std::any which store objects internally if they are small enough. Specifically, an empty class can be stored in a std::any object and the std::any object can overlap with another object that has the same empty class type just right to cause both empty classes to have the same address.
I'm thinking about making a LWG issue for this. Though I don't think any implementations implement these incorrectly because this overlapping requires the storage to be unused and cannot happen in constant expressions.
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]<mailto:Std-Proposals_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]<mailto:Std-Proposals_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
It’s unnecessarily complicated for something that is fundamentally simple.
> This doesn't seem relevant to the original mail.
It is as relevant as it could possibly get in this situation.
You can’t sit on your “chair” and eat at your “table”, when they are both the same thing.
You can either use it as a chair or as a table, but not both at the same time. And if you try it anyway bad things will happen.
This should be simple enough to understand.
You can re-use addresses to do different things, you have language constructs that helps you do that.
But it doesn’t mean that every possible of combination of what you could do with these things results in a well-formed application.
This is a clear example of that for this same reason.
And this is not helped by the fact that available documentation such as this: https://en.cppreference.com/w/cpp/utility/launder.html
Shows an “example usage” of the feature, that is not just UB, it should just be straight out ill formed because the lifetime of the laundered object is never over when it is repurposed and laundered, but the compiler doesn’t care.
The compiler will let you do it (use the same thing both as the table and a distinct chair) but it doesn’t mean it is correct.
From: Jonathan Wakely <cxx_at_[hidden]>
Sent: Wednesday, December 17, 2025 10:11
To: C++ Proposals <std-proposals_at_[hidden]>
Cc: Tiago Freire <tmiguelf_at_hotmail.com>
Subject: Re: [std-proposals] std::launder when multiple objects of the same type exist at the same address
On Wed, 17 Dec 2025, 08:35 Tiago Freire via Std-Proposals, <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>> wrote:
It is physically impossible for 2 distinct object to share the same address at the same time unless they have 0 size (i.e. unless there is no object, at which point address is irrelevant).
Can you restate this in terms of the C++ standard, e.g. potentially overlapping subjects?
You can have 2 distinct pointers to the same address, pointing to the same object, but where the pointers can misrepresent the type of the object.
An object is an abstract representation of a "thing", while the "pointer type" is just a hint of what that "thing is".
I can have a "chair" and place a label on it calling a "table", I can even put a vase on top of this thing that I've labeled "table", I can invite guests to have dinner using this "table", but it is still a chair, and you certainly don't have both a distinct "table" and a "chair".
This doesn't seem relevant to the original mail.
-----Original Message-----
From: Std-Proposals <std-proposals-bounces_at_[hidden]<mailto:std-proposals-bounces_at_[hidden]>> On Behalf Of Halalaluyafail3 via Std-Proposals
Sent: Wednesday, December 17, 2025 02:40
To: Halalaluyafail3 via Std-Proposals <std-proposals_at_[hidden]<mailto:std-proposals_at_[hidden]>>
Cc: Halalaluyafail3 <luigighiron_at_gmail.com<mailto:luigighiron_at_[hidden]>>
Subject: [std-proposals] std::launder when multiple objects of the same type exist at the same address
N5032 Section 17.6.5 [ptr.launder] Paragraphs 2 and 3:
> Preconditions: p represents the address A of a byte in memory. An
> object X that is within its lifetime (6.8.4) and whose type is similar
> (7.3.6) to T is located at the address A. All bytes of storage that
> would be reachable through
> (6.9.4) the result are reachable through p.
>
> Returns: A value of type T* that points to X.
This section seems to assume that at most one possible X can exist. However, it appears possible to construct two objects in a way that they could both be that
X:
struct S{
unsigned char x[4];
};
static_assert(sizeof(S)==4);
S s;
S*p=::new((void*)s.x)S;
std::launder((S*)s.x)->~S();
s.~S();
All pointers involved here can reach all 4 bytes of s, so reachability doesn't affect anything. s is an object of type S which exists at some address A. An array s.x spanning all of the bytes of s exists as a subobject of s. s.x must have the same address as s because it occupies the same storage, and because of pointer-interconvertibility. Then, another object of type S is created in s.x where s.x provides storage for it. This new object *p occupies the same storage as s.x, so it must have the same address as s.x and s. So there are two objects s and *p which both have the same address, same type, same reachable bytes, and are both within their lifetime.
Given this, it is unclear what std::launder((S*)s.x) points to. (S*)s.x points to the same address as both s and *p, and both objects meet the requirements to be X. Here is an example that demonstrates each case individually:
//same S as before
alignas(S)unsigned char a[4];
::new((void*)a)S;
std::launder((S*)a)->~S();
S b;
std::launder((S*)b.x)->~S();
std::launder((S*)s.x) could be either case, so is s.~S() defined (launder results in p) or undefined (launder results in &s)?
See also GCC bug 121180, this issue can arise from types such as std::any which store objects internally if they are small enough. Specifically, an empty class can be stored in a std::any object and the std::any object can overlap with another object that has the same empty class type just right to cause both empty classes to have the same address.
I'm thinking about making a LWG issue for this. Though I don't think any implementations implement these incorrectly because this overlapping requires the storage to be unused and cannot happen in constant expressions.
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]<mailto:Std-Proposals_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]<mailto:Std-Proposals_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2025-12-17 09:46:38
