# define GC_BUILD
#endif
-#include "gc_cpp.h"
+#include "gc.h"
-#if !defined(GC_NEW_DELETE_NEED_THROW) && defined(__GNUC__) \
- && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
-# define GC_NEW_DELETE_NEED_THROW
-#endif
+#include <new> // for bad_alloc, precedes include of gc_cpp.h
+
+#include "gc_cpp.h" // for GC_OPERATOR_NEW_ARRAY, GC_DECL_DELETE_THROW
-#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()
+#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
+# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
#else
-# define GC_DECL_NEW_THROW /* empty */
-# define GC_DECL_DELETE_THROW /* empty */
-#endif // !GC_NEW_DELETE_NEED_THROW
+# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
+#endif
+
+GC_API void GC_CALL GC_throw_bad_alloc() {
+ GC_ALLOCATOR_THROW_OR_ABORT();
+}
#ifndef _MSC_VER
+# if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \
+ && !defined(GC_NEW_DELETE_NEED_THROW) \
+ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) \
+ && (__cplusplus < 201103L || defined(__clang__))
+# define GC_NEW_DELETE_NEED_THROW
+# endif
+
+# ifdef GC_NEW_DELETE_NEED_THROW
+# define GC_DECL_NEW_THROW throw(std::bad_alloc)
+# else
+# define GC_DECL_NEW_THROW /* empty */
+# endif
+
void* operator new(size_t size) GC_DECL_NEW_THROW {
- return GC_MALLOC_UNCOLLECTABLE(size);
+ void* obj = GC_MALLOC_UNCOLLECTABLE(size);
+ if (0 == obj)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return obj;
}
void operator delete(void* obj) GC_DECL_DELETE_THROW {
# 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);
+ if (0 == obj)
+ GC_ALLOCATOR_THROW_OR_ABORT();
+ return obj;
}
void operator delete[](void* obj) GC_DECL_DELETE_THROW {
# define GC_PLACEMENT_DELETE
#endif
+#ifndef GC_DECL_DELETE_THROW
+# if defined(__DMC__) || (defined(__BORLANDC__) \
+ && (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
+ || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
+ || (defined(__WATCOMC__) && !defined(_CPPUNWIND))
+# define GC_DECL_DELETE_THROW /* empty */
+# ifndef GC_NEW_ABORTS_ON_OOM
+# define GC_NEW_ABORTS_ON_OOM
+# endif
+# else
+# define GC_DECL_DELETE_THROW throw()
+# endif
+#endif // !GC_DECL_DELETE_THROW
+
+#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
+# define GC_OP_NEW_OOM_CHECK(obj) \
+ do { if (!(obj)) GC_abort_on_oom(); } while (0)
+#elif defined(GC_INCLUDE_NEW)
+# include <new> // for bad_alloc
+# define GC_OP_NEW_OOM_CHECK(obj) if (obj) {} else throw std::bad_alloc()
+#else
+ // "new" header is not included, so bad_alloc cannot be thrown directly.
+ GC_API void GC_CALL GC_throw_bad_alloc();
+# define GC_OP_NEW_OOM_CHECK(obj) if (obj) {} else GC_throw_bad_alloc()
+#endif // !GC_NEW_ABORTS_ON_OOM && !GC_INCLUDE_NEW
+
#ifdef GC_NAMESPACE
namespace boehmgc
{
# if _MSC_VER > 1020
inline void* operator new[](size_t size)
{
- 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)
inline void* operator new(size_t size)
{
- 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)
inline void* operator new(size_t size, int /* nBlockUse */,
const char* szFileName, int nLine)
{
- 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 */)
{
- return GC_malloc_uncollectable(size);
+ void* obj = GC_malloc_uncollectable(size);
+ GC_OP_NEW_OOM_CHECK(obj);
+ return obj;
}
# endif /* !GC_DEBUG */
inline void* gc::operator new(size_t size)
{
- 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)
{
+ 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)
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