Skip to content

Commit b3d3076

Browse files
committed
Prepare libcxx and libcxxabi for pointer field protection.
Pointer field protection has the following characteristics: - Pointer fields in RTTI types are unsigned. Signing these fields is unnecessary because PFP is a mechanism for protecting the heap, and the RTTI objects typically live in global variables. Therefore, mark the fields with the no_field_protection to inhibit PFP for these fields. - libcxx's interim trivial relocatability implementation, which memcpy's some non-trivially-copyable objects according to the value of a trait, conflicts with PFP by causing such copies to result in a crash in some cases where the object being copied includes a pointer field. These copies are undefined behavior and in C++26 they must be made using std::trivially_relocate which is not yet implemented, together with using a different predicate for the trait. Therefore, make libcxx's trivially relocatable predicate simply return the value of the trivially copyable trait when PFP is enabled, which results in standards compliant behavior that is accommodated by PFP. - Pointer field protection is an ABI break, so adjust the ABI tag when it is enabled. Pull Request: llvm#151651
1 parent 1510b3d commit b3d3076

File tree

7 files changed

+83
-36
lines changed

7 files changed

+83
-36
lines changed

libcxx/include/__config

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,21 @@ typedef __char32_t char32_t;
484484
# define _LIBCPP_EXCEPTIONS_SIG e
485485
# endif
486486

487+
# if !_LIBCPP_HAS_EXCEPTIONS
488+
# define _LIBCPP_EXCEPTIONS_SIG n
489+
# else
490+
# define _LIBCPP_EXCEPTIONS_SIG e
491+
# endif
492+
493+
# if __has_feature(pointer_field_protection)
494+
# define _LIBCPP_PFP_SIG p
495+
# else
496+
# define _LIBCPP_PFP_SIG
497+
# endif
498+
487499
# define _LIBCPP_ODR_SIGNATURE \
488-
_LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_EXCEPTIONS_SIG), _LIBCPP_VERSION)
500+
_LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_EXCEPTIONS_SIG), _LIBCPP_PFP_SIG), \
501+
_LIBCPP_VERSION)
489502

490503
// This macro marks a symbol as being hidden from libc++'s ABI. This is achieved
491504
// on two levels:
@@ -1262,6 +1275,12 @@ typedef __char32_t char32_t;
12621275
# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 0
12631276
# endif
12641277

1278+
# if __has_feature(pointer_field_protection)
1279+
# define _LIBCPP_NO_PFP [[clang::no_field_protection]]
1280+
# else
1281+
# define _LIBCPP_NO_PFP
1282+
# endif
1283+
12651284
#endif // __cplusplus
12661285

12671286
#endif // _LIBCPP___CONFIG

libcxx/include/__type_traits/is_trivially_relocatable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ template <class _Tp, class = void>
3434
struct __libcpp_is_trivially_relocatable : is_trivially_copyable<_Tp> {};
3535
#endif
3636

37+
// __trivially_relocatable on libc++'s builtin types does not currently return the right answer with PFP.
38+
#if !__has_feature(pointer_field_protection)
3739
template <class _Tp>
3840
struct __libcpp_is_trivially_relocatable<_Tp,
3941
__enable_if_t<is_same<_Tp, typename _Tp::__trivially_relocatable>::value> >
4042
: true_type {};
43+
#endif
4144

4245
_LIBCPP_END_NAMESPACE_STD
4346

libcxx/include/typeinfo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH type_info
300300
protected:
301301
typedef __type_info_implementations::__impl __impl;
302302

303-
__impl::__type_name_t __type_name;
303+
_LIBCPP_NO_PFP __impl::__type_name_t __type_name;
304304

305305
_LIBCPP_HIDE_FROM_ABI explicit type_info(const char* __n) : __type_name(__impl::__string_to_type_name(__n)) {}
306306

libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,12 @@ void unique_ptr_test() {
256256
ComparePrettyPrintToRegex(std::move(forty_two),
257257
R"(std::unique_ptr<int> containing = {__ptr_ = 0x[a-f0-9]+})");
258258

259+
#if !__has_feature(pointer_field_protection)
260+
// GDB doesn't know how to read PFP fields correctly yet.
259261
std::unique_ptr<int> this_is_null;
260262
ComparePrettyPrintToChars(std::move(this_is_null),
261263
R"(std::unique_ptr is nullptr)");
264+
#endif
262265
}
263266

