Skip to content

Commit d603ed6

Browse files
committed
[libc++] Pass type information down to __libcpp_allocate
Currently, places where we call __libcpp_allocate must drop type information on the ground even when they actually have such information available. That is unfortunate since some toolchains and system allocators are able to provide improved security when they know what type is being allocated. This is the purpose of http://wg21.link/p2719, where we introduce a new variant of `operator new` which takes a type in its interface. A different but related issue is that `std::allocator` does not honor any in-class `T::operator new` since it is specified to call the global `::operator new` instead. This patch closes the gap to make it trivial for implementations that provide typed memory allocators to actually benefit from that information in more contexts, and also makes libc++ forward-compatible with future proposals that would fix the existing defects in `std::allocator`. Since this is a widely-used function and making this a template could have an impact on debug info sizes, I tried minimizing the number of templated layers by removing `__do_deallocate_handle_size`, which was easy to replace with a macro (and IMO this leads to cleaner code). We could also explore using `_LIBCPP_NODEBUG` on `__libcpp_allocate` and friends if that proves to be a problem.
1 parent 9474e09 commit d603ed6

File tree

10 files changed

+63
-120
lines changed

10 files changed

+63
-120
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,6 @@ set(files
548548
__memory/array_cookie.h
549549
__memory/assume_aligned.h
550550
__memory/auto_ptr.h
551-
__memory/builtin_new_allocator.h
552551
__memory/compressed_pair.h
553552
__memory/concepts.h
554553
__memory/construct_at.h

libcxx/include/__functional/function.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <__memory/allocator.h>
2323
#include <__memory/allocator_destructor.h>
2424
#include <__memory/allocator_traits.h>
25-
#include <__memory/builtin_new_allocator.h>
2625
#include <__memory/compressed_pair.h>
2726
#include <__memory/unique_ptr.h>
2827
#include <__type_traits/aligned_storage.h>
@@ -213,8 +212,10 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
213212
}
214213

215214
_LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const {
216-
__builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<__default_alloc_func>(1);
217-
__default_alloc_func* __res = ::new ((void*)__hold.get()) __default_alloc_func(__f_);
215+
using _Self = __default_alloc_func;
216+
unique_ptr<_Self, __deallocating_deleter<_Self>> __hold =
217+
std::__libcpp_allocate<_Self>(sizeof(_Self), _LIBCPP_ALIGNOF(_Self));
218+
_Self* __res = ::new ((void*)__hold.get()) _Self(__f_);
218219
(void)__hold.release();
219220
return __res;
220221
}
@@ -223,7 +224,7 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
223224

224225
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__default_alloc_func* __f) {
225226
__f->destroy();
226-
__builtin_new_allocator::__deallocate_type<__default_alloc_func>(__f, 1);
227+
__deallocating_deleter<__default_alloc_func>()(__f);
227228
}
228229
};
229230

@@ -669,8 +670,9 @@ class __policy_func<_Rp(_ArgTypes...)> {
669670
if (__use_small_storage<_Fun>()) {
670671
::new ((void*)&__buf_.__small) _Fun(std::move(__f));
671672
} else {
672-
__builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<_Fun>(1);
673-
__buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
673+
unique_ptr<_Fun, __deallocating_deleter<_Fun>> __hold =
674+
std::__libcpp_allocate<_Fun>(sizeof(_Fun), _LIBCPP_ALIGNOF(_Fun));
675+
__buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
674676
(void)__hold.release();
675677
}
676678
}

