Skip to content

Commit 798f6b8

Browse files
authored
Merge pull request #25617 from alexrp/libcxx-libunwind-backports
`libcxx`, `libunwind`: backport llvm/llvm-project#162867, llvm/llvm-project#160182, llvm/llvm-project#158347
2 parents 2ab0ca1 + 751375f commit 798f6b8

File tree

4 files changed

+97
-11
lines changed

4 files changed

+97
-11
lines changed

lib/libcxx/include/__configuration/abi.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,20 @@
3030
#elif _LIBCPP_ABI_FORCE_MICROSOFT
3131
# define _LIBCPP_ABI_MICROSOFT
3232
#else
33+
// Windows uses the Microsoft ABI
3334
# if defined(_WIN32) && defined(_MSC_VER)
3435
# define _LIBCPP_ABI_MICROSOFT
36+
37+
// 32-bit ARM uses the Itanium ABI with a few differences (array cookies, etc),
38+
// and so does 64-bit ARM on Apple platforms.
39+
# elif defined(__arm__) || (defined(__APPLE__) && defined(__aarch64__))
40+
# define _LIBCPP_ABI_ITANIUM_WITH_ARM_DIFFERENCES
41+
42+
// Non-Apple 64-bit ARM uses the vanilla Itanium ABI
43+
# elif defined(__aarch64__)
44+
# define _LIBCPP_ABI_ITANIUM
45+
46+
// We assume that other architectures also use the vanilla Itanium ABI too
3547
# else
3648
# define _LIBCPP_ABI_ITANIUM
3749
# endif

lib/libcxx/include/__memory/array_cookie.h

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <__config>
1414
#include <__configuration/abi.h>
1515
#include <__cstddef/size_t.h>
16+
#include <__memory/addressof.h>
1617
#include <__type_traits/integral_constant.h>
1718
#include <__type_traits/is_trivially_destructible.h>
1819
#include <__type_traits/negation.h>
@@ -26,28 +27,95 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2627
// Trait representing whether a type requires an array cookie at the start of its allocation when
2728
// allocated as `new T[n]` and deallocated as `delete[] array`.
2829
//
29-
// Under the Itanium C++ ABI [1], we know that an array cookie is available unless `T` is trivially
30-
// destructible and the call to `operator delete[]` is not a sized operator delete. Under ABIs other
31-
// than the Itanium ABI, we assume there are no array cookies.
30+
// Under the Itanium C++ ABI [1] and the ARM ABI which derives from it, we know that an array cookie is available
31+
// unless `T` is trivially destructible and the call to `operator delete[]` is not a sized operator delete. Under
32+
// other ABIs, we assume there are no array cookies.
3233
//
3334
// [1]: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-cookies
34-
#ifdef _LIBCPP_ABI_ITANIUM
35+
#if defined(_LIBCPP_ABI_ITANIUM) || defined(_LIBCPP_ABI_ITANIUM_WITH_ARM_DIFFERENCES)
3536
// TODO: Use a builtin instead
36-
// TODO: We should factor in the choice of the usual deallocation function in this determination.
37+
// TODO: We should factor in the choice of the usual deallocation function in this determination:
38+
// a cookie may be available in more cases but we ignore those for now.
3739
template <class _Tp>
3840
struct __has_array_cookie : _Not<is_trivially_destructible<_Tp> > {};
3941
#else
4042
template <class _Tp>
4143
struct __has_array_cookie : false_type {};
4244
#endif
4345

