Skip to content

Commit f86786e

Browse files
ldionnekazutakahirata
authored andcommitted
[libc++] Pass type information down to __libcpp_allocate (llvm#118837)
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`. It also makes the internal allocation API higher level by operating on objects instead of operating on bytes of memory. 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).
1 parent 3958594 commit f86786e

File tree

12 files changed

+112
-128
lines changed

12 files changed

+112
-128
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,6 @@ set(files
547547
__memory/array_cookie.h
548548
__memory/assume_aligned.h
549549
__memory/auto_ptr.h
550-
__memory/builtin_new_allocator.h
551550
__memory/compressed_pair.h
552551
__memory/concepts.h
553552
__memory/construct_at.h
@@ -880,6 +879,7 @@ set(files
880879
__utility/cmp.h
881880
__utility/convert_to_integral.h
882881
__utility/declval.h
882+
__utility/element_count.h
883883
__utility/empty.h
884884
__utility/exception_guard.h
885885
__utility/exchange.h

libcxx/include/__functional/function.h

Lines changed: 13 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>
@@ -193,6 +192,13 @@ class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
193192
}
194193
};
195194

195+
template <class _Tp>
196+
struct __deallocating_deleter {
197+
_LIBCPP_HIDE_FROM_ABI void operator()(void* __p) const {
198+
std::__libcpp_deallocate<_Tp>(static_cast<_Tp*>(__p), __element_count(1));
199+
}
200+
};
201+
196202
template <class _Fp, class _Rp, class... _ArgTypes>
197203
class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
198204
_Fp __f_;
@@ -212,8 +218,9 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
212218
}
213219

214220
_LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const {
215-
__builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<__default_alloc_func>(1);
216-
__default_alloc_func* __res = ::new ((void*)__hold.get()) __default_alloc_func(__f_);
221+
using _Self = __default_alloc_func;
222+
unique_ptr<_Self, __deallocating_deleter<_Self>> __hold(std::__libcpp_allocate<_Self>(__element_count(1)));
223+
_Self* __res = ::new ((void*)__hold.get()) _Self(__f_);
217224
(void)__hold.release();
218225
return __res;
219226
}
@@ -222,7 +229,7 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
222229

223230
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__default_alloc_func* __f) {
224231
__f->destroy();
225-
__builtin_new_allocator::__deallocate_type<__default_alloc_func>(__f, 1);
232+
std::__libcpp_deallocate<__default_alloc_func>(__f, __element_count(1));
226233
}
227234
};
228235

@@ -668,8 +675,8 @@ class __policy_func<_Rp(_ArgTypes...)> {
668675
if (__use_small_storage<_Fun>()) {
669676
::new ((void*)&__buf_.__small) _Fun(std::move(__f));
670677
} else {
671-
__builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<_Fun>(1);
672-
__buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
678+
unique_ptr<_Fun, __deallocating_deleter<_Fun>> __hold(std::__libcpp_allocate<_Fun>(__element_count(1)));
679+
__buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
673680
(void)__hold.release();
674681
}
675682
}

libcxx/include/__memory/allocator.h

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

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

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
@@ -40,7 +40,7 @@ struct __temporary_buffer_deleter {
4040
return;
4141
}
4242

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

libcxx/include/__new/allocate.h

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <__cstddef/size_t.h>
1515
#include <__new/align_val_t.h>
1616
#include <__new/global_new_delete.h> // for _LIBCPP_HAS_SIZED_DEALLOCATION
17+
#include <__type_traits/type_identity.h>
18+
#include <__utility/element_count.h>
1719

1820
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1921
# pragma GCC system_header
@@ -47,52 +49,58 @@ _LIBCPP_HIDE_FROM_ABI void __libcpp_operator_delete(_Args... __args) _NOEXCEPT {
4749
#endif
4850
}
4951

50-
inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_allocate(size_t __size, size_t __align) {
52+
template <class _Tp>
53+
inline _LIBCPP_HIDE_FROM_ABI _Tp* __libcpp_allocate(__element_count __n, size_t __align = _LIBCPP_ALIGNOF(_Tp)) {
54+
size_t __size = static_cast<size_t>(__n) * sizeof(_Tp);
5155
#if _LIBCPP_HAS_ALIGNED_ALLOCATION
5256
if (__is_overaligned_for_new(__align)) {
5357
const align_val_t __align_val = static_cast<align_val_t>(__align);
54-
return __libcpp_operator_new(__size, __align_val);
58+
return static_cast<_Tp*>(std::__libcpp_operator_new(__size, __align_val));
5559
}
5660
#endif
5761

5862
(void)__align;
59-
return __libcpp_operator_new(__size);
63+
return static_cast<_Tp*>(std::__libcpp_operator_new(__size));
6064
}
6165

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...);
66+
#if _LIBCPP_HAS_SIZED_DEALLOCATION
67+
# define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) __VA_ARGS__
6768
#else
68-
return std::__libcpp_operator_delete(__ptr, __size, __args...);
69+
# define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) /* nothing */
6970
#endif
70-
}
7171

72-
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) _NOEXCEPT {
72+
template <class _Tp>
73+
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate(
74+
__type_identity_t<_Tp>* __ptr, __element_count __n, size_t __align = _LIBCPP_ALIGNOF(_Tp)) _NOEXCEPT {
75+
size_t __size = static_cast<size_t>(__n) * sizeof(_Tp);
76+
(void)__size;
7377
#if !_LIBCPP_HAS_ALIGNED_ALLOCATION
7478
(void)__align;
75-
return __do_deallocate_handle_size(__ptr, __size);
79+
return std::__libcpp_operator_delete(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size));
7680
#else
7781
if (__is_overaligned_for_new(__align)) {
7882
const align_val_t __align_val = static_cast<align_val_t>(__align);
79-
return __do_deallocate_handle_size(__ptr, __size, __align_val);
83+
return std::__libcpp_operator_delete(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size), __align_val);
8084
} else {
81-
return __do_deallocate_handle_size(__ptr, __size);
85+
return std::__libcpp_operator_delete(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size));
8286
}
8387
#endif
8488
}
8589

86-
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate_unsized(void* __ptr, size_t __align) _NOEXCEPT {
90+
#undef _LIBCPP_ONLY_IF_SIZED_DEALLOCATION
91+
92+
template <class _Tp>
93+
inline _LIBCPP_HIDE_FROM_ABI void
94+
__libcpp_deallocate_unsized(__type_identity_t<_Tp>* __ptr, size_t __align = _LIBCPP_ALIGNOF(_Tp)) _NOEXCEPT {
8795
#if !_LIBCPP_HAS_ALIGNED_ALLOCATION
8896
(void)__align;
89-
return __libcpp_operator_delete(__ptr);
97+
return std::__libcpp_operator_delete(__ptr);
9098
#else
9199
if (__is_overaligned_for_new(__align)) {
92100
const align_val_t __align_val = static_cast<align_val_t>(__align);
93-
return __libcpp_operator_delete(__ptr, __align_val);
101+
return std::__libcpp_operator_delete(__ptr, __align_val);
94102
} else {
95-
return __libcpp_operator_delete(__ptr);
103+
return std::__libcpp_operator_delete(__ptr);
96104
}
97105
#endif
98106
}

libcxx/include/__string/constexpr_c_functions.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <__type_traits/is_trivially_copyable.h>
2626
#include <__type_traits/is_trivially_lexicographically_comparable.h>
2727
#include <__type_traits/remove_cv.h>
28+
#include <__utility/element_count.h>
2829
#include <__utility/is_pointer_in_range.h>
2930

3031
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -33,10 +34,6 @@
3334

3435
_LIBCPP_BEGIN_NAMESPACE_STD
3536

36-
// Type used to encode that a function takes an integer that represents a number
37-
// of elements as opposed to a number of bytes.
38-
enum class __element_count : size_t {};
39-
4037
template <class _Tp>
4138
inline const bool __is_char_type = false;
4239

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___UTILITY_ELEMENT_COUNT_H
10+
#define _LIBCPP___UTILITY_ELEMENT_COUNT_H
11+
12+
#include <__config>
13+
#include <__cstddef/size_t.h>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
_LIBCPP_BEGIN_NAMESPACE_STD
20+
21+
// Type used to encode that a function takes an integer that represents a number
22+
// of elements as opposed to a number of bytes.
23+
enum class __element_count : size_t {};
24+
25+
_LIBCPP_END_NAMESPACE_STD
26+
27+
#endif // _LIBCPP___UTILITY_ELEMENT_COUNT_H

libcxx/include/__utility/small_buffer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class __small_buffer {
6868
if constexpr (__fits_in_buffer<_Stored>) {
6969
return std::launder(reinterpret_cast<_Stored*>(__buffer_));
7070
} else {
71-
byte* __allocation = static_cast<byte*>(std::__libcpp_allocate(sizeof(_Stored), alignof(_Stored)));
71+
byte* __allocation = reinterpret_cast<byte*>(std::__libcpp_allocate<_Stored>(__element_count(1)));
7272
std::construct_at(reinterpret_cast<byte**>(__buffer_), __allocation);
7373
return std::launder(reinterpret_cast<_Stored*>(__allocation));
7474
}
@@ -77,7 +77,7 @@ class __small_buffer {
7777
template <class _Stored>
7878
_LIBCPP_HIDE_FROM_ABI void __dealloc() noexcept {
7979
if constexpr (!__fits_in_buffer<_Stored>)
80-
std::__libcpp_deallocate(*reinterpret_cast<void**>(__buffer_), sizeof(_Stored), alignof(_Stored));
80+
std::__libcpp_deallocate<_Stored>(__get<_Stored>(), __element_count(1));
8181
}
8282

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

libcxx/include/module.modulemap

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,14 +1527,16 @@ module std [system] {
15271527
module aligned_alloc { header "__memory/aligned_alloc.h" }
15281528
module allocate_at_least { header "__memory/allocate_at_least.h" }
15291529
module allocation_guard { header "__memory/allocation_guard.h" }
1530-
module allocator { header "__memory/allocator.h" }
1530+
module allocator {
1531+
header "__memory/allocator.h"
1532+
export * // TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108
1533+
}
15311534
module allocator_arg_t { header "__memory/allocator_arg_t.h" }
15321535
module allocator_destructor { header "__memory/allocator_destructor.h" }
15331536
module allocator_traits { header "__memory/allocator_traits.h" }
15341537
module array_cookie { header "__memory/array_cookie.h" }
15351538
module assume_aligned { header "__memory/assume_aligned.h" }
15361539
module auto_ptr { header "__memory/auto_ptr.h" }
1537-
module builtin_new_allocator { header "__memory/builtin_new_allocator.h" }
15381540
module compressed_pair { header "__memory/compressed_pair.h" }
15391541
module concepts { header "__memory/concepts.h" }
15401542
module construct_at { header "__memory/construct_at.h" }
@@ -1569,6 +1571,7 @@ module std [system] {
15691571
header "__memory/unique_temporary_buffer.h"
15701572
export std.memory.unique_ptr
15711573
export std_core.type_traits.is_constant_evaluated
1574+
export * // TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108
15721575
}
15731576
module uses_allocator { header "__memory/uses_allocator.h" }
15741577
module uses_allocator_construction { header "__memory/uses_allocator_construction.h" }
@@ -1604,7 +1607,11 @@ module std [system] {
16041607
module new {
16051608
header "new"
16061609
module align_val_t { header "__new/align_val_t.h" }
1607-
module allocate { header "__new/allocate.h" }
1610+
module allocate {
1611+
header "__new/allocate.h"
1612+
export std.utility.element_count // used as part of the API
1613+
export * // TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108
1614+
}
16081615
module destroying_delete_t { header "__new/destroying_delete_t.h" }
16091616
module exceptions { header "__new/exceptions.h" }
16101617
module global_new_delete {
@@ -1911,7 +1918,10 @@ module std [system] {
19111918

19121919
module string {
19131920
module char_traits { header "__string/char_traits.h" }
1914-
module constexpr_c_functions { header "__string/constexpr_c_functions.h" }
1921+
module constexpr_c_functions {
1922+
header "__string/constexpr_c_functions.h"
1923+
export std.utility.element_count // used as part of the constexpr C function's API
1924+
}
19151925
module extern_template_lists { header "__string/extern_template_lists.h" }
19161926
module fwd { header "__fwd/string.h" }
19171927

@@ -2021,6 +2031,7 @@ module std [system] {
20212031
}
20222032
module cmp { header "__utility/cmp.h" }
20232033
module convert_to_integral { header "__utility/convert_to_integral.h" }
2034+
module element_count { header "__utility/element_count.h" }
20242035
module exception_guard { header "__utility/exception_guard.h" }
20252036
module exchange { header "__utility/exchange.h" }
20262037
module forward_like { header "__utility/forward_like.h" }

0 commit comments

Comments
 (0)