]> granicus.if.org Git - gc/commitdiff
Never return null pointer by C++ operator new (gc_cpp)
authorIvan Maidanski <ivmai@mail.ru>
Fri, 1 Jun 2018 08:29:41 +0000 (11:29 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Fri, 1 Jun 2018 08:40:54 +0000 (11:40 +0300)
Now, in case of the allocation failure, new and new[] operators throw
bad_alloc (or abort the application if an ancient compiler is used).

* gc_cpp.cc (GC_NEW_DELETE_NEED_THROW): Remove.
* gc_cpp.cc (GC_DECL_NEW_THROW, GC_DECL_DELETE_THROW): Move macro
definition to gc_cpp.h.
* gc_cpp.cc [GC_NEW_DELETE_NEED_THROW]: Do not include "new" header.
* gc_cpp.cc [!_MSC_VER] (operator new): Call GC_OP_NEW_OOM_CHECK() for
the allocation result.
* gc_cpp.cc [!_MSC_VER && GC_OPERATOR_NEW_ARRAY && !CPPCHECK]
(operator new[]): Likewise.
* include/gc.h (GC_abort_on_oom): Declare new API function.
* include/gc_cpp.h [!GC_NEW_DELETE_THROW_NOT_NEEDED
&& (GC_GNUC_PREREQ(4,2) || __BORLANDC__>=0x0550 || _MSC_VER>1020
|| __WATCOMC__>=1050)] (GC_NEW_DELETE_NEED_THROW):
Define macro.
* include/gc_cpp.h [GC_NEW_DELETE_NEED_THROW]: Include "new" header.
* include/gc_cpp.h (GC_OP_NEW_OOM_CHECK): New internal macro (throws
bad_alloc or cals GC_abort_on_oom).
* include/gc_cpp.h (gc::new(size_t), gc::new(size_t,GCPlacement), new):
Add GC_DECL_NEW_THROW; call GC_OP_NEW_OOM_CHECK() for the allocation
result.
* include/gc_cpp.h [GC_OPERATOR_NEW_ARRAY] (gc::new[](size_t),
gc::new[](size_t,GCPlacement, new[]): Likewise.
* misc.c (GC_abort_on_oom): Implement function.
* tests/test.c [CPPCHECK] (main): Call UNTESTED(GC_abort_on_oom).

gc_cpp.cc
include/gc.h
include/gc_cpp.h
misc.c
tests/test.c

index 80a9708ac01fab1b50d3fc4525b5a4faf6327817..73f54cfd611dcb100930788391bf8ff28caf5186 100644 (file)
--- a/gc_cpp.cc
+++ b/gc_cpp.cc
@@ -29,23 +29,12 @@ built-in "new" and "delete".
 
 #include "gc_cpp.h"
 
-#if GC_GNUC_PREREQ(4, 2) && !defined(GC_NEW_DELETE_NEED_THROW)
-# define GC_NEW_DELETE_NEED_THROW
-#endif
-
-#ifdef GC_NEW_DELETE_NEED_THROW
-# include <new> /* for std::bad_alloc */
-# define GC_DECL_NEW_THROW throw(std::bad_alloc)
-# define GC_DECL_DELETE_THROW throw()
-#else
-# define GC_DECL_NEW_THROW /* empty */
-# define GC_DECL_DELETE_THROW /* empty */
-#endif // !GC_NEW_DELETE_NEED_THROW
-
 #ifndef _MSC_VER
 
   void* operator new(size_t size) GC_DECL_NEW_THROW {
-    return GC_MALLOC_UNCOLLECTABLE(size);
+    void* obj = GC_MALLOC_UNCOLLECTABLE(size);
+    GC_OP_NEW_OOM_CHECK(obj);
+    return obj;
   }
 
   void operator delete(void* obj) GC_DECL_DELETE_THROW {
@@ -54,7 +43,9 @@ built-in "new" and "delete".
 
 # if defined(GC_OPERATOR_NEW_ARRAY) && !defined(CPPCHECK)
     void* operator new[](size_t size) GC_DECL_NEW_THROW {
-      return GC_MALLOC_UNCOLLECTABLE(size);
+      void* obj = GC_MALLOC_UNCOLLECTABLE(size);
+      GC_OP_NEW_OOM_CHECK(obj);
+      return obj;
     }
 
     void operator delete[](void* obj) GC_DECL_DELETE_THROW {
index ff051284348fa9700c0e803a3afe910ababef1c7..0f5d8435569e0c0a2bb2563aae2963a447cd184e 100644 (file)
@@ -1343,6 +1343,9 @@ typedef void (GC_CALLBACK * GC_abort_func)(const char * /* msg */);
 GC_API void GC_CALL GC_set_abort_func(GC_abort_func) GC_ATTR_NONNULL(1);
 GC_API GC_abort_func GC_CALL GC_get_abort_func(void);
 
+/* A portable way to abort the application because of not enough memory.*/
+GC_API void GC_CALL GC_abort_on_oom(void);
+
 /* The following is intended to be used by a higher level       */
 /* (e.g. Java-like) finalization facility.  It is expected      */
 /* that finalization code will arrange for hidden pointers to   */
index 875c64e29214f02cc14c2090f5b5f3363cd063ef..091e709b3ae10987fbc288630ef50b70f11964ee 100644 (file)
@@ -173,6 +173,26 @@ by UseGC.  GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
 # define GC_PLACEMENT_DELETE
 #endif
 
+#if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \
+    && !defined(GC_NEW_DELETE_NEED_THROW) \
+    && (GC_GNUC_PREREQ(4, 2) || __BORLANDC__ >= 0x0550 \
+        || _MSC_VER > 1020 || __WATCOMC__ >= 1050)
+# define GC_NEW_DELETE_NEED_THROW
+#endif
+
+#ifdef GC_NEW_DELETE_NEED_THROW
+# include <new> /* for std::bad_alloc */
+# define GC_DECL_NEW_THROW throw(std::bad_alloc)
+# define GC_DECL_DELETE_THROW throw()
+# define GC_OP_NEW_OOM_CHECK(obj) \
+                do { if (!(obj)) throw std::bad_alloc(); } while (0)
+#else
+# define GC_DECL_NEW_THROW /* empty */
+# define GC_DECL_DELETE_THROW /* empty */
+# define GC_OP_NEW_OOM_CHECK(obj) \
+                do { if (!(obj)) GC_abort_on_oom(); } while (0)
+#endif // !GC_NEW_DELETE_NEED_THROW
+
 #ifdef GC_NAMESPACE
 namespace boehmgc
 {
@@ -198,8 +218,8 @@ enum GCPlacement
 class gc
 {
 public:
-  inline void* operator new(size_t size);
-  inline void* operator new(size_t size, GCPlacement gcp);
+  inline void* operator new(size_t size) GC_DECL_NEW_THROW;
+  inline void* operator new(size_t size, GCPlacement gcp) GC_DECL_NEW_THROW;
   inline void* operator new(size_t size, void* p);
     // Must be redefined here, since the other overloadings hide
     // the global definition.
@@ -212,8 +232,9 @@ public:
 # endif // GC_PLACEMENT_DELETE
 
 # ifdef GC_OPERATOR_NEW_ARRAY
-    inline void* operator new[](size_t size);
-    inline void* operator new[](size_t size, GCPlacement gcp);
+    inline void* operator new[](size_t size) GC_DECL_NEW_THROW;
+    inline void* operator new[](size_t size, GCPlacement gcp)
+                                                        GC_DECL_NEW_THROW;
     inline void* operator new[](size_t size, void* p);
     inline void operator delete[](void* obj);
 #   ifdef GC_PLACEMENT_DELETE
@@ -255,7 +276,7 @@ extern "C" {
 
 inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
                           GC_NS_QUALIFY(GCCleanUpFunc) /* cleanup */ = 0,
-                          void* /* clientData */ = 0);
+                          void* /* clientData */ = 0) GC_DECL_NEW_THROW;
     // Allocates a collectible or uncollectible object, according to the
     // value of "gcp".
     //
@@ -284,9 +305,11 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
   // to arbitrary ordering during linking).
 
 # if _MSC_VER > 1020
-    inline void* operator new[](size_t size)
+    inline void* operator new[](size_t size) GC_DECL_NEW_THROW
     {
-      return GC_MALLOC_UNCOLLECTABLE(size);
+      void* obj = GC_MALLOC_UNCOLLECTABLE(size);
+      GC_OP_NEW_OOM_CHECK(obj);
+      return obj;
     }
 
     inline void operator delete[](void* obj)
@@ -295,9 +318,11 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
     }
 # endif
 
-  inline void* operator new(size_t size)
+  inline void* operator new(size_t size) GC_DECL_NEW_THROW
   {
-    return GC_MALLOC_UNCOLLECTABLE(size);
+    void* obj = GC_MALLOC_UNCOLLECTABLE(size);
+    GC_OP_NEW_OOM_CHECK(obj);
+    return obj;
   }
 
   inline void operator delete(void* obj)
@@ -309,14 +334,20 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
 # ifdef GC_DEBUG
     inline void* operator new(size_t size, int /* nBlockUse */,
                               const char* szFileName, int nLine)
+                                                        GC_DECL_NEW_THROW
     {
-      return GC_debug_malloc_uncollectable(size, szFileName, nLine);
+      void* obj = GC_debug_malloc_uncollectable(size, szFileName, nLine);
+      GC_OP_NEW_OOM_CHECK(obj);
+      return obj;
     }
 # else
     inline void* operator new(size_t size, int /* nBlockUse */,
                               const char* /* szFileName */, int /* nLine */)
+                                                        GC_DECL_NEW_THROW
     {
-      return GC_malloc_uncollectable(size);
+      void* obj = GC_malloc_uncollectable(size);
+      GC_OP_NEW_OOM_CHECK(obj);
+      return obj;
     }
 # endif /* !GC_DEBUG */
 
@@ -324,6 +355,7 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
     // This new operator is used by VC++ 7+ in Debug builds:
     inline void* operator new[](size_t size, int nBlockUse,
                                 const char* szFileName, int nLine)
+                                                        GC_DECL_NEW_THROW
     {
       return operator new(size, nBlockUse, szFileName, nLine);
     }
@@ -335,7 +367,7 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
   // The operator new for arrays, identical to the above.
   inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
                               GC_NS_QUALIFY(GCCleanUpFunc) /* cleanup */ = 0,
-                              void* /* clientData */ = 0);
+                              void* /* clientData */ = 0) GC_DECL_NEW_THROW;
 #endif // GC_OPERATOR_NEW_ARRAY
 
 /* Inline implementation */
@@ -345,26 +377,34 @@ namespace boehmgc
 {
 #endif
 
-inline void* gc::operator new(size_t size)
+inline void* gc::operator new(size_t size) GC_DECL_NEW_THROW
 {
-  return GC_MALLOC(size);
+  void* obj = GC_MALLOC(size);
+  GC_OP_NEW_OOM_CHECK(obj);
+  return obj;
 }
 
-inline void* gc::operator new(size_t size, GCPlacement gcp)
+inline void* gc::operator new(size_t size, GCPlacement gcp) GC_DECL_NEW_THROW
 {
+  void* obj;
   switch (gcp) {
   case UseGC:
-    return GC_MALLOC(size);
+    obj = GC_MALLOC(size);
+    break;
   case PointerFreeGC:
-    return GC_MALLOC_ATOMIC(size);
+    obj = GC_MALLOC_ATOMIC(size);
+    break;
 # ifdef GC_ATOMIC_UNCOLLECTABLE
     case PointerFreeNoGC:
-      return GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
+      obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
+      break;
 # endif
   case NoGC:
   default:
-    return GC_MALLOC_UNCOLLECTABLE(size);
+    obj = GC_MALLOC_UNCOLLECTABLE(size);
   }
+  GC_OP_NEW_OOM_CHECK(obj);
+  return obj;
 }
 
 inline void* gc::operator new(size_t /* size */, void* p)
@@ -387,12 +427,13 @@ inline void gc::operator delete(void* obj)
 #endif // GC_PLACEMENT_DELETE
 
 #ifdef GC_OPERATOR_NEW_ARRAY
-  inline void* gc::operator new[](size_t size)
+  inline void* gc::operator new[](size_t size) GC_DECL_NEW_THROW
   {
     return gc::operator new(size);
   }
 
   inline void* gc::operator new[](size_t size, GCPlacement gcp)
+                                                        GC_DECL_NEW_THROW
   {
     return gc::operator new(size, gcp);
   }
@@ -452,26 +493,30 @@ inline gc_cleanup::gc_cleanup()
 
 inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
                           GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
-                          void* clientData)
+                          void* clientData) GC_DECL_NEW_THROW
 {
   void* obj;
   switch (gcp) {
   case GC_NS_QUALIFY(UseGC):
     obj = GC_MALLOC(size);
-    if (cleanup != 0) {
+    if (cleanup != 0 && obj != 0) {
       GC_REGISTER_FINALIZER_IGNORE_SELF(obj, cleanup, clientData, 0, 0);
     }
-    return obj;
+    break;
   case GC_NS_QUALIFY(PointerFreeGC):
-    return GC_MALLOC_ATOMIC(size);
+    obj = GC_MALLOC_ATOMIC(size);
+    break;
 # ifdef GC_ATOMIC_UNCOLLECTABLE
     case GC_NS_QUALIFY(PointerFreeNoGC):
-      return GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
+      obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
+      break;
 # endif
   case GC_NS_QUALIFY(NoGC):
   default:
-    return GC_MALLOC_UNCOLLECTABLE(size);
+    obj = GC_MALLOC_UNCOLLECTABLE(size);
   }
+  GC_OP_NEW_OOM_CHECK(obj);
+  return obj;
 }
 
 #ifdef GC_PLACEMENT_DELETE
@@ -486,7 +531,7 @@ inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
 #ifdef GC_OPERATOR_NEW_ARRAY
   inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
                               GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
-                              void* clientData)
+                              void* clientData) GC_DECL_NEW_THROW
   {
     return ::operator new(size, gcp, cleanup, clientData);
   }
diff --git a/misc.c b/misc.c
index 7d0f466d118827fa02622f36ac6796a1e7c66a67..c91c788afd47717172fc0291200d4c487bc7288f 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -2516,3 +2516,9 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void)
 {
     return (int)GC_force_unmap_on_gcollect;
 }
+
+GC_API void GC_CALL GC_abort_on_oom(void)
+{
+    GC_err_printf("Insufficient memory for the allocation\n");
+    EXIT();
+}
index 4700a8c708eb57b239e616041e3d1b943389ed75..69fd7bdd37db89c5574f9cdacdb8bd707ebff6da 100644 (file)
@@ -1882,6 +1882,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p)
          UNTESTED(GetModuleNameFromStack);
          UNTESTED(GetSymbolNameFromStack);
 #      endif
+       UNTESTED(GC_abort_on_oom);
        UNTESTED(GC_get_bytes_since_gc);
        UNTESTED(GC_get_dont_expand);
        UNTESTED(GC_get_dont_precollect);