10

I'm working on a performance-critical dynamically-linked library (DLL) that should also have a relatively small binary size. Since it doesn't explicitly throw any exceptions, I'd like to disable exception support altogether. However, there's one exception (pun unintended): when running out of memory (OOM), I have to report an error code to the application so it has a chance to handle things gracefully. The code base is too large to check every allocation individually and propagate the error, and contains external code that I shouldn't touch. So I'd like to catch OOM exceptions in my DLL's exported functions.

A quick test shows that when disabling C++ exceptions in Visual C++ 2010 (i.e. no /EHa, /EHsc or /EHs flags), it still jumps to a catch(std::bad_alloc&) block when allocating too much memory.

So it seems to work as desired. However, I get the following level 1 warning: "C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc". MSDN says that "an object with automatic storage in the frame, between the function doing the throw and the function catching the throw, will not be destroyed".

Exactly what would I lose here? It's fine to leave things in an undefined state, as long as anything that was created through the library can be deleted, and the application can start over again (if it so chooses). Is there a big risk of leaking memory that cannot be recovered?

Do DLLs use a separate memory pool? And if so, can I purge it without requiring the application to unload the DLL? I can easily make my library ignore any further (exported) function calls until the application performs a reinitialization.

Thanks for your advice.

Nicolas Capens
  • 832
  • 6
  • 12
  • *Do DLLs use a separate memory pool?* http://stackoverflow.com/questions/10820114/do-statically-linked-dlls-use-a-different-heap-than-the-main-program – thang Feb 06 '13 at 17:17
  • *And if so, can I purge it without requiring the application to unload the DLL?* yeah, just delete the stuff from new and free the stuff from malloc. – thang Feb 06 '13 at 17:17
  • 1
    Not having exception handling means that objects created on the stack (and inside a constructor that fails) will not be destroyed. If you are just going to exit when the `bad_alloc` happens, then you are fine with that, I suppose [as long a you don't have strange resources that don't get cleaned up with program exit - but most should]. If you are wanting to "continue" after `bad_alloc`, then the code will need to track objects and destroy all objects created in stack frames between the `throw` and `catch`. You can experiement by writing some small code that has printouts in destructors. – Mats Petersson Feb 06 '13 at 17:19
  • @thang I meant get it deleted automatically. I use multiple third-party components, any of which may throw an OOM exception, so it would be nice to be able to deallocate any memory ever allocated from within my DLL (and kill any threads / close any file handles while we're at it). Statically linking the C runtime would increase binary size which is also not desirable. – Nicolas Capens Feb 07 '13 at 21:24

1 Answers1

1

A few preliminaries:

I don't know if throwing an exception without exception handling enabled is undefined behavior or not by the standard, but you are certainly not going to get stack unwinding/destructor calls from your objects on the stack.

If you are writing C++ style code using RAII for mutexes, files, memory, etc, this is a Very Bad Thing.

Moving on then, and assuming your code is essentially C-style code:

1) If you are statically linking to the C runtime library, your DLL will not share a heap with your main application. Unloading the DLL should release the leaked memory -- but again, have a care about other resources.

2) If you are dynamically linking to the C runtime (quite common), then you are sharing a heap. You will have to have a way to manually release any memory allocated from the DLL.

Having myself mucked around far too much with DLL boundary issues, I would recommend a quick benchmarking to see what you're paying for in terms of leaving exceptions enabled. Depending on your platform and compiler, unthrown exceptions can have a quite negligible performance impact.

Stephen
  • 166
  • 2
  • 5
  • It's not C-style code, and a significant portion of it is not under my control. While I do trust this third-party code under normal operation, when an OOM exception is thrown I don't think I can make any assumptions, regardless of whether exception handling is enabled. "_You will have to have a way to manually release any memory allocated from the DLL._" That is precisely what my question is about. :-) – Nicolas Capens Feb 07 '13 at 21:37
  • Sorry, but I think then that there really isn't any way to do what you want. To achieve the "manual release from the DLL" in my own plugin type systems, I require all client code to allocate using a custom allocation routine that my core supplies to the DLL. This association allows the core to drop a DLL much like you want. But if you can't enforce this yourself, then I don't think it can be done. – Stephen Feb 12 '13 at 23:22