Skip to content

Commit 01df775

Browse files
authored
[libc++] Take the ABI break for std::list's pointer UB unconditionally (#100585)
This ABI break only affects fancy pointer which have a different value representation when pointing to a base of T instead of T itself. This seems like a rather small set of fancy pointers, which themselves already represent a very small niche. This patch swaps a pointer to T with a pointer to base of T in a few library-internal types.
1 parent 50985d2 commit 01df775

File tree

5 files changed

+112
-98
lines changed

5 files changed

+112
-98
lines changed

libcxx/docs/ReleaseNotes/20.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ LLVM 21
102102
ABI Affecting Changes
103103
---------------------
104104

105+
- The ABI breaks for removing undefined behaviour in ``std::forward_list``, ``std::list``, ``std::map``, ``std::set``,
106+
``std::multimap``, ``std::multiset``, ``std::unordered_map``, ``std::unordered_set``, ``std::unordered_multimap`` and
107+
``std::unordered_multiset`` are now applied unconditionally. This only affects fancy pointers which have a different
108+
value representation when pointing at the base of an internal node type instead of the type itself. A size or
109+
alignment difference is diagnosed, but more subtle ABI breaks may result in unexpected behaviour.
110+
105111
- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. The ABI impact is:
106112

107113
- When using the Itanium ABI (most non-MSVC platforms), empty types are now placed at the beginning of the enclosing