264267
void bitset_test() {
@@ -476,10 +479,13 @@ void vector_test() {
476479
"std::vector of length "
477480
"3, capacity 3 = {5, 6, 7}");
478481

482+
#if !__has_feature(pointer_field_protection)
483+
// GDB doesn't know how to read PFP fields correctly yet.
479484
std::vector<int, UncompressibleAllocator<int>> test3({7, 8});
480485
ComparePrettyPrintToChars(std::move(test3),
481486
"std::vector of length "
482487
"2, capacity 2 = {7, 8}");
488+
#endif
483489
}
484490

485491
void set_iterator_test() {
@@ -650,8 +656,11 @@ void shared_ptr_test() {
650656
test0,
651657
R"(std::shared_ptr<int> count [3\?], weak [0\?]( \(libc\+\+ missing debug info\))? containing = {__ptr_ = 0x[a-f0-9]+})");
652658

659+
#if !__has_feature(pointer_field_protection)
660+
// GDB doesn't know how to read PFP fields correctly yet.
653661
std::shared_ptr<const int> test3;
654662
ComparePrettyPrintToChars(test3, "std::shared_ptr is nullptr");
663+
#endif
655664
}
656665

657666
void streampos_test() {

libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
# include <locale>
2929
#endif
3030

31+
#if __has_feature(pointer_field_protection)
32+
constexpr bool pfp_disabled = false;
33+
#else
34+
constexpr bool pfp_disabled = true;
35+
#endif
36+
3137
static_assert(std::__libcpp_is_trivially_relocatable<char>::value, "");
3238
static_assert(std::__libcpp_is_trivially_relocatable<int>::value, "");
3339
static_assert(std::__libcpp_is_trivially_relocatable<double>::value, "");
@@ -70,8 +76,8 @@ static_assert(!std::__libcpp_is_trivially_relocatable<NonTrivialDestructor>::val
7076
// ----------------------
7177

7278
// __split_buffer
73-
static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<int> >::value, "");
74-
static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<NotTriviallyCopyable> >::value, "");
79+
static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<int> >::value == pfp_disabled, "");
80+
static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<NotTriviallyCopyable> >::value == pfp_disabled, "");
7581
static_assert(!std::__libcpp_is_trivially_relocatable<std::__split_buffer<int, test_allocator<int> > >::value, "");
7682

7783
// standard library types
@@ -84,7 +90,7 @@ static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<
8490

8591
static_assert(std::__libcpp_is_trivially_relocatable<std::array<int, 1> >::value, "");
8692
static_assert(!std::__libcpp_is_trivially_relocatable<std::array<NotTriviallyCopyable, 1> >::value, "");
87-
static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<int>, 1> >::value, "");
93+
static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<int>, 1> >::value == pfp_disabled, "");
8894

8995
// basic_string
9096
#if !__has_feature(address_sanitizer) || !_LIBCPP_INSTRUMENTED_WITH_ASAN
@@ -99,17 +105,17 @@ struct NotTriviallyRelocatableCharTraits : constexpr_char_traits<T> {
99105
};
100106

