diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst index 67791a5e55ac7c..fd0f3af5ef2f96 100644 --- a/libcxx/docs/Hardening.rst +++ b/libcxx/docs/Hardening.rst @@ -341,6 +341,16 @@ Vendors can use the following ABI options to enable additional hardening checks: ABI impact: changes the iterator type of ``vector`` (except ``vector``). +- ``_LIBCPP_ABI_BOUNDED_UNIQUE_PTR``` -- tracks the bounds of the array stored inside + a ``std::unique_ptr``, allowing it to trap when accessed out-of-bounds. This + requires the ``std::unique_ptr`` to be created using an API like ``std::make_unique`` + or ``std::make_unique_for_overwrite``, otherwise the bounds information is not available + to the library. + + ABI impact: changes the layout of ``std::unique_ptr``, and the representation + of a few library types that use ``std::unique_ptr`` internally, such as + the unordered containers. + ABI tags -------- diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst index dcb1102d81d641..e7f86ddafb8fbc 100644 --- a/libcxx/docs/ReleaseNotes/20.rst +++ b/libcxx/docs/ReleaseNotes/20.rst @@ -60,6 +60,10 @@ Improvements and New Features compile times and smaller debug information as well as better code generation if optimizations are disabled. The Chromium project measured a 5% reduction in object file and debug information size. +- The ``_LIBCPP_ABI_BOUNDED_UNIQUE_PTR`` ABI configuration was added, which allows ``std::unique_ptr`` to + detect out-of-bounds accesses in certain circumstances. ``std::unique_ptr`` can now also detect out-of-bounds + accesses for a limited set of types (non-trivially destructible types) when the ABI configuration is disabled. + Deprecations and Removals ------------------------- diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h index 62c129f5921dee..7095d56c6dc39d 100644 --- a/libcxx/include/__configuration/abi.h +++ b/libcxx/include/__configuration/abi.h @@ -186,6 +186,8 @@ // of types can be checked. // // ABI impact: This causes the layout of std::unique_ptr to change and its size to increase. +// This also affects the representation of a few library types that use std::unique_ptr +// internally, such as the unordered containers. // #define _LIBCPP_ABI_BOUNDED_UNIQUE_PTR #if defined(_LIBCPP_COMPILER_CLANG_BASED) diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h index 6e42ef1eaa1a3c..f18e5987cb9ae9 100644 --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -543,7 +543,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT { reset(__u.release()); __deleter_ = std::forward(__u.get_deleter()); - __checker_ = std::move(std::move(__u.__checker_)); + __checker_ = std::move(__u.__checker_); return *this; } diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/incomplete.sh.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/incomplete.sh.cpp index 4a03d2bcf07bfe..f208e0cb3737d2 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/incomplete.sh.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/incomplete.sh.cpp @@ -23,19 +23,19 @@ #include #include -struct T; -extern void use(std::unique_ptr& ptr); -extern void use(std::unique_ptr& ptr); +struct Foo; +extern void use(std::unique_ptr& ptr); +extern void use(std::unique_ptr& ptr); #ifdef INCOMPLETE -void use(std::unique_ptr& ptr) { +void use(std::unique_ptr& ptr) { { - T* x = ptr.get(); + Foo* x = ptr.get(); assert(x != nullptr); } { - T& ref = *ptr; + Foo& ref = *ptr; assert(&ref == ptr.get()); } { @@ -52,9 +52,9 @@ void use(std::unique_ptr& ptr) { } } -void use(std::unique_ptr& ptr) { +void use(std::unique_ptr& ptr) { { - T* x = ptr.get(); + Foo* x = ptr.get(); assert(x != nullptr); } { @@ -75,16 +75,16 @@ void use(std::unique_ptr& ptr) { #ifdef COMPLETE -struct T {}; // complete the type +struct Foo {}; // complete the type int main(int, char**) { { - std::unique_ptr ptr(new T()); + std::unique_ptr ptr(new Foo()); use(ptr); } { - std::unique_ptr ptr(new T[3]()); + std::unique_ptr ptr(new Foo[3]()); use(ptr); } return 0; diff --git a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp index bb4ac981600f9e..b7cc12350027b9 100644 --- a/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp +++ b/libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.observers/assert.subscript.pass.cpp @@ -26,6 +26,7 @@ #include "check_assertion.h" #include "type_algorithms.h" +#include "test_macros.h" struct MyDeleter { MyDeleter() = default; @@ -48,6 +49,9 @@ struct MyDeleter { template void test() { + LIBCPP_STATIC_ASSERT(std::__has_array_cookie::value); + LIBCPP_STATIC_ASSERT(!std::__has_array_cookie::value); + // For types with an array cookie, we can always detect OOB accesses. Note that reliance on an array // cookie is limited to the default deleter, since a unique_ptr with a custom deleter may not have // been allocated with `new T[n]`.