[libc++] Apply post-commit review comments for unique_ptr<T[]> hardening (#111704)
diff --git a/libcxx/docs/Hardening.rst b/libcxx/docs/Hardening.rst
index 67791a5..fd0f3af 100644
--- a/libcxx/docs/Hardening.rst
+++ b/libcxx/docs/Hardening.rst
@@ -341,6 +341,16 @@
ABI impact: changes the iterator type of ``vector`` (except ``vector<bool>``).
+- ``_LIBCPP_ABI_BOUNDED_UNIQUE_PTR``` -- tracks the bounds of the array stored inside
+ a ``std::unique_ptr<T[]>``, 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<T[]>``, 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 bf3aafe6..905fd81 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -62,6 +62,10 @@
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<T[]>`` to
+ detect out-of-bounds accesses in certain circumstances. ``std::unique_ptr<T[]>`` 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 62c129f..7095d56 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<T[]> 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 6203ec7..28c62e1 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -546,7 +546,7 @@
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT {
reset(__u.release());
__deleter_ = std::forward<deleter_type>(__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 4a03d2b..f208e0cb 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 <memory>
#include <cassert>
-struct T;
-extern void use(std::unique_ptr<T>& ptr);
-extern void use(std::unique_ptr<T[]>& ptr);
+struct Foo;
+extern void use(std::unique_ptr<Foo>& ptr);
+extern void use(std::unique_ptr<Foo[]>& ptr);
#ifdef INCOMPLETE
-void use(std::unique_ptr<T>& ptr) {
+void use(std::unique_ptr<Foo>& 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<T[]>& ptr) {
+void use(std::unique_ptr<Foo[]>& ptr) {
{
- T* x = ptr.get();
+ Foo* x = ptr.get();
assert(x != nullptr);
}
{
@@ -75,16 +75,16 @@
#ifdef COMPLETE
-struct T {}; // complete the type
+struct Foo {}; // complete the type
int main(int, char**) {
{
- std::unique_ptr<T> ptr(new T());
+ std::unique_ptr<Foo> ptr(new Foo());
use(ptr);
}
{
- std::unique_ptr<T[]> ptr(new T[3]());
+ std::unique_ptr<Foo[]> 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 bb4ac98..b7cc123 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 @@
template <class WithCookie, class NoCookie>
void test() {
+ LIBCPP_STATIC_ASSERT(std::__has_array_cookie<WithCookie>::value);
+ LIBCPP_STATIC_ASSERT(!std::__has_array_cookie<NoCookie>::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]`.