101107
static_assert(std::__libcpp_is_trivially_relocatable<
102-
std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::value,
108+
std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::value == pfp_disabled,
103109
"");
104110
static_assert(std::__libcpp_is_trivially_relocatable<
105-
std::basic_string<char, NotTriviallyRelocatableCharTraits<char>, std::allocator<char> > >::value,
111+
std::basic_string<char, NotTriviallyRelocatableCharTraits<char>, std::allocator<char> > >::value == pfp_disabled,
106112
"");
107113
static_assert(std::__libcpp_is_trivially_relocatable<
108-
std::basic_string<MyChar, constexpr_char_traits<MyChar>, std::allocator<MyChar> > >::value,
114+
std::basic_string<MyChar, constexpr_char_traits<MyChar>, std::allocator<MyChar> > >::value == pfp_disabled,
109115
"");
110116
static_assert(
111117
std::__libcpp_is_trivially_relocatable<
112-
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, std::allocator<MyChar> > >::value,
118+
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, std::allocator<MyChar> > >::value == pfp_disabled,
113119
"");
114120
static_assert(!std::__libcpp_is_trivially_relocatable<
115121
std::basic_string<char, std::char_traits<char>, test_allocator<char> > >::value,
@@ -121,21 +127,21 @@ static_assert(
121127
#endif
122128

123129
// deque
124-
static_assert(std::__libcpp_is_trivially_relocatable<std::deque<int> >::value, "");
125-
static_assert(std::__libcpp_is_trivially_relocatable<std::deque<NotTriviallyCopyable> >::value, "");
130+
static_assert(std::__libcpp_is_trivially_relocatable<std::deque<int> >::value == pfp_disabled, "");
131+
static_assert(std::__libcpp_is_trivially_relocatable<std::deque<NotTriviallyCopyable> >::value == pfp_disabled, "");
126132
static_assert(!std::__libcpp_is_trivially_relocatable<std::deque<int, test_allocator<int> > >::value, "");
127133

128134
// exception_ptr
129135
#ifndef _LIBCPP_ABI_MICROSOFT // FIXME: Is this also the case on windows?
130-
static_assert(std::__libcpp_is_trivially_relocatable<std::exception_ptr>::value, "");
136+
static_assert(std::__libcpp_is_trivially_relocatable<std::exception_ptr>::value == pfp_disabled, "");
131137
#endif
132138

133139
// expected
134140
#if TEST_STD_VER >= 23
135-
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, int> >::value);
136-
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, int>>::value);
137-
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, std::unique_ptr<int>>>::value);
138-
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, std::unique_ptr<int>>>::value);
141+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, int> >::value == pfp_disabled);
142+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, int>>::value == pfp_disabled);
143+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, std::unique_ptr<int>>>::value == pfp_disabled);
144+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, std::unique_ptr<int>>>::value == pfp_disabled);
139145

140146
static_assert(!std::__libcpp_is_trivially_relocatable<std::expected<int, NotTriviallyCopyable>>::value);
141147
static_assert(!std::__libcpp_is_trivially_relocatable<std::expected<NotTriviallyCopyable, int>>::value);
@@ -145,42 +151,42 @@ static_assert(
145151

146152
// locale
147153
#ifndef TEST_HAS_NO_LOCALIZATION
148-
static_assert(std::__libcpp_is_trivially_relocatable<std::locale>::value, "");
154+
static_assert(std::__libcpp_is_trivially_relocatable<std::locale>::value == pfp_disabled, "");
149155
#endif
150156

151157
// optional
152158
#if TEST_STD_VER >= 17
153159
static_assert(std::__libcpp_is_trivially_relocatable<std::optional<int>>::value, "");
154160
static_assert(!std::__libcpp_is_trivially_relocatable<std::optional<NotTriviallyCopyable>>::value, "");
155-
static_assert(std::__libcpp_is_trivially_relocatable<std::optional<std::unique_ptr<int>>>::value, "");
161+
static_assert(std::__libcpp_is_trivially_relocatable<std::optional<std::unique_ptr<int>>>::value == pfp_disabled, "");
156162
#endif // TEST_STD_VER >= 17
157163

158164
// pair
159-
static_assert(std::__libcpp_is_trivially_relocatable<std::pair<int, int> >::value, "");
165+
static_assert(std::__libcpp_is_trivially_relocatable<std::pair<int, int> >::value == pfp_disabled, "");
160166
static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<NotTriviallyCopyable, int> >::value, "");
161167
static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<int, NotTriviallyCopyable> >::value, "");
162168
static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
163169
"");
164-
static_assert(std::__libcpp_is_trivially_relocatable<std::pair<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
170+
static_assert(std::__libcpp_is_trivially_relocatable<std::pair<std::unique_ptr<int>, std::unique_ptr<int> > >::value == pfp_disabled,
165171
"");
166172

167173
// shared_ptr
168-
static_assert(std::__libcpp_is_trivially_relocatable<std::shared_ptr<NotTriviallyCopyable> >::value, "");
174+
static_assert(std::__libcpp_is_trivially_relocatable<std::shared_ptr<NotTriviallyCopyable> >::value == pfp_disabled, "");
169175

170176
// tuple
171177
#if TEST_STD_VER >= 11
172178
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<> >::value, "");
173179

174-
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int> >::value, "");
180+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int> >::value == pfp_disabled, "");
175181
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable> >::value, "");
176-
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int> > >::value, "");
182+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int> > >::value == pfp_disabled, "");
177183

