mirror of
https://github.com/encounter/bdwgc.git
synced 2026-03-30 10:57:55 -07:00
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:
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user