Prevent clobbering of data in Result's tail padding internally and externally #407
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
llvm/llvm-project#70494 points out that
[[no_unique_address]]
on a union member can cause its placement-new construction to clobber data in its tail padding, as ctors can and do write their entiresizeof()
size, not just their data-size.So we do some wild things to prevent this from occurring:
The
T
andE
union are grouped with the state into a struct, which we callInner
. This structure is always constructed together as a group when changing the state to Ok or Err. This ensures that we constructT
orE
and then set the state (which follows in the struct) thus avoiding clobbering of the state.Second, the Inner struct needs to be protected from clobbering other things in its tail padding. So it is wrapped in another struct that conditionally applies
[[no_unique_address]]
to it, which we callMaybeNoUniqueAddress
.We mark
Inner
as[[no_unique_address]]
only when there is no tail padding inT
orE
. Then the tail padding ofInner
which is introduced by the state flag can be used by things external to theResult
.All of this is put into the outermost structure
StorageVoid
orStorageNonVoid
for a voidT
or not, respectively. Everything is marked[[no_unique_address]]
exceptInner
which is conditionally marked as mentioned above.In order to do this, we've rewritten the entire implementation of Result's storage. In the process, copy/move operations and destructors are all trivial if the same for both
T
andE
are trivial, which fixes #403.The Clang 18 and GCC builds are failing due to the Clang-18 apt package not including libclang: llvm/llvm-project#73402