[libcxx-commits] [libcxx] aab67db - [libc++] Fix shared_ptr rebinding allocators to incomplete types (#206145)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jun 26 23:12:24 PDT 2026
Author: Nikolas Klauser
Date: 2026-06-27T08:12:19+02:00
New Revision: aab67db385c2f4b7ac93adf616a52dbd943cfae5
URL: https://github.com/llvm/llvm-project/commit/aab67db385c2f4b7ac93adf616a52dbd943cfae5
DIFF: https://github.com/llvm/llvm-project/commit/aab67db385c2f4b7ac93adf616a52dbd943cfae5.diff
LOG: [libc++] Fix shared_ptr rebinding allocators to incomplete types (#206145)
https://github.com/llvm/llvm-project/pull/200401 caused various ways to
create a `shared_ptr` control block to reject any allocators which
required a complete type. This patch allows allocators to again require
a complete type.
Added:
Modified:
libcxx/include/__memory/shared_ptr.h
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
libcxx/test/support/min_allocator.h
Removed:
################################################################################
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 76a52c35bdf12..750d253912ab1 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -90,9 +90,7 @@ class weak_ptr;
template <class _Tp, class _Dp, class _Alloc>
class _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_pointer final : public __shared_weak_count {
- using __alloc_t _LIBCPP_NODEBUG = __allocator_traits_rebind_t<_Alloc, __shared_ptr_pointer>;
-
- _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
_LIBCPP_NO_UNIQUE_ADDRESS _Dp __deleter_;
_LIBCPP_NO_UNIQUE_ADDRESS _Tp __ptr_;
@@ -114,8 +112,10 @@ class _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_pointer final : public __shared_
}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override {
+ using __alloc_t = __allocator_traits_rebind_t<_Alloc, __shared_ptr_pointer>;
+
__alloc_t __a(__alloc_);
- __alloc_.~__alloc_t();
+ __alloc_.~_Alloc();
__a.deallocate(pointer_traits<typename allocator_traits<__alloc_t>::pointer>::pointer_to(*this), 1);
}
};
@@ -127,51 +127,52 @@ struct __for_overwrite_tag {};
template <class _Tp, class _Alloc>
struct _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_emplace : __shared_weak_count {
- using __alloc_t _LIBCPP_NODEBUG = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace>;
- using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<__alloc_t>;
+ using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<_Alloc>;
using __value_type _LIBCPP_NODEBUG = __remove_cv_t<_Tp>;
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace(_Alloc __a, _Args&&... __args) : __alloc_(std::move(__a)) {
- __alloc_traits::construct(__alloc_, __get_elem(), std::forward<_Args>(__args)...);
+ allocator_traits<_Alloc>::construct(__alloc_, __get_elem(), std::forward<_Args>(__args)...);
}
_LIBCPP_HIDE_FROM_ABI __value_type* __get_elem() _NOEXCEPT { return reinterpret_cast<__value_type*>(__buffer_); }
private:
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override {
- __alloc_traits::destroy(__alloc_, __get_elem());
+ allocator_traits<_Alloc>::destroy(__alloc_, __get_elem());
}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override {
+ using __alloc_t = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace>;
__alloc_t __tmp(__alloc_);
- __alloc_.~__alloc_t();
- __alloc_traits::deallocate(__tmp, pointer_traits<typename __alloc_traits::pointer>::pointer_to(*this), 1);
+ __alloc_.~_Alloc();
+ allocator_traits<__alloc_t>::deallocate(
+ __tmp, pointer_traits<typename allocator_traits<__alloc_t>::pointer>::pointer_to(*this), 1);
}
- _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
_ALIGNAS_TYPE(__value_type) char __buffer_[sizeof(__value_type)];
};
template <class _Tp, class _Alloc>
struct _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_emplace_for_overwrite : __shared_weak_count {
- using __alloc_t _LIBCPP_NODEBUG = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace_for_overwrite>;
using __value_type _LIBCPP_NODEBUG = __remove_cv_t<_Tp>;
_LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace_for_overwrite(_Alloc __a) : __alloc_(std::move(__a)) {}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override { __value_.~__value_type(); }
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override {
- __alloc_t __tmp(__alloc_);
- __alloc_.~__alloc_t();
+ using __alloc_t = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace_for_overwrite>;
using __alloc_traits = allocator_traits<__alloc_t>;
+ __alloc_t __tmp(__alloc_);
+ __alloc_.~_Alloc();
__alloc_traits::deallocate(__tmp, pointer_traits<typename __alloc_traits::pointer>::pointer_to(*this), 1);
}
_LIBCPP_HIDE_FROM_ABI __value_type* __get_elem() _NOEXCEPT { return std::addressof(__value_); }
private:
- _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
_LIBCPP_NO_UNIQUE_ADDRESS __value_type __value_;
};
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
index 074ef44a1f76b..787a108a000e1 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
@@ -165,5 +165,9 @@ int main(int, char**)
test_allocator<derived[4]> >::value, "");
}
+ { // Make sure that the allocator isn't instantiated with an incomplete type
+ std::shared_ptr<int> ptr(new int, std::default_delete<int>(), complete_type_allocator<int>());
+ }
+
return 0;
}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
index 341a442c90a16..2fb89f8e22be8 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
@@ -126,6 +126,7 @@ int main(int, char**)
{
test<bare_allocator<void> >();
test<test_allocator<void> >();
+ test<complete_type_allocator<int> >();
test_allocator_statistics alloc_stats;
{
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
index e6e063304453a..63cfd8c5ae1a5 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
@@ -206,6 +206,12 @@ void test() {
testTypeWithDefaultCtor();
testAllocatorOperationsCalled();
testNotValueInitialized();
+
+ { // Make sure that the allocator isn't instantiated with an incomplete type
+ (void)std::allocate_shared_for_overwrite<int>(complete_type_allocator<int>{});
+ (void)std::allocate_shared_for_overwrite<int[]>(complete_type_allocator<int>{}, 1);
+ (void)std::allocate_shared_for_overwrite<int[1]>(complete_type_allocator<int>{});
+ }
}
int main(int, char**) {
diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h
index 16775649f55cf..6beffc1d2eb10 100644
--- a/libcxx/test/support/min_allocator.h
+++ b/libcxx/test/support/min_allocator.h
@@ -410,7 +410,7 @@ class complete_type_allocator {
TEST_CONSTEXPR_CXX20 complete_type_allocator() TEST_NOEXCEPT {}
template <class U>
- TEST_CONSTEXPR_CXX20 explicit complete_type_allocator(complete_type_allocator<U>) TEST_NOEXCEPT {}
+ TEST_CONSTEXPR_CXX20 complete_type_allocator(complete_type_allocator<U>) TEST_NOEXCEPT {}
TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return static_cast<T*>(std::allocator<T>().allocate(n)); }
More information about the libcxx-commits
mailing list