libcxx/include/__memory/allocator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if<!is_void<_Tp>::v
101101
if (__libcpp_is_constant_evaluated()) {
102102
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
103103
} else {
104-
return static_cast<_Tp*>(std::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
104+
return static_cast<_Tp*>(std::__libcpp_allocate<_Tp>(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
105105
}
106106
}
107107

@@ -116,7 +116,7 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if<!is_void<_Tp>::v
116116
if (__libcpp_is_constant_evaluated()) {
117117
::operator delete(__p);
118118
} else {
119-
std::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
119+
std::__libcpp_deallocate<_Tp>((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
120120
}
121121
}
122122

libcxx/include/__memory/builtin_new_allocator.h

Lines changed: 0 additions & 67 deletions
This file was deleted.

libcxx/include/__memory/unique_temporary_buffer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct __temporary_buffer_deleter {
3939
return;
4040
}
4141

42-
std::__libcpp_deallocate_unsized((void*)__ptr, _LIBCPP_ALIGNOF(_Tp));
42+
std::__libcpp_deallocate_unsized<_Tp>((void*)__ptr, _LIBCPP_ALIGNOF(_Tp));
4343
}
4444
};
4545

libcxx/include/__new/allocate.h

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI bool __is_overaligned_for_new(siz
2929
#endif
3030
}
3131

32-
template <class... _Args>
32+
template <class _Tp, class... _Args>
3333
_LIBCPP_HIDE_FROM_ABI void* __libcpp_operator_new(_Args... __args) {
3434
#if __has_builtin(__builtin_operator_new) && __has_builtin(__builtin_operator_delete)
3535
return __builtin_operator_new(__args...);
@@ -38,7 +38,7 @@ _LIBCPP_HIDE_FROM_ABI void* __libcpp_operator_new(_Args... __args) {
3838
#endif
3939
}
4040

41-
template <class... _Args>
41+
template <class _Tp, class... _Args>
4242
_LIBCPP_HIDE_FROM_ABI void __libcpp_operator_delete(_Args... __args) _NOEXCEPT {
4343
#if __has_builtin(__builtin_operator_new) && __has_builtin(__builtin_operator_delete)
4444
__builtin_operator_delete(__args...);
@@ -47,52 +47,61 @@ _LIBCPP_HIDE_FROM_ABI void __libcpp_operator_delete(_Args... __args) _NOEXCEPT {
4747
#endif
4848
}
4949

50+
template <class _Tp>
5051
inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_allocate(size_t __size, size_t __align) {
5152
#if _LIBCPP_HAS_ALIGNED_ALLOCATION
5253
if (__is_overaligned_for_new(__align)) {
5354
const align_val_t __align_val = static_cast<align_val_t>(__align);
54-
return __libcpp_operator_new(__size, __align_val);
55+
return std::__libcpp_operator_new<_Tp>(__size, __align_val);
5556
}
5657
#endif
5758

5859
(void)__align;
59-
return __libcpp_operator_new(__size);
60+
return std::__libcpp_operator_new<_Tp>(__size);
6061
}
6162

62-
template <class... _Args>
63-
_LIBCPP_HIDE_FROM_ABI void __do_deallocate_handle_size(void* __ptr, size_t __size, _Args... __args) _NOEXCEPT {
64-
#if !_LIBCPP_HAS_SIZED_DEALLOCATION
65-
(void)__size;
66-
return std::__libcpp_operator_delete(__ptr, __args...);
63+
#if _LIBCPP_HAS_SIZED_DEALLOCATION
64+
# define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) __VA_ARGS__
6765
#else
68-
return std::__libcpp_operator_delete(__ptr, __size, __args...);
66+
# define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) /* nothing */
6967
#endif
70-
}
7168

69+
template <class _Tp>
7270
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) _NOEXCEPT {
71+
(void)__size;
7372
#if !_LIBCPP_HAS_ALIGNED_ALLOCATION
7473
(void)__align;
75-
return __do_deallocate_handle_size(__ptr, __size);
74+
return std::__libcpp_operator_delete<_Tp>(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size));
7675
#else
7776
if (__is_overaligned_for_new(__align)) {
7877
const align_val_t __align_val = static_cast<align_val_t>(__align);
79-
return __do_deallocate_handle_size(__ptr, __size, __align_val);
78+
return std::__libcpp_operator_delete<_Tp>(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size), __align_val);
8079
} else {
81-
return __do_deallocate_handle_size(__ptr, __size);
80+
return std::__libcpp_operator_delete<_Tp>(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size));
8281
}
8382
#endif
8483
}
8584

