diff --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h index b95c6a37c5c11..1b8711f10811d 100644 --- a/libcxx/include/__memory_resource/polymorphic_allocator.h +++ b/libcxx/include/__memory_resource/polymorphic_allocator.h @@ -50,7 +50,9 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator { _LIBCPP_HIDE_FROM_ABI polymorphic_allocator() noexcept : __res_(std::pmr::get_default_resource()) {} - _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* __r) noexcept : __res_(__r) {} + _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* _LIBCPP_DIAGNOSE_NULLPTR __r) noexcept : __res_(__r) { + _LIBCPP_ASSERT_NON_NULL(__r, "Attempted to pass a nullptr resource to polymorphic_alloator"); + } _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator&) = default; @@ -174,7 +176,7 @@ class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator { return polymorphic_allocator(); } - _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; } + [[__gnu__::__returns_nonnull__]] _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; } _LIBCPP_HIDE_FROM_ABI friend bool operator==(const polymorphic_allocator& __lhs, const polymorphic_allocator& __rhs) noexcept { diff --git a/libcxx/test/libcxx/mem/mem.res/ctor.nullptr.assert.pass.cpp b/libcxx/test/libcxx/mem/mem.res/ctor.nullptr.assert.pass.cpp new file mode 100644 index 0000000000000..831985f2ce37f --- /dev/null +++ b/libcxx/test/libcxx/mem/mem.res/ctor.nullptr.assert.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// Test hardening assertions for std::pmr::polymorphic_allocator. + +// REQUIRES: has-unix-headers +// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: c++03, c++11, c++14 +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// We're testing nullptr assertions +// ADDITIONAL_COMPILE_FLAGS: -Wno-nonnull + +#include + +#include "check_assertion.h" + +int main(int, char**) { + TEST_LIBCPP_ASSERT_FAILURE( + std::pmr::polymorphic_allocator(nullptr), "Attempted to pass a nullptr resource to polymorphic_alloator"); + + return 0; +} diff --git a/libcxx/test/libcxx/mem/mem.res/nonnull.verify.cpp b/libcxx/test/libcxx/mem/mem.res/nonnull.verify.cpp new file mode 100644 index 0000000000000..c5a6c8a3db3cf --- /dev/null +++ b/libcxx/test/libcxx/mem/mem.res/nonnull.verify.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// Ensure that passing a nullptr to polymorphic_allocator is diagnosed + +#include + +void test() { + std::pmr::polymorphic_allocator alloc(nullptr); // expected-warning {{null passed}} +} diff --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp index 23865f67a694b..22cb72414e975 100644 --- a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp +++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp @@ -17,11 +17,19 @@ // memory_resource * // polymorphic_allocator::resource() const -#include #include +#include +#include +#include #include "test_macros.h" +struct resource : std::pmr::memory_resource { + void* do_allocate(size_t, size_t) override { TEST_THROW(std::bad_alloc()); } + void do_deallocate(void*, size_t, size_t) override { assert(false); } + bool do_is_equal(const std::pmr::memory_resource&) const noexcept override { return false; } +}; + int main(int, char**) { typedef std::pmr::polymorphic_allocator A; { @@ -29,24 +37,19 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(a.resource()), std::pmr::memory_resource*); } { - std::pmr::memory_resource* mptr = (std::pmr::memory_resource*)42; - A const a(mptr); - assert(a.resource() == mptr); - } - { - A const a(nullptr); - assert(a.resource() == nullptr); - assert(a.resource() == nullptr); + resource res; + A const a(&res); + assert(a.resource() == &res); } { A const a; assert(a.resource() == std::pmr::get_default_resource()); } { - std::pmr::memory_resource* mptr = (std::pmr::memory_resource*)42; - std::pmr::set_default_resource(mptr); + resource res; + std::pmr::set_default_resource(&res); A const a; - assert(a.resource() == mptr); + assert(a.resource() == &res); assert(a.resource() == std::pmr::get_default_resource()); } diff --git a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp index 58d6cccd244cf..ccac1178fe516 100644 --- a/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp +++ b/libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp @@ -17,11 +17,19 @@ // polymorphic_allocator // polymorphic_allocator::select_on_container_copy_construction() const -#include #include +#include +#include +#include #include "test_macros.h" +struct resource : std::pmr::memory_resource { + void* do_allocate(size_t, size_t) override { TEST_THROW(std::bad_alloc()); } + void do_deallocate(void*, size_t, size_t) override { assert(false); } + bool do_is_equal(const std::pmr::memory_resource&) const noexcept override { return false; } +}; + int main(int, char**) { typedef std::pmr::polymorphic_allocator A; { @@ -29,22 +37,12 @@ int main(int, char**) { ASSERT_SAME_TYPE(decltype(a.select_on_container_copy_construction()), A); } { - std::pmr::memory_resource* mptr = (std::pmr::memory_resource*)42; - A const a(mptr); - assert(a.resource() == mptr); - A const other = a.select_on_container_copy_construction(); - assert(other.resource() == std::pmr::get_default_resource()); - assert(a.resource() == mptr); - } - { - std::pmr::memory_resource* mptr = (std::pmr::memory_resource*)42; - std::pmr::set_default_resource(mptr); - A const a(nullptr); - assert(a.resource() == nullptr); + resource res; + A const a(&res); + assert(a.resource() == &res); A const other = a.select_on_container_copy_construction(); assert(other.resource() == std::pmr::get_default_resource()); - assert(other.resource() == mptr); - assert(a.resource() == nullptr); + assert(a.resource() == &res); } return 0;