[libcxx-commits] [libcxxabi] 4207ad5 - [libc++] Fix noexcept behaviour of operator new helper functions (#74337)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 22 10:38:58 PST 2024


Author: azhan92
Date: 2024-01-22T13:38:54-05:00
New Revision: 4207ad57707f07208dfb1d7c79889e1372c396ab

URL: https://github.com/llvm/llvm-project/commit/4207ad57707f07208dfb1d7c79889e1372c396ab
DIFF: https://github.com/llvm/llvm-project/commit/4207ad57707f07208dfb1d7c79889e1372c396ab.diff

LOG: [libc++] Fix noexcept behaviour of operator new helper functions  (#74337)

This patch removes the noexcept specifier introduced in #69407 since the
Standard allows a new handler to throw an exception of type bad_alloc 
(or derived from it). With the noexcept specifier on the helper
functions, we would immediately terminate the program.

The patch also adds tests for the case that had regressed.

Co-authored-by: Alison Zhang <alisonzhang at ibm.com>

Added: 
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.except.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.except.pass.cpp

Modified: 
    libcxx/src/new.cpp
    libcxxabi/src/stdlib_new_delete.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp
index 033bba5c1fc95b6..cb8b4aae8d5f94b 100644
--- a/libcxx/src/new.cpp
+++ b/libcxx/src/new.cpp
@@ -20,7 +20,7 @@
 // in this shared library, so that they can be overridden by programs
 // that define non-weak copies of the functions.
 
-static void* operator_new_impl(std::size_t size) noexcept {
+static void* operator_new_impl(std::size_t size) {
   if (size == 0)
     size = 1;
   void* p;
@@ -87,7 +87,7 @@ _LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator del
 
 #  if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
 
-static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) noexcept {
+static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
   if (size == 0)
     size = 1;
   if (static_cast<size_t>(alignment) < sizeof(void*))

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp
new file mode 100644
index 000000000000000..6a2b098c1b5738a
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new[](std::numeric_limits<std::size_t>::max());
+    (void)x;
+    assert(false);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp
new file mode 100644
index 000000000000000..cde7dc53be5bde5
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new[](std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32));
+    (void)x;
+    assert(false);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.except.pass.cpp
new file mode 100644
index 000000000000000..251ba0f495991fd
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new[](std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32), std::nothrow);
+    (void)x;
+    assert(x == NULL);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.except.pass.cpp
new file mode 100644
index 000000000000000..a68a980bb4f7a90
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new[](std::numeric_limits<std::size_t>::max(), std::nothrow);
+    (void)x;
+    assert(x == NULL);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp
new file mode 100644
index 000000000000000..6a515555e6dbd67
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new(std::numeric_limits<std::size_t>::max());
+    (void)x;
+    assert(false);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp
new file mode 100644
index 000000000000000..cb83fb26ab1e6ce
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new(std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32));
+    (void)x;
+    assert(false);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.except.pass.cpp
new file mode 100644
index 000000000000000..d95e78e24e1a9bb
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new(std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32), std::nothrow);
+    (void)x;
+    assert(x == NULL);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.except.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.except.pass.cpp
new file mode 100644
index 000000000000000..db9a90709b50548
--- /dev/null
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.except.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-exceptions
+// UNSUPPORTED: sanitizer-new-delete
+
+#include <new>
+#include <cassert>
+#include <limits>
+#include <cstdlib>
+
+struct construction_key {};
+struct my_bad_alloc : std::bad_alloc {
+  my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
+  my_bad_alloc(construction_key) : self(this) {}
+  const my_bad_alloc* const self;
+};
+
+int new_handler_called = 0;
+
+void my_new_handler() {
+  ++new_handler_called;
+  throw my_bad_alloc(construction_key());
+}
+
+int main(int, char**) {
+  std::set_new_handler(my_new_handler);
+  try {
+    void* x = operator new(std::numeric_limits<std::size_t>::max(), std::nothrow);
+    (void)x;
+    assert(x == NULL);
+  } catch (my_bad_alloc const& e) {
+    assert(new_handler_called == 1);
+    assert(e.self == &e);
+  } catch (...) {
+    assert(false);
+  }
+  return 0;
+}

diff  --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp
index 6c9990f063dde66..f8a00ec5842566e 100644
--- a/libcxxabi/src/stdlib_new_delete.cpp
+++ b/libcxxabi/src/stdlib_new_delete.cpp
@@ -30,7 +30,7 @@
 // in this shared library, so that they can be overridden by programs
 // that define non-weak copies of the functions.
 
-static void* operator_new_impl(std::size_t size) noexcept {
+static void* operator_new_impl(std::size_t size) {
   if (size == 0)
     size = 1;
   void* p;
@@ -107,7 +107,7 @@ void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
 
 #if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
 
-static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) noexcept {
+static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
   if (size == 0)
     size = 1;
   if (static_cast<size_t>(alignment) < sizeof(void*))


        


More information about the libcxx-commits mailing list