46+
struct __itanium_array_cookie {
47+
size_t __element_count;
48+
};
49+
50+
template <class _Tp>
51+
struct [[__gnu__::__aligned__(_LIBCPP_ALIGNOF(_Tp))]] __arm_array_cookie {
52+
size_t __element_size;
53+
size_t __element_count;
54+
};
55+
56+
// Return the element count in the array cookie located before the given pointer.
57+
//
58+
// In the Itanium ABI [1]
59+
// ----------------------
60+
// The element count is stored immediately before the first element of the array. If the preferred alignment
61+
// of array elements (which is different from the ABI alignment) is more than that of size_t, additional
62+
// padding bytes exist before the array cookie. Assuming array elements of size and alignment 16 bytes, that
63+
// gives us the following layout:
64+
//
65+
// |ooooooooxxxxxxxxaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd|
66+
// ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67+
// | ^^^^^^^^ |
68+
// | | array elements
69+
// padding |
70+
// element count
71+
//
72+
//
73+
// In the Itanium ABI with ARM differences [2]
74+
// -------------------------------------------
75+
// The array cookie is stored at the very start of the allocation and it has the following form:
76+
//
77+
// struct array_cookie {
78+
// std::size_t element_size; // element_size != 0
79+
// std::size_t element_count;
80+
// };
81+
//
82+
// Assuming elements of size and alignment 32 bytes, this gives us the following layout:
83+
//
84+
// |xxxxxxxxXXXXXXXXooooooooooooooooaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
85+
// ^^^^^^^^ ^^^^^^^^^^^^^^^^
86+
// | ^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
87+
// element size | padding |
88+
// element count array elements
89+
//
90+
// We must be careful to take into account the alignment of the array cookie, which may result in padding
91+
// bytes between the element count and the first element of the array. Note that for ARM, the compiler
92+
// aligns the array cookie using the ABI alignment, not the preferred alignment of array elements.
93+
//
94+
// [1]: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-cookies
95+
// [2]: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Handle-C++-differences
4496
template <class _Tp>
4597
// Avoid failures when -fsanitize-address-poison-custom-array-cookie is enabled
46-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") size_t __get_array_cookie(_Tp const* __ptr) {
98+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") size_t __get_array_cookie([[__maybe_unused__]] _Tp const* __ptr) {
4799
static_assert(
48100
__has_array_cookie<_Tp>::value, "Trying to access the array cookie of a type that is not guaranteed to have one");
49-
size_t const* __cookie = reinterpret_cast<size_t const*>(__ptr) - 1; // TODO: Use a builtin instead
50-
return *__cookie;
101+
102+
#if defined(_LIBCPP_ABI_ITANIUM)
103+
using _ArrayCookie = __itanium_array_cookie;
104+
#elif defined(_LIBCPP_ABI_ITANIUM_WITH_ARM_DIFFERENCES)
105+
using _ArrayCookie = __arm_array_cookie<_Tp>;
106+
#else
107+
static_assert(false, "The array cookie layout is unknown on this ABI");
108+
struct _ArrayCookie { // dummy definition required to make the function parse
109+
size_t element_count;
110+
};
111+
#endif
112+
113+
char const* __array_cookie_start = reinterpret_cast<char const*>(__ptr) - sizeof(_ArrayCookie);
114+
_ArrayCookie __cookie;
115+
// This is necessary to avoid violating strict aliasing. It's valid because _ArrayCookie is an
116+
// implicit lifetime type.
117+
__builtin_memcpy(std::addressof(__cookie), __array_cookie_start, sizeof(_ArrayCookie));
118+
return __cookie.__element_count;
51119
}
52120

53121
_LIBCPP_END_NAMESPACE_STD

lib/libcxx/include/__ranges/join_view.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,13 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
410410

411411
static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator
412412
__compose(__segment_iterator __seg_iter, __local_iterator __local_iter) {
413-
return _JoinViewIterator(
414-
std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter));
413+
auto&& __parent = std::move(__seg_iter).__get_data();
414+
auto&& __outer = std::move(__seg_iter).__get_iter();
415+
if (__local_iter == ranges::end(*__outer)) {
416+
++__outer;
417+
return _JoinViewIterator(*__parent, __outer);
418+
}
419+
return _JoinViewIterator(__parent, __outer, std::move(__local_iter));
415420
}
416421
};
417422

lib/libunwind/src/Unwind-seh.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
174174
}
175175
// FIXME: Indicate target frame in foreign case!
176176
// phase 2: the clean up phase
177-
RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable);
177+
RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, disp->ContextRecord,
178+
disp->HistoryTable);
178179
_LIBUNWIND_ABORT("RtlUnwindEx() failed");
179180
case _URC_INSTALL_CONTEXT: {
180181
// If we were called by __libunwind_seh_personality(), indicate that

0 commit comments

Comments
 (0)