aboutsummaryrefslogtreecommitdiff
path: root/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
diff options
context:
space:
mode:
authorJan Kokemüller <jan.kokemueller@gmail.com>2024-01-22 15:05:39 +0100
committerGitHub <noreply@github.com>2024-01-22 09:05:39 -0500
commit4f4690530e8b40cdf3a17c76a352b26c2fb0446c (patch)
treec157c476049d6032b0a734ab92e73dbc6d6734e1 /libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
parentbf7b8dae0615884816fff54cac08bc691746b1ee (diff)
downloadllvm-4f4690530e8b40cdf3a17c76a352b26c2fb0446c.zip
llvm-4f4690530e8b40cdf3a17c76a352b26c2fb0446c.tar.gz
llvm-4f4690530e8b40cdf3a17c76a352b26c2fb0446c.tar.bz2
[libc++] Ensure that std::expected has no tail padding (#69673)
Currently std::expected can have some padding bytes in its tail due to [[no_unique_address]]. Those padding bytes can be used by other objects. For example, in the current implementation: sizeof(std::expected<std::optional<int>, bool>) == sizeof(std::expected<std::expected<std::optional<int>, bool>, bool>) As a result, the data layout of an std::expected<std::expected<std::optional<int>, bool>, bool> can look like this: +-- optional "has value" flag | +--padding /---int---\ | | 00 00 00 00 01 00 00 00 | | | +- "outer" expected "has value" flag | +- expected "has value" flag This is problematic because `emplace()`ing the "inner" expected can not only overwrite the "inner" expected "has value" flag (issue #68552) but also the tail padding where other objects might live. This patch fixes the problem by ensuring that std::expected has no tail padding, which is achieved by conditional usage of [[no_unique_address]] based on the tail padding that this would create. This is an ABI breaking change because the following property changes: sizeof(std::expected<std::optional<int>, bool>) < sizeof(std::expected<std::expected<std::optional<int>, bool>, bool>) Before the change, this relation didn't hold. After the change, the relation does hold, which means that the size of std::expected in these cases increases after this patch. The data layout will change in the following cases where tail padding can be reused by other objects: class foo : std::expected<std::optional<int>, bool> { bool b; }; or using [[no_unique_address]]: struct foo { [[no_unique_address]] std::expected<std::optional<int>, bool> e; bool b; }; The vendor communication is handled in #70820. Fixes: #70494 Co-authored-by: philnik777 <nikolasklauser@berlin.de> Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
Diffstat (limited to 'libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp')
-rw-r--r--libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp22
1 files changed, 22 insertions, 0 deletions
diff --git a/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
index 3478230..f19599d 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
@@ -227,6 +227,28 @@ constexpr bool test() {
}
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true> x(std::unexpect);
+ CheckForInvalidWrites<true> y;
+
+ x.swap(y);
+
+ assert(x.check());
+ assert(y.check());
+ }
+ {
+ CheckForInvalidWrites<false> x(std::unexpect);
+ CheckForInvalidWrites<false> y;
+
+ x.swap(y);
+
+ assert(x.check());
+ assert(y.check());
+ }
+ }
+
return true;
}