178-
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int, int> >::value, "");
184+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int, int> >::value == pfp_disabled, "");
179185
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable, int> >::value, "");
180186
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<int, NotTriviallyCopyable> >::value, "");
181187
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
182188
"");
183-
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
189+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int>, std::unique_ptr<int> > >::value == pfp_disabled,
184190
"");
185191
#endif // TEST_STD_VER >= 11
186192

@@ -205,9 +211,9 @@ struct NotTriviallyRelocatablePointer {
205211
void operator()(T*);
206212
};
207213

208-
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<int> >::value, "");
209-
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<NotTriviallyCopyable> >::value, "");
210-
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[]> >::value, "");
214+
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<int> >::value == pfp_disabled, "");
215+
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<NotTriviallyCopyable> >::value == pfp_disabled, "");
216+
static_assert(std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[]> >::value == pfp_disabled, "");
211217
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int, NotTriviallyRelocatableDeleter> >::value,
212218
"");
213219
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[], NotTriviallyRelocatableDeleter> >::value,
@@ -221,23 +227,23 @@ static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[], Not
221227
#if TEST_STD_VER >= 17
222228
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<int> >::value, "");
223229
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable> >::value, "");
224-
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int> > >::value, "");
230+
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int> > >::value == pfp_disabled, "");
225231

226232
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<int, int> >::value, "");
227233
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable, int> >::value, "");
228234
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<int, NotTriviallyCopyable> >::value, "");
229235
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
230236
"");
231-
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
237+
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int>, std::unique_ptr<int> > >::value == pfp_disabled,
232238
"");
233239
#endif // TEST_STD_VER >= 17
234240

235241
// vector
236-
static_assert(std::__libcpp_is_trivially_relocatable<std::vector<int> >::value, "");
237-
static_assert(std::__libcpp_is_trivially_relocatable<std::vector<NotTriviallyCopyable> >::value, "");
242+
static_assert(std::__libcpp_is_trivially_relocatable<std::vector<int> >::value == pfp_disabled, "");
243+
static_assert(std::__libcpp_is_trivially_relocatable<std::vector<NotTriviallyCopyable> >::value == pfp_disabled, "");
238244
static_assert(!std::__libcpp_is_trivially_relocatable<std::vector<int, test_allocator<int> > >::value, "");
239245

240246
// weak_ptr
241-
static_assert(std::__libcpp_is_trivially_relocatable<std::weak_ptr<NotTriviallyCopyable> >::value, "");
247+
static_assert(std::__libcpp_is_trivially_relocatable<std::weak_ptr<NotTriviallyCopyable> >::value == pfp_disabled, "");
242248

243249
// TODO: Mark all the trivially relocatable STL types as such

libcxxabi/include/__cxxabi_config.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,14 @@
109109
# define _LIBCXXABI_NOEXCEPT noexcept
110110
#endif
111111

112+
#if defined(_LIBCXXABI_COMPILER_CLANG)
113+
# if __has_feature(pointer_field_protection)
114+
# define _LIBCXXABI_NO_PFP [[clang::no_field_protection]]
115+
# else
116+
# define _LIBCXXABI_NO_PFP
117+
# endif
118+
#else
119+
# define _LIBCXXABI_NO_PFP
120+
#endif
121+
112122
#endif // ____CXXABI_CONFIG_H

libcxxabi/src/private_typeinfo.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
145145
// Has one non-virtual public base class at offset zero
146146
class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info {
147147
public:
148-
const __class_type_info *__base_type;
148+
_LIBCXXABI_NO_PFP const __class_type_info *__base_type;
149149

150150
_LIBCXXABI_HIDDEN virtual ~__si_class_type_info();
151151

@@ -204,7 +204,7 @@ class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info {
204204
class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {
205205
public:
206206
unsigned int __flags;
207-
const __shim_type_info *__pointee;
207+
_LIBCXXABI_NO_PFP const __shim_type_info *__pointee;
208208

209209
enum __masks {
210210
__const_mask = 0x1,
@@ -245,7 +245,7 @@ class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info {
245245
class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info
246246
: public __pbase_type_info {
247247
public:
248-
const __class_type_info *__context;
248+
_LIBCXXABI_NO_PFP const __class_type_info *__context;
249249

250250
_LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info();
251251
_LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,

0 commit comments

Comments
 (0)