libcxx/include/__hash_table

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,18 @@ struct __hash_node_base {
7777
typedef __hash_node_base __first_node;
7878
typedef __rebind_pointer_t<_NodePtr, __first_node> __node_base_pointer;
7979
typedef _NodePtr __node_pointer;
80-
81-
#if defined(_LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB)
8280
typedef __node_base_pointer __next_pointer;
83-
#else
84-
typedef __conditional_t<is_pointer<__node_pointer>::value, __node_base_pointer, __node_pointer> __next_pointer;
81+
82+
// TODO(LLVM 22): Remove this check
83+
#ifndef _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB
84+
static_assert(sizeof(__node_base_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) ==
85+
_LIBCPP_ALIGNOF(__node_pointer),
86+
"It looks like you are using std::__hash_table (an implementation detail for the unordered containers) "
87+
"with a fancy pointer type that thas a different representation depending on whether it points to a "
88+
"__hash_table base pointer or a __hash_table node pointer (both of which are implementation details of "
89+
"the standard library). This means that your ABI is being broken between LLVM 19 and LLVM 20. If you "
90+
"don't care about your ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to "
91+
"silence this diagnostic.");
8592
#endif
8693

8794
__next_pointer __next_;

libcxx/include/__tree

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,18 @@ struct __tree_node_base_types {
566566

567567
typedef __tree_end_node<__node_base_pointer> __end_node_type;
568568
typedef __rebind_pointer_t<_VoidPtr, __end_node_type> __end_node_pointer;
569-
#if defined(_LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB)
570569
typedef __end_node_pointer __parent_pointer;
571-
#else
572-
typedef __conditional_t< is_pointer<__end_node_pointer>::value, __end_node_pointer, __node_base_pointer>
573-
__parent_pointer;
570+
571+
// TODO(LLVM 22): Remove this check
572+
#ifndef _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB
573+
static_assert(sizeof(__node_base_pointer) == sizeof(__end_node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) ==
574+
_LIBCPP_ALIGNOF(__end_node_pointer),
575+
"It looks like you are using std::__tree (an implementation detail for (multi)map/set) with a fancy "
576+
"pointer type that thas a different representation depending on whether it points to a __tree base "
577+
"pointer or a __tree node pointer (both of which are implementation details of the standard library). "
578+
"This means that your ABI is being broken between LLVM 19 and LLVM 20. If you don't care about your "
579+
"ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to silence this "
580+
"diagnostic.");
574581
#endif
575582

576583
private:
@@ -605,12 +612,7 @@ public:
605612
typedef _Tp __node_value_type;
606613
typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer;
607614
typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
608-
#if defined(_LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB)
609615
typedef typename __base::__end_node_pointer __iter_pointer;
610-
#else
611-
typedef __conditional_t< is_pointer<__node_pointer>::value, typename __base::__end_node_pointer, __node_pointer>
612-
__iter_pointer;
613-
#endif
614616

615617
private:
616618
static_assert(!is_const<__node_type>::value, "_NodePtr should never be a pointer to const");

libcxx/include/forward_list

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -278,18 +278,20 @@ struct __forward_node_traits {
278278
typedef __rebind_pointer_t<_NodePtr, __begin_node> __begin_node_pointer;
279279
typedef __rebind_pointer_t<_NodePtr, void> __void_pointer;
280280

281-
#if defined(_LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB)
282-
typedef __begin_node_pointer __iter_node_pointer;
283-
#else
284-
typedef __conditional_t<is_pointer<__void_pointer>::value, __begin_node_pointer, __node_pointer> __iter_node_pointer;
281+
// TODO(LLVM 22): Remove this check
282+
#ifndef _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB
283+
static_assert(sizeof(__begin_node_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__begin_node_pointer) ==
284+
_LIBCPP_ALIGNOF(__node_pointer),
285+
"It looks like you are using std::forward_list with a fancy pointer type that thas a different "
286+
"representation depending on whether it points to a forward_list base pointer or a forward_list node "
287+
"pointer (both of which are implementation details of the standard library). This means that your ABI "
288+
"is being broken between LLVM 19 and LLVM 20. If you don't care about your ABI being broken, define "
289+
"the _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB macro to silence this diagnostic.");
285290
#endif
286291

287-
typedef __conditional_t<is_same<__iter_node_pointer, __node_pointer>::value, __begin_node_pointer, __node_pointer>
288-
__non_iter_node_pointer;
289-
290-
_LIBCPP_HIDE_FROM_ABI static __iter_node_pointer __as_iter_node(__iter_node_pointer __p) { return __p; }
291-
_LIBCPP_HIDE_FROM_ABI static __iter_node_pointer __as_iter_node(__non_iter_node_pointer __p) {
292-
return static_cast<__iter_node_pointer>(static_cast<__void_pointer>(__p));
292+
_LIBCPP_HIDE_FROM_ABI static __begin_node_pointer __as_iter_node(__begin_node_pointer __p) { return __p; }
293+
_LIBCPP_HIDE_FROM_ABI static __begin_node_pointer __as_iter_node(__node_pointer __p) {
294+
return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__p));
293295
}
294296
};
295297

@@ -351,10 +353,9 @@ class _LIBCPP_TEMPLATE_VIS __forward_list_iterator {
351353
typedef __forward_node_traits<_NodePtr> __traits;
352354
typedef typename __traits::__node_pointer __node_pointer;
353355
typedef typename __traits::__begin_node_pointer __begin_node_pointer;
354-
typedef typename __traits::__iter_node_pointer __iter_node_pointer;
355356
typedef typename __traits::__void_pointer __void_pointer;
356357

357-
__iter_node_pointer __ptr_;
358+
__begin_node_pointer __ptr_;
358359

359360
_LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const {
360361
return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__ptr_));
@@ -417,10 +418,9 @@ class _LIBCPP_TEMPLATE_VIS __forward_list_const_iterator {
417418
typedef typename __traits::__node_type __node_type;
418419
typedef typename __traits::__node_pointer __node_pointer;
419420
typedef typename __traits::__begin_node_pointer __begin_node_pointer;
420-
typedef typename __traits::__iter_node_pointer __iter_node_pointer;
421421
typedef typename __traits::__void_pointer __void_pointer;
422422

423-
__iter_node_pointer __ptr_;
423+
__begin_node_pointer __ptr_;
424424

425425
_LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const {
426426
return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__ptr_));

0 commit comments

Comments
 (0)