Never return null pointer by C++ operator new (gc_cpp)

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).
This commit is contained in:
Ivan Maidanski
2018-06-01 11:29:41 +03:00
parent b6afec3039
commit cb1194d17e
5 changed files with 88 additions and 42 deletions
+6 -15
View File
@@ -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 {
+3
View 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 */
+72 -27
View 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);
}
+6
View File
@@ -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();
}
+1
View 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);