[Gc] Patch that adds throw of std::bad_alloc for GC'd operator new.

Talbot, George Gtalbot at locuspharma.com
Thu May 28 12:18:36 PDT 2009


Hi,

For my C++ app, I needed to be able to detect out of memory in a way that follows the standard somewhat, in that operator new should throw std::bad_alloc if it fails.  This patch accomplishes this by adding "throw (std::bad_alloc)" to the existing declarations of operator new, and declaring a second version that takes const nothrow_t as a parameter and catches the exception if allocation fails (and returns zero in that case).

To enable the throwing behavior, I added a class at the top of the file, gc_cpp_init, that initializes the GC and installs an out-of-memory handler that calls the existing C++ new handler, if installed, or throws std::bad_alloc().

Also adds placement options for ignore-off-page, which I needed when allocating some large I/O caches in my app.

Let me know if this works for you.

Tested on Linux x86_64, gcc 4.1.3

--
George T. Talbot
<gtalbot at locuspharma.com>


gtalbot at germanium:~/work/current/lcfs/gc-cvs/bdwgc$ cvs diff include/gc_cpp.h
Index: include/gc_cpp.h
===================================================================
RCS file: /cvsroot/bdwgc/bdwgc/include/gc_cpp.h,v
retrieving revision 1.6
diff -r1.6 gc_cpp.h
18a19
>     throwing and non-throwing gc::operator new: George T. Talbot
141a143,144
> #include <stdexcept>
> #include <new>
172c175,221
<                   NoGC, PointerFreeGC};
---
>                   NoGC, PointerFreeGC, GCIgnoreOffPage,
>                   PointerFreeGCIgnoreOffPage};
>
> /** For C++, this object should be used to initialize GC and set up
>  *  the appropriate OOM handler.  It is designed to be a global variable,
>  *  and the construction parameter is designed to get it to run when other
>  *  explicity-instantiated global variables are instantiated.
>  */
> struct gc_cpp_init
> {
>     explicit gc_cpp_init(int unused)
>         : prev_oom(GC_oom_fn)
>     {
>         GC_INIT();
>         GC_oom_fn   = cpp_oom_fn;
>     }
>
>     ~gc_cpp_init()
>     {
>         GC_oom_fn   = prev_oom;
>     }
>
> private:
>     gc_cpp_init(const gc_cpp_init&);
>     gc_cpp_init&    operator=(const gc_cpp_init&);
>
>     static void dummy() { }
>
>     static void*    cpp_oom_fn(size_t)
>     {
>         std::new_handler cur = std::set_new_handler(dummy);
>         std::set_new_handler(cur);
>
>         if (cur)
>         {
>             cur();
>         }
>         else
>         {
>             throw std::bad_alloc();
>         }
>
>         return 0;
>     }
>
>     void*   (*prev_oom) (size_t);
> };
175,176c224,227
<     inline void* operator new( size_t size );
<     inline void* operator new( size_t size, GCPlacement gcp );
---
>     inline void* operator new( size_t size ) throw (std::bad_alloc);
>     inline void* operator new( size_t size, GCPlacement gcp ) throw (std::bad_alloc);
>     inline void* operator new( size_t size, const std::nothrow_t& ) throw();
>     inline void* operator new( size_t size, GCPlacement gcp, const std::nothrow_t& ) throw();
188,189c239,244
<     inline void* operator new[]( size_t size );
<     inline void* operator new[]( size_t size, GCPlacement gcp );
---
>     inline void* operator new[]( size_t size ) throw (std::bad_alloc);
>     inline void* operator new[]( size_t size, GCPlacement gcp ) throw (std::bad_alloc);
>
>     inline void* operator new[]( size_t size, const std::nothrow_t& ) throw();
>     inline void* operator new[]( size_t size, GCPlacement gcp, const std::nothrow_t& ) throw();
>
229c284,292
<     void* clientData = 0 );
---
>     void* clientData = 0 ) throw (std::bad_alloc);
>
> inline void* operator new(
>     size_t size,
>     GCPlacement gcp,
>     const std::nothrow_t& x,
>     GCCleanUpFunc cleanup = 0,
>     void* clientData = 0 ) throw ();
>
256c319,320
<  void *operator new[]( size_t size );
---
>  void *operator new[]( size_t size ) throw (std::bad_alloc);
>  void *operator new[]( size_t size, const std::nothrow_t& ) throw();
279c343,349
<     void* clientData = 0 );
---
>     void* clientData = 0 ) throw (std::bad_alloc);
> inline void* operator new[](
>     size_t size,
>     GCPlacement gcp,
>     const std::nothrow_t&,
>     GCCleanUpFunc cleanup = 0,
>     void* clientData = 0 ) throw ();
291,292c361,412
< inline void* gc::operator new( size_t size ) {
<     return GC_MALLOC( size );}
---
> inline void* gc::operator new( size_t size ) throw (std::bad_alloc)
> {
>     return GC_MALLOC( size );
> }
>
> inline void* gc::operator new( size_t size, const std::nothrow_t& ) throw()
> {
>     try
>     {
>         return GC_MALLOC(size);
>     }
>     catch (std::bad_alloc)
>     {
>         return 0;
>     }
> }
>
> /* I found this useful, YMMV. -GTT */
> #ifdef GC_OVERRIDE_OPERATOR_NEW
> inline void*    operator new(size_t size) throw (std::bad_alloc)
> {
>     return GC_MALLOC(size);
> }
>
> inline void*    operator new(size_t size, const std::nothrow_t& x) throw()
> {
>     try
>     {
>         return GC_MALLOC(size);
>     }
>     catch (std::bad_alloc)
>     {
>         return 0;
>     }
> }
>
> inline void     operator delete(void* p) throw()
> {
>     GC_FREE(p);
> }
> #endif
>
> inline void* gc::operator new( size_t size, GCPlacement gcp ) throw (std::bad_alloc)
> {
>     switch (gcp)
>     {
>         case UseGC:                         return GC_MALLOC( size );                           break;
>         case PointerFreeGC:                 return GC_MALLOC_ATOMIC( size );                    break;
>         case GCIgnoreOffPage:               return GC_MALLOC_IGNORE_OFF_PAGE( size );           break;
>         case PointerFreeGCIgnoreOffPage:    return GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE( size );    break;
>         case NoGC:                          return GC_MALLOC_UNCOLLECTABLE( size );             break;
>     }
294,300c414,428
< inline void* gc::operator new( size_t size, GCPlacement gcp ) {
<     if (gcp == UseGC)
<         return GC_MALLOC( size );
<     else if (gcp == PointerFreeGC)
<       return GC_MALLOC_ATOMIC( size );
<     else
<         return GC_MALLOC_UNCOLLECTABLE( size );}
---
>     throw std::bad_alloc();
> }
>
> inline void* gc::operator new( size_t size, GCPlacement gcp, const std::nothrow_t& ) throw ()
> {
>     try
>     {
>         return gc::operator new(size, gcp);
>     }
>     catch (std::bad_alloc)
>     {
>         return 0;
>     }
> }
>
318c446
< inline void* gc::operator new[]( size_t size ) {
---
> inline void* gc::operator new[]( size_t size ) throw (std::bad_alloc) {
321c449,463
< inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
---
> inline void* gc::operator new[]( size_t size, const std::nothrow_t& x ) throw() {
>     return gc::operator new( size, x );}
>
> #   ifdef GC_OVERRIDE_OPERATOR_NEW
> inline void* operator new[]( size_t size ) throw (std::bad_alloc) {
>     return gc::operator new[]( size );}
>
> inline void* operator new[]( size_t size, const std::nothrow_t& x ) throw() {
>     return gc::operator new[]( size, x );}
>
> inline void operator delete[](void* p) throw() {
>     gc::operator delete(p);}
> #   endif
>
> inline void* gc::operator new[]( size_t size, GCPlacement gcp ) throw (std::bad_alloc) {
323a466,468
> inline void* gc::operator new[]( size_t size, GCPlacement gcp, const std::nothrow_t& x ) throw () {
>     return gc::operator new( size, gcp, x );}
>
363c508
<     void* clientData )
---
>     void* clientData ) throw (std::bad_alloc)
365c510,524
<     void* obj;
---
>     void* rv = 0;
>
>     switch (gcp)
>     {
>         case UseGC:                         rv = GC_MALLOC( size );                         break;
>         case PointerFreeGC:                 rv = GC_MALLOC_ATOMIC( size );                  break;
>         case GCIgnoreOffPage:               rv = GC_MALLOC_IGNORE_OFF_PAGE( size );         break;
>         case PointerFreeGCIgnoreOffPage:    rv = GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE( size );  break;
>         case NoGC:                          rv = GC_MALLOC_UNCOLLECTABLE( size );           break;
>         default:                            throw std::bad_alloc();
>     }
>
>     if (cleanup != 0)
>         GC_REGISTER_FINALIZER_IGNORE_SELF(
>             rv, cleanup, clientData, 0, 0 );
367,376c526,527
<     if (gcp == UseGC) {
<         obj = GC_MALLOC( size );
<         if (cleanup != 0)
<             GC_REGISTER_FINALIZER_IGNORE_SELF(
<                 obj, cleanup, clientData, 0, 0 );}
<     else if (gcp == PointerFreeGC) {
<         obj = GC_MALLOC_ATOMIC( size );}
<     else {
<         obj = GC_MALLOC_UNCOLLECTABLE( size );};
<     return obj;}
---
>     return rv;
> }
377a529,545
> inline void* operator new(
>     size_t size,
>     GCPlacement gcp,
>     const std::nothrow_t&,
>     GCCleanUpFunc cleanup,
>     void* clientData ) throw ()
> {
>     try
>     {
>         return operator new(size, gcp, cleanup, clientData);
>     }
>     catch (std::bad_alloc)
>     {
>         return 0;
>     }
> }
>
395c563
<     void* clientData )
---
>     void* clientData ) throw (std::bad_alloc)
398a567,575
> inline void* operator new[](
>     size_t size,
>     GCPlacement gcp,
>     GCCleanUpFunc cleanup,
>     void* clientData,
>     const std::nothrow_t& x ) throw ()
> {
>     return ::operator new( size, gcp, x, cleanup, clientData );}
>



More information about the Gc mailing list