85+
template <class _Tp>
86+
struct __deallocating_deleter {
87+
_LIBCPP_HIDE_FROM_ABI void operator()(void* __p) const {
88+
std::__libcpp_deallocate<_Tp>(__p, sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
89+
}
90+
};
91+
92+
#undef _LIBCPP_ONLY_IF_SIZED_DEALLOCATION
93+
94+
template <class _Tp>
8695
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate_unsized(void* __ptr, size_t __align) _NOEXCEPT {
8796
#if !_LIBCPP_HAS_ALIGNED_ALLOCATION
8897
(void)__align;
89-
return __libcpp_operator_delete(__ptr);
98+
return std::__libcpp_operator_delete<_Tp>(__ptr);
9099
#else
91100
if (__is_overaligned_for_new(__align)) {
92101
const align_val_t __align_val = static_cast<align_val_t>(__align);
93-
return __libcpp_operator_delete(__ptr, __align_val);
102+
return std::__libcpp_operator_delete<_Tp>(__ptr, __align_val);
94103
} else {
95-
return __libcpp_operator_delete(__ptr);
104+
return std::__libcpp_operator_delete<_Tp>(__ptr);
96105
}
97106
#endif
98107
}

libcxx/include/__utility/small_buffer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class __small_buffer {
6767
if constexpr (__fits_in_buffer<_Stored>) {
6868
return std::launder(reinterpret_cast<_Stored*>(__buffer_));
6969
} else {
70-
byte* __allocation = static_cast<byte*>(std::__libcpp_allocate(sizeof(_Stored), alignof(_Stored)));
70+
byte* __allocation = static_cast<byte*>(std::__libcpp_allocate<_Stored>(sizeof(_Stored), alignof(_Stored)));
7171
std::construct_at(reinterpret_cast<byte**>(__buffer_), __allocation);
7272
return std::launder(reinterpret_cast<_Stored*>(__allocation));
7373
}
@@ -76,7 +76,7 @@ class __small_buffer {
7676
template <class _Stored>
7777
_LIBCPP_HIDE_FROM_ABI void __dealloc() noexcept {
7878
if constexpr (!__fits_in_buffer<_Stored>)
79-
std::__libcpp_deallocate(*reinterpret_cast<void**>(__buffer_), sizeof(_Stored), alignof(_Stored));
79+
std::__libcpp_deallocate<_Stored>(*reinterpret_cast<void**>(__buffer_), sizeof(_Stored), alignof(_Stored));
8080
}
8181

8282
template <class _Stored, class... _Args>

libcxx/include/module.modulemap

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1534,7 +1534,6 @@ module std [system] {
15341534
module array_cookie { header "__memory/array_cookie.h" }
15351535
module assume_aligned { header "__memory/assume_aligned.h" }
15361536
module auto_ptr { header "__memory/auto_ptr.h" }
1537-
module builtin_new_allocator { header "__memory/builtin_new_allocator.h" }
15381537
module compressed_pair { header "__memory/compressed_pair.h" }
15391538
module concepts { header "__memory/concepts.h" }
15401539
module construct_at { header "__memory/construct_at.h" }

libcxx/src/memory_resource.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,22 @@ static bool is_aligned_to(void* ptr, size_t align) {
4141
class _LIBCPP_EXPORTED_FROM_ABI __new_delete_memory_resource_imp : public memory_resource {
4242
void* do_allocate(size_t bytes, size_t align) override {
4343
#if _LIBCPP_HAS_ALIGNED_ALLOCATION
44-
return std::__libcpp_allocate(bytes, align);
44+
return std::__libcpp_allocate<std::byte>(bytes, align);
4545
#else
4646
if (bytes == 0)
4747
bytes = 1;
48-
void* result = std::__libcpp_allocate(bytes, align);
48+
void* result = std::__libcpp_allocate<std::byte>(bytes, align);
4949
if (!is_aligned_to(result, align)) {
50-
std::__libcpp_deallocate(result, bytes, align);
50+
std::__libcpp_deallocate<std::byte>(result, bytes, align);
5151
__throw_bad_alloc();
5252
}
5353
return result;
5454
#endif
5555
}
5656

57-
void do_deallocate(void* p, size_t bytes, size_t align) override { std::__libcpp_deallocate(p, bytes, align); }
57+
void do_deallocate(void* p, size_t bytes, size_t align) override {
58+
std::__libcpp_deallocate<std::byte>(p, bytes, align);
59+
}
5860

5961
bool do_is_equal(const memory_resource& other) const noexcept override { return &other == this; }
6062
};

0 commit comments

Comments
 (0)