]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR libstdc++/68210 adjust operator new and delete for LWG 206
authorJonathan Wakely <jwakely@redhat.com>
Fri, 10 Aug 2018 20:20:27 +0000 (21:20 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 10 Aug 2018 20:20:27 +0000 (21:20 +0100)
Ensure that nothrow versions of new and delete call the ordinary
versions of new or delete, instead of calling malloc or free directly.

These files are all compiled with -std=gnu++14 so can use noexcept and
nullptr to make the code more readable.

PR libstdc++/68210
* doc/xml/manual/intro.xml: Document LWG 206 change.
* libsupc++/del_op.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept.
* libsupc++/del_opa.cc: Likewise.
* libsupc++/del_opant.cc: Likewise.
* libsupc++/del_opnt.cc: Likewise. Call operator delete(ptr) instead
of free(ptr).
* libsupc++/del_ops.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept.
* libsupc++/del_opsa.cc: Likewise.
* libsupc++/del_opva.cc: Likewise.
* libsupc++/del_opvant.cc: Likewise.
* libsupc++/del_opvnt.cc: Likewise. Call operator delete[](ptr)
instead of operator delete(ptr).
* libsupc++/del_opvs.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept.
* libsupc++/del_opvsa.cc: Likewise.
* libsupc++/new_op.cc: Use __builtin_expect in check for zero size.
* libsupc++/new_opa.cc: Use nullptr instead of literal 0.
* libsupc++/new_opant.cc: Likewise. Replace _GLIBCXX_USE_NOEXCEPT
with noexcept.
* libsupc++/new_opnt.cc: Likewise. Call operator new(sz) instead of
malloc(sz).
* libsupc++/new_opvant.cc: Use nullptr and noexcept.
* libsupc++/new_opvnt.cc: Likewise. Call operator new[](sz) instead of
operator new(sz, nothrow).
* testsuite/18_support/new_nothrow.cc: New test.

From-SVN: r263478

20 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/doc/xml/manual/intro.xml
libstdc++-v3/libsupc++/del_op.cc
libstdc++-v3/libsupc++/del_opa.cc
libstdc++-v3/libsupc++/del_opant.cc
libstdc++-v3/libsupc++/del_opnt.cc
libstdc++-v3/libsupc++/del_ops.cc
libstdc++-v3/libsupc++/del_opsa.cc
libstdc++-v3/libsupc++/del_opva.cc
libstdc++-v3/libsupc++/del_opvant.cc
libstdc++-v3/libsupc++/del_opvnt.cc
libstdc++-v3/libsupc++/del_opvs.cc
libstdc++-v3/libsupc++/del_opvsa.cc
libstdc++-v3/libsupc++/new_op.cc
libstdc++-v3/libsupc++/new_opa.cc
libstdc++-v3/libsupc++/new_opant.cc
libstdc++-v3/libsupc++/new_opnt.cc
libstdc++-v3/libsupc++/new_opvant.cc
libstdc++-v3/libsupc++/new_opvnt.cc
libstdc++-v3/testsuite/18_support/new_nothrow.cc [new file with mode: 0644]

index aa90b20410d427575ad0bea25d80b8487b5966e7..fd547e26039146f0e9e96e7ad8047fe7b9ac0b0c 100644 (file)
@@ -1,3 +1,31 @@
+2018-08-10  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/68210
+       * doc/xml/manual/intro.xml: Document LWG 206 change.
+       * libsupc++/del_op.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept.
+       * libsupc++/del_opa.cc: Likewise.
+       * libsupc++/del_opant.cc: Likewise.
+       * libsupc++/del_opnt.cc: Likewise. Call operator delete(ptr) instead
+       of free(ptr).
+       * libsupc++/del_ops.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept.
+       * libsupc++/del_opsa.cc: Likewise.
+       * libsupc++/del_opva.cc: Likewise.
+       * libsupc++/del_opvant.cc: Likewise.
+       * libsupc++/del_opvnt.cc: Likewise. Call operator delete[](ptr)
+       instead of operator delete(ptr).
+       * libsupc++/del_opvs.cc: Replace _GLIBCXX_USE_NOEXCEPT with noexcept.
+       * libsupc++/del_opvsa.cc: Likewise.
+       * libsupc++/new_op.cc: Use __builtin_expect in check for zero size.
+       * libsupc++/new_opa.cc: Use nullptr instead of literal 0.
+       * libsupc++/new_opant.cc: Likewise. Replace _GLIBCXX_USE_NOEXCEPT
+       with noexcept.
+       * libsupc++/new_opnt.cc: Likewise. Call operator new(sz) instead of
+       malloc(sz).
+       * libsupc++/new_opvant.cc: Use nullptr and noexcept.
+       * libsupc++/new_opvnt.cc: Likewise. Call operator new[](sz) instead of
+       operator new(sz, nothrow).
+       * testsuite/18_support/new_nothrow.cc: New test.
+
 2018-08-10  Martin Liska  <mliska@suse.cz>
 
        * libsupc++/new_op.cc (new): Remove __builtin_expect as malloc
index fea07e2bb5f80f6e2a8ee541d9e000fdb59d1ce6..cb187e1a2ed7733305069872aac70c2c383a5b7b 100644 (file)
@@ -440,6 +440,17 @@ requirements of the license of GCC.
     <listitem><para>Yes, it can, specifically if EOF is reached while skipping whitespace.
     </para></listitem></varlistentry>
 
+    <varlistentry xml:id="manual.bugs.dr206"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#206">206</link>:
+       <emphasis><code>operator new(size_t, nothrow)</code> may become
+          unlinked to ordinary <code>operator new</code> if ordinary
+          version replaced
+        </emphasis>
+    </term>
+    <listitem><para>The <code>nothrow</code> forms of new and delete were
+      changed to call the throwing forms, handling any exception by
+      catching it and returning a null pointer.
+    </para></listitem></varlistentry>
+
     <varlistentry xml:id="manual.bugs.dr211"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#211">211</link>:
        <emphasis>operator&gt;&gt;(istream&amp;, string&amp;) doesn't set failbit</emphasis>
     </term>
index 9a5cb82fdf0953aec6e7bc5350fc31257c74fd93..ab3b617afa7a5a822d52155d61b9199857c58911 100644 (file)
@@ -44,7 +44,7 @@ _GLIBCXX_END_NAMESPACE_VERSION
 #pragma GCC diagnostic ignored "-Wsized-deallocation"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete(void* ptr) _GLIBCXX_USE_NOEXCEPT
+operator delete(void* ptr) noexcept
 {
   std::free(ptr);
 }
index 71f384df661cd228dbb20176513d0680e95c88c0..2a1f0aba3a16134f5641c6b5d8100c8b8c0b5a9d 100644 (file)
@@ -44,7 +44,7 @@ _GLIBCXX_END_NAMESPACE_VERSION
 #pragma GCC diagnostic ignored "-Wsized-deallocation"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete(void* ptr, std::align_val_t) _GLIBCXX_USE_NOEXCEPT
+operator delete(void* ptr, std::align_val_t) noexcept
 {
 #if _GLIBCXX_HAVE_ALIGNED_ALLOC || _GLIBCXX_HAVE_POSIX_MEMALIGN \
     || _GLIBCXX_HAVE_MEMALIGN
index a4305a3146af0e1c77ae6f905470f306b2c2d6fa..603d9f2e9d29f0eb3b56cfe66586540c467d8d58 100644 (file)
@@ -27,7 +27,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete (void *ptr, std::align_val_t al, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
+operator delete (void *ptr, std::align_val_t al, const std::nothrow_t&) noexcept
 {
   ::operator delete (ptr, al);
 }
index 2bbcdc3dceb73eb7aa2aeec48ea7b3189d6fcf33..a2762659d9feaa366d3d9e182a792fc60129d11a 100644 (file)
@@ -41,7 +41,10 @@ _GLIBCXX_END_NAMESPACE_VERSION
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete (void *ptr, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
+operator delete (void *ptr, const std::nothrow_t&) noexcept
 {
-  std::free(ptr);
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 206. operator new(size_t, nothrow) may become unlinked to ordinary
+  // operator new if ordinary version replaced
+  ::operator delete (ptr);
 }
index 1fa24f22dc34169bab35252d1eef1ed02d0b1798..e452c7cf19eb85fcc81f5863fae7ac7b4d9b9190 100644 (file)
@@ -28,7 +28,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete(void* ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT
+operator delete(void* ptr, std::size_t) noexcept
 {
   ::operator delete (ptr);
 }
index 1984fce9c906c38f6769b080453216a9641b35f2..2cadb4b6ae428272213e9fdf39b9d1467a6cb5a0 100644 (file)
@@ -27,7 +27,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete(void* ptr, std::size_t, std::align_val_t al) _GLIBCXX_USE_NOEXCEPT
+operator delete(void* ptr, std::size_t, std::align_val_t al) noexcept
 {
   ::operator delete (ptr, al);
 }
index dc727b38c2433ead6020d432e8e23fbcf81edea5..a539ccc81878c090a4fc08512634e54d27d0fb40 100644 (file)
@@ -30,7 +30,7 @@
 #pragma GCC diagnostic ignored "-Wsized-deallocation"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete[] (void *ptr, std::align_val_t al) _GLIBCXX_USE_NOEXCEPT
+operator delete[] (void *ptr, std::align_val_t al) noexcept
 {
   ::operator delete (ptr, al);
 }
index 86406b253b1e6186aca578e9e73bbf5b76d29d2f..892c8b7999b3cd83590831df09a4e6c8cde8ad27 100644 (file)
@@ -27,7 +27,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete[] (void *ptr, std::align_val_t al, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
+operator delete[] (void *ptr, std::align_val_t al, const std::nothrow_t&) noexcept
 {
   ::operator delete[] (ptr, al);
 }
index ed06d2e82d50dee16be1105d93226b7b1c413823..f050526093b4174315d45cd1810599f31a0182ff 100644 (file)
@@ -27,7 +27,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete[] (void *ptr, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
+operator delete[] (void *ptr, const std::nothrow_t&) noexcept
 {
-  ::operator delete (ptr);
+  ::operator delete[] (ptr);
 }
index 2be94d6562c125cac471916955f41475175d62d7..4b1e161fb2574b2cba011c7979fd0ef9d2d170cf 100644 (file)
@@ -28,7 +28,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete[] (void *ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT
+operator delete[] (void *ptr, std::size_t) noexcept
 {
   ::operator delete[] (ptr);
 }
index 02f1845246247000183d1cba34950b8efff9b621..00ea369ee6909767eadd8502ee28c957aa1dbb27 100644 (file)
@@ -27,7 +27,7 @@
 #include "new"
 
 _GLIBCXX_WEAK_DEFINITION void
-operator delete[] (void *ptr, std::size_t, std::align_val_t al) _GLIBCXX_USE_NOEXCEPT
+operator delete[] (void *ptr, std::size_t, std::align_val_t al) noexcept
 {
   ::operator delete[] (ptr, al);
 }
index 3caa0bab2eaa094fe4df1d4391b1797012a45e78..df77950cd97d0151ee915a70ced4087fd6c14f5d 100644 (file)
@@ -44,7 +44,7 @@ operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
   void *p;
 
   /* malloc (0) is unpredictable; avoid it.  */
-  if (sz == 0)
+  if (__builtin_expect (sz == 0, false))
     sz = 1;
 
   while ((p = malloc (sz)) == 0)
index a27ff843ca1c21ad46d4ff8c281a4fa6763f85e9..aa3e5dc4ce5d6ed553e3e1ab4e0e60c972e63aa8 100644 (file)
@@ -101,7 +101,6 @@ aligned_alloc (std::size_t al, std::size_t sz)
 _GLIBCXX_WEAK_DEFINITION void *
 operator new (std::size_t sz, std::align_val_t al)
 {
-  void *p;
   std::size_t align = (std::size_t)al;
 
   /* Alignment must be a power of two.  */
@@ -125,8 +124,9 @@ operator new (std::size_t sz, std::align_val_t al)
     sz += align - rem;
 #endif
 
-  using __gnu_cxx::aligned_alloc;
-  while ((p = aligned_alloc (align, sz)) == 0)
+  void *p;
+
+  while ((p = __gnu_cxx::aligned_alloc (align, sz)) == nullptr)
     {
       new_handler handler = std::get_new_handler ();
       if (! handler)
index b4458402d028e7d48fb3ac1ca9ff5f9cd632b0c4..f08ae0c2ac480a6911e69570bd28b3648007b454 100644 (file)
@@ -29,7 +29,7 @@
 
 _GLIBCXX_WEAK_DEFINITION void*
 operator new(std::size_t sz, std::align_val_t al, const std::nothrow_t&)
-  _GLIBCXX_USE_NOEXCEPT
+  noexcept
 {
   __try
     {
@@ -37,6 +37,6 @@ operator new(std::size_t sz, std::align_val_t al, const std::nothrow_t&)
     }
   __catch(...)
     {
-      return 0;
+      return nullptr;
     }
 }
index faab44e66c27e7491756b876829024b799b44f79..ffe44b939bb5400af347e2938c27f6b5f7f52fb4 100644 (file)
@@ -32,28 +32,17 @@ using std::bad_alloc;
 extern "C" void *malloc (std::size_t);
 
 _GLIBCXX_WEAK_DEFINITION void *
-operator new (std::size_t sz, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
+operator new (std::size_t sz, const std::nothrow_t&) noexcept
 {
-  void *p;
-
-  /* malloc (0) is unpredictable; avoid it.  */
-  if (sz == 0)
-    sz = 1;
-
-  while ((p = malloc (sz)) == 0)
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 206. operator new(size_t, nothrow) may become unlinked to ordinary
+  // operator new if ordinary version replaced
+  __try
     {
-      new_handler handler = std::get_new_handler ();
-      if (! handler)
-       return 0;
-      __try
-       {
-         handler ();
-       }
-      __catch(const bad_alloc&)
-       {
-         return 0;
-       }
+      return ::operator new(sz);
+    }
+  __catch (...)
+    {
+      return nullptr;
     }
-
-  return p;
 }
index faeb4dc2cb2bdb5cf51bf59862b8c16fa938fb03..4ba1268fbe9ce799f040e30442952752f069aac1 100644 (file)
@@ -29,7 +29,7 @@
 
 _GLIBCXX_WEAK_DEFINITION void*
 operator new[] (std::size_t sz, std::align_val_t al, const std::nothrow_t&)
-  _GLIBCXX_USE_NOEXCEPT
+  noexcept
 {
   __try
     {
@@ -37,6 +37,6 @@ operator new[] (std::size_t sz, std::align_val_t al, const std::nothrow_t&)
     }
   __catch(...)
     {
-      return 0;
+      return nullptr;
     }
 }
index 828a971dafbf78fff4f770b976608cfe1602f7d8..3678b8e1ac9395e120142bc32fce17ac6ec9f869 100644 (file)
 #include "new"
  
 _GLIBCXX_WEAK_DEFINITION void*
-operator new[] (std::size_t sz, const std::nothrow_t& nothrow)
-  _GLIBCXX_USE_NOEXCEPT
+operator new[] (std::size_t sz, const std::nothrow_t&) noexcept
 {
-  return ::operator new(sz, nothrow);
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 206. operator new(size_t, nothrow) may become unlinked to ordinary
+  // operator new if ordinary version replaced
+  __try
+    {
+      return ::operator new[](sz);
+    }
+  __catch (...)
+    {
+      return nullptr;
+    }
 }
diff --git a/libstdc++-v3/testsuite/18_support/new_nothrow.cc b/libstdc++-v3/testsuite/18_support/new_nothrow.cc
new file mode 100644 (file)
index 0000000..362dabf
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+
+#include <new>
+#include <stdlib.h>
+#include <testsuite_hooks.h>
+
+// PR libstdc++/68210
+
+struct MyBadAlloc: std::bad_alloc { };
+
+static bool new_fail;
+static bool bad_alloc_thrown;
+static unsigned new_called;
+static unsigned delete_called;
+static unsigned new_vec_called;
+static unsigned delete_vec_called;
+static unsigned new_handler_called;
+
+static void new_handler ()
+{
+    if (new_handler_called++)
+        throw MyBadAlloc ();
+}
+
+void* operator new (size_t n)
+{
+    static size_t cntr;
+
+    ++new_called;
+
+    for ( ; ; ) {
+        if (void *p = new_fail ? 0 : malloc (n + sizeof n)) {
+            *static_cast<size_t*>(p) = ++cntr;
+            return static_cast<size_t*>(p) + 1;
+        }
+
+        if (std::new_handler h = std::set_new_handler (0)) {
+            std::set_new_handler (h);
+            h ();
+        }
+        else {
+            bad_alloc_thrown = true;
+            throw MyBadAlloc ();
+        }
+    }
+}
+
+void operator delete (void *p)
+{
+    ++delete_called;
+    if (p)
+        free (static_cast<size_t*>(p) - 1);
+}
+
+void* operator new[] (size_t n)
+{
+    ++new_vec_called;
+    return operator new(n);
+}
+
+void operator delete[] (void *p)
+{
+    ++delete_vec_called;
+    operator delete(p);
+}
+
+#if __cplusplus >= 201402L
+void operator delete (void *p, std::size_t)
+{
+  ::operator delete(p);
+}
+void operator delete[] (void *p, std::size_t)
+{
+  ::operator delete[](p);
+}
+#endif
+
+void init()
+{
+    new_fail = false;
+    new_called = 0;
+    delete_called = 0;
+    new_vec_called = 0;
+    delete_vec_called = 0;
+    new_handler_called = 0;
+    std::set_new_handler (0);
+}
+
+void
+test01()
+{
+    init ();
+
+    void *p = operator new (1, std::nothrow);
+
+    VERIFY (p != 0);
+    VERIFY (1 == new_called);
+    VERIFY (0 == new_handler_called);
+    VERIFY (!bad_alloc_thrown);
+
+    operator delete (p, std::nothrow);
+    VERIFY( 1 == delete_called );
+
+    new_fail = true;
+    p = operator new (1, std::nothrow);
+
+    VERIFY (0 == p);
+    VERIFY (2 == new_called);
+    VERIFY (0 == new_handler_called);
+    VERIFY (bad_alloc_thrown);
+
+    new_fail = true;
+    bad_alloc_thrown = false;
+    std::set_new_handler (new_handler);
+    p = operator new (1, std::nothrow);
+
+    VERIFY (0 == p);
+    VERIFY (3 == new_called);
+    VERIFY (2 == new_handler_called);
+    VERIFY (!bad_alloc_thrown);
+}
+
+void
+test02()
+{
+    init ();
+
+    void *p = operator new[] (1, std::nothrow);
+
+    VERIFY (p != 0);
+    VERIFY (1 == new_called);
+    VERIFY (1 == new_vec_called);
+    VERIFY (0 == new_handler_called);
+    VERIFY (!bad_alloc_thrown);
+
+    operator delete[] (p, std::nothrow);
+    VERIFY( 1 == delete_called );
+    VERIFY( 1 == delete_vec_called );
+
+    new_fail = true;
+    p = operator new[] (1, std::nothrow);
+
+    VERIFY (0 == p);
+    VERIFY (2 == new_called);
+    VERIFY (2 == new_vec_called);
+    VERIFY (0 == new_handler_called);
+    VERIFY (bad_alloc_thrown);
+
+    new_fail = true;
+    bad_alloc_thrown = false;
+    std::set_new_handler (new_handler);
+    p = operator new[] (1, std::nothrow);
+
+    VERIFY (0 == p);
+    VERIFY (3 == new_called);
+    VERIFY (3 == new_vec_called);
+    VERIFY (2 == new_handler_called);
+    VERIFY (!bad_alloc_thrown);
+}
+
+
+int main()
+{
+  test01();
+  test02();
+}