Question for C++ experts about exception allocation failure

How is failure to allocate an exception object handled in various compilers? 15.1.4 says that "the memory for the temporary copy of the exception being thrown is allocated in an unspecified way" but I don't think it specifies behavior for the case when the allocation fails. I know that some compilers allocate exceptions from the heap, so does this mean that an attempt to throw any exception could, in theory, result in a std::bad_alloc being thrown instead? As far as I can tell such behavior wouldn't violate the C++ standard, but I'm not sure my interpretation is correct. Anyone? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
How is failure to allocate an exception object handled in various compilers? 15.1.4 says that "the memory for the temporary copy of the exception being thrown is allocated in an unspecified way" but I don't think it specifies behavior for the case when the allocation fails. I know that some compilers allocate exceptions from the heap, so does this mean that an attempt to throw any exception could, in theory, result in a std::bad_alloc being thrown instead? As far as I can tell such behavior wouldn't violate the C++ standard, but I'm not sure my interpretation is correct. Anyone?
Stroustrup, The C++ Programming Language, Special Edition, page 371: "Throwing an exception requires an object to throw. A C++ implementation is required to have enough spare memory to be able to throw bad_alloc in case of memory exhaustion. However, it is possible that throwing some other exception will cause memory exhaustion." That seems to imply that in case of allocation failure when allocating an exception, bad_alloc is thrown instead, although he stops short of saying precisely that. --Jeffrey Bosboom

On Sat, May 16, 2009 at 7:36 PM, Jeffrey Bosboom <jbosboom@uci.edu> wrote:
Emil Dotchevski wrote:
How is failure to allocate an exception object handled in various compilers? 15.1.4 says that "the memory for the temporary copy of the exception being thrown is allocated in an unspecified way" but I don't think it specifies behavior for the case when the allocation fails. I know that some compilers allocate exceptions from the heap, so does this mean that an attempt to throw any exception could, in theory, result in a std::bad_alloc being thrown instead? As far as I can tell such behavior wouldn't violate the C++ standard, but I'm not sure my interpretation is correct. Anyone?
Stroustrup, The C++ Programming Language, Special Edition, page 371: "Throwing an exception requires an object to throw. A C++ implementation is required to have enough spare memory to be able to throw bad_alloc in case of memory exhaustion. However, it is possible that throwing some other exception will cause memory exhaustion."
That seems to imply that in case of allocation failure when allocating an exception, bad_alloc is thrown instead, although he stops short of saying precisely that.
The C++ standard is also careful not to specify precisely this behavior, but at least it's seems clear that throwing bad_alloc in case there's no memory to throw the requested exception is a valid (platform-specific) behavior. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
How is failure to allocate an exception object handled in various compilers? 15.1.4 says that "the memory for the temporary copy of the exception being thrown is allocated in an unspecified way" but I don't think it specifies behavior for the case when the allocation fails. I know that some compilers allocate exceptions from the heap, so does this mean that an attempt to throw any exception could, in theory, result in a std::bad_alloc being thrown instead? As far as I can tell such behavior wouldn't violate the C++ standard, but I'm not sure my interpretation is correct. Anyone?
GCC allocates exceptions on the heap. If that fails, it will allocate them in the emergency storage instead. The emergency storage is a small buffer (64 slots of a few kB each - used to be 16 slots, but I changed that when I implemented exception propagation) allocated statically. If allocation in emergency storage fails, GCC aborts the process. The way the common C++ ABI is specified, I think every compiler that follows it will have to do a very similar thing. There's a __cxa_allocate_exception function specified. So Sun, IBM and HP's compilers probably do the same thing. But I can't vouch for it. http://www.codesourcery.com/public/cxx-abi/abi-eh.html#cxx-throw MSVC allocates on the stack. Sebastian

GCC allocates exceptions on the heap. If that fails, it will allocate them in the emergency storage instead. The emergency storage is a small
MSVC allocates on the stack.
I am a bit surprised. During compilation it can be checked what is the maximal size of exception being thrown and preallocate space for it (or maybe two such to handle throwing from within catch). This way exception propagation will always succeed unless user uses new during exception construction (like with Boost.Exception data injection). But this is done by the user himself/herself so it is up to his/her control and choice. Adam Badura

Adam Badura wrote:
GCC allocates exceptions on the heap. If that fails, it will allocate them in the emergency storage instead. The emergency storage is a small
MSVC allocates on the stack.
I am a bit surprised. During compilation it can be checked what is the maximal size of exception being thrown and preallocate space for it (or maybe two such to handle throwing from within catch). First, the analysis to get the total size of all exceptions that could be active at the same time requires the dynamic call stack. This includes dynamic libraries. It is therefore fundamentally impossible to correctly determine this size. Second, when threading is in play, you must multiply this amount by the maximum number of threads ever active concurrently. This is just as impossible. Third, when you have exception propagation, you can keep exceptions alive indefinitely. In theory, you could end every single catch block you have by pushing current_exception() into a global container. Thus, over the run time of the application you can accumulate an arbitrary amount of exceptions.
So no, you can't statically determine the size you need. Sebastian

First, the analysis to get the total size of all exceptions that could be active at the same time requires the dynamic call stack. This includes dynamic libraries. It is therefore fundamentally impossible to correctly determine this size.
Obviously I meant case when you have one binary unit. So the compiler knows everything (the system API does not throw). I doubt whether Standard (actual) says anything about exceptions propagations between programs (a DLL and EXE are here different programs). Inter-module propagation of exceptions is a risky thing. It will work only in case you actually have strong control over all those modules. On the other hand such propagation beyond modules indeed is used and works. So maybe Standard did not request preallocation because in practical cases (different binary modules) it would not work anyway.
Second, when threading is in play, you must multiply this amount by the maximum number of threads ever active concurrently. This is just as impossible.
Again the same. Current Standard does not deal with multi-threading.
Third, when you have exception propagation, you can keep exceptions alive indefinitely. In theory, you could end every single catch block you have by pushing current_exception() into a global container. Thus, over the run time of the application you can accumulate an arbitrary amount of exceptions.
AFAIK this is not true. At a single execution point we might require space for only two exceptions (per thread). The one actually thrown and a second one in case we are in catch block and we construct a new exception. There is no such thing as current_exception in current Standard and the one implemented in Boost.Exception makes a (dynamically allocated) copy. How will current_exception be implemented in future C++ Standard implementation I don't know. More exceptions would be possible if if throwing an exception while an exception is already active would not terminate execution. The Standard might allow throwing a second exception unless it would lead to unwinding the same function for two exceptions at the same time. This way we could call to throwing functions in destructors if we just did not propagate exceptions from them. If I am not mistaken Standard does not allow it and terminates upon throw for a second time (I don't know why this is so). So I don't see way of achieving more then 2 exception objects at the same time (per thread).
So no, you can't statically determine the size you need.
In most practical cases indeed. However there exist cases where such detection is possible and I think no so hard. Adam Badura

AMDG Adam Badura wrote:
AFAIK this is not true. At a single execution point we might require space for only two exceptions (per thread). The one actually thrown and a second one in case we are in catch block and we construct a new exception. There is no such thing as current_exception in current Standard and the one implemented in Boost.Exception makes a (dynamically allocated) copy. How will current_exception be implemented in future C++ Standard implementation I don't know. More exceptions would be possible if if throwing an exception while an exception is already active would not terminate execution. The Standard might allow throwing a second exception unless it would lead to unwinding the same function for two exceptions at the same time. This way we could call to throwing functions in destructors if we just did not propagate exceptions from them. If I am not mistaken Standard does not allow it and terminates upon throw for a second time (I don't know why this is so). So I don't see way of achieving more then 2 exception objects at the same time (per thread).
terminate will not be called unless the destructor exits with an exception. You can have an arbitrary number of active exceptions. In Christ, Steven Watanabe

terminate will not be called unless the destructor exits with an exception. You can have an arbitrary number of active exceptions.
I rechecked in the standard. And yes. I got that wrong. Thanks for correcting me. Adam Badura

Adam Badura wrote:
First, the analysis to get the total size of all exceptions that could be active at the same time requires the dynamic call stack. This includes dynamic libraries. It is therefore fundamentally impossible to correctly determine this size.
Obviously I meant case when you have one binary unit. So the compiler knows everything (the system API does not throw). I doubt whether Standard (actual) says anything about exceptions propagations between programs (a DLL and EXE are here different programs). Inter-module propagation of exceptions is a risky thing. It will work only in case you actually have strong control over all those modules. On the other hand such propagation beyond modules indeed is used and works. So maybe Standard did not request preallocation because in practical cases (different binary modules) it would not work anyway. It does not request preallocation because the standard doesn't request *anything* about implementation details. Storage for exceptions is an implementation detail.
Second, when threading is in play, you must multiply this amount by the maximum number of threads ever active concurrently. This is just as impossible.
Again the same. Current Standard does not deal with multi-threading.
At the same time, it is not entirely blind to it. It does not require anything that is impossible to do in a multi-threaded environment.
Third, when you have exception propagation, you can keep exceptions alive indefinitely. In theory, you could end every single catch block you have by pushing current_exception() into a global container. Thus, over the run time of the application you can accumulate an arbitrary amount of exceptions.
AFAIK this is not true. At a single execution point we might require space for only two exceptions (per thread). The one actually thrown and a second one in case we are in catch block and we construct a new exception. There is no such thing as current_exception in current Standard and the one implemented in Boost.Exception makes a (dynamically allocated) copy. How will current_exception be implemented in future C++ Standard implementation I don't know. More exceptions would be possible if if throwing an exception while an exception is already active would not terminate execution. The Standard might allow throwing a second exception unless it would lead to unwinding the same function for two exceptions at the same time. This way we could call to throwing functions in destructors if we just did not propagate exceptions from them. If I am not mistaken Standard does not allow it and terminates upon throw for a second time (I don't know why this is so). So I don't see way of achieving more then 2 exception objects at the same time (per thread). Here's a perfectly legal, perfectly defined C++03 program in a single module with a single thread that has a runtime-determined number of exceptions:
#include <iostream> void fun(int recursions); int main() { int n; std::cin >> n; fun(n); } void fun(int recursions) { try { throw 0; } catch(int) { fun(recursions - 1); } } Sebastian

Here's a perfectly legal, perfectly defined C++03 program in a single module with a single thread that has a runtime-determined number of exceptions:
#include <iostream>
void fun(int recursions);
int main() { int n; std::cin >> n; fun(n); }
void fun(int recursions) { try { throw 0; } catch(int) { fun(recursions - 1); } }
Actually you must use the exception object in the catch so that the compiler cannot optimize it away. So this example is not correct. :) Adam Badura

On Tue, 19 May 2009 07:37:26 +0200, "Adam Badura" <abadura@o2.pl> wrote:
Here's a perfectly legal, perfectly defined C++03 program in a single module with a single thread that has a runtime-determined number of exceptions:
#include <iostream>
void fun(int recursions);
int main() { int n; std::cin >> n; fun(n); }
void fun(int recursions) { try { throw 0; } catch(int) { fun(recursions - 1); } }
Actually you must use the exception object in the catch so that the compiler cannot optimize it away. So this example is not correct. :)
Just because the compiler *can*, doesn't mean that it does. In fact, I very much doubt you'll find a compiler that does. Exception handling is partially implemented in support libraries, and dealing with disappearing exception objects is hard for a library. So it's still likely runtime-determined. The compiler could also analyze the program and determine that it's one big noop and completely optimize it away, except for the input statement. But by all means, print the int or use a type with a non-trivial constructor as the exception. My point is made, and nit-picking won't change that. Sebastian

On Sun, May 17, 2009 at 1:53 AM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Emil Dotchevski wrote:
How is failure to allocate an exception object handled in various compilers? 15.1.4 says that "the memory for the temporary copy of the exception being thrown is allocated in an unspecified way" but I don't think it specifies behavior for the case when the allocation fails. I know that some compilers allocate exceptions from the heap, so does this mean that an attempt to throw any exception could, in theory, result in a std::bad_alloc being thrown instead? As far as I can tell such behavior wouldn't violate the C++ standard, but I'm not sure my interpretation is correct. Anyone?
MSVC allocates on the stack.
Now that you mention this, I remember something else I was wondering about MSVC: is the code in the exception handler executed on top of the stack, just over the exception object that was put there by the throw? Also, you could run out of stack memory. It's likely that in this case you'll get abort() just like when you run out of memory for exceptions in GCC, unless you have structured exception handling enabled -- and in that case would you get some sort of stack overflow exception? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski <emildotchevski@gmail.com> writes:
On Sun, May 17, 2009 at 1:53 AM, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Emil Dotchevski wrote:
How is failure to allocate an exception object handled in various compilers? 15.1.4 says that "the memory for the temporary copy of the exception being thrown is allocated in an unspecified way" but I don't think it specifies behavior for the case when the allocation fails. I know that some compilers allocate exceptions from the heap, so does this mean that an attempt to throw any exception could, in theory, result in a std::bad_alloc being thrown instead? As far as I can tell such behavior wouldn't violate the C++ standard, but I'm not sure my interpretation is correct. Anyone?
MSVC allocates on the stack.
Now that you mention this, I remember something else I was wondering about MSVC: is the code in the exception handler executed on top of the stack, just over the exception object that was put there by the throw?
I don't think exception objects are allocated on the stack in MSVC, and I don't see how they could be --- if an exception is caught then before the handler is entered the stack needs to be unwound and all the destructors run. Having an exception object lurking halfway down the empty stack space would just confuse things no end. However, the object in the throw expression (e.g. throw my_class();) is typically a temporary, and thus stack allocated, and the runtime might not copy this until a handler has been found.
Also, you could run out of stack memory. It's likely that in this case you'll get abort() just like when you run out of memory for exceptions in GCC, unless you have structured exception handling enabled -- and in that case would you get some sort of stack overflow exception?
If you run out of stack space in MSVC you do get a stack overflow structured exception. If you haven't provided a handler then this will terminate your program. Anthony -- Author of C++ Concurrency in Action | http://www.manning.com/williams just::thread C++0x thread library | http://www.stdthread.co.uk Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

2009/5/18 Anthony Williams <anthony.ajw@gmail.com>
I don't see how they could be --- if an exception is caught then before the handler is entered the stack needs to be unwound and all the destructors run.
Here is one way it could be on the stack (I think I heard it when someone described the Metrowerks implementation, but I could be wrong): Allocate a new stack frame when the throw expression is encountered, and keep track of where it is. Wherever a new stack frame is needed (say, for local variables in destructors during stack unwinding), allocate them below the stack frame of the exception. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

Hi, 2009/5/18 Anthony Williams <anthony.ajw@gmail.com>:
I don't think exception objects are allocated on the stack in MSVC, and I don't see how they could be --- if an exception is caught then before the handler is entered the stack needs to be unwound and all the destructors run. Having an exception object lurking halfway down the empty stack space would just confuse things no end.
I debugged this once to find out what's what exactly and it is halfway down the stack. The stack below it is unwound but it is not freed until the end of the exception handler. The exception handler executes on the stack just above (below) the exception, and the exception is destroyed and the stack below it freed when it's done. This all is based on empirical measurement. When I figured it out it seemed like a good solution, except for the case where you have just unwound a big stack and build up a new big stack inside an exception handler. That seems an off-case that isn't worth the trouble though. Kind regards, Peter Bindels

Peter Bindels <dascandy@gmail.com> writes:
2009/5/18 Anthony Williams <anthony.ajw@gmail.com>:
I don't think exception objects are allocated on the stack in MSVC, and I don't see how they could be --- if an exception is caught then before the handler is entered the stack needs to be unwound and all the destructors run. Having an exception object lurking halfway down the empty stack space would just confuse things no end.
I debugged this once to find out what's what exactly and it is halfway down the stack. The stack below it is unwound but it is not freed until the end of the exception handler. The exception handler executes on the stack just above (below) the exception, and the exception is destroyed and the stack below it freed when it's done. This all is based on empirical measurement.
Wow. I stand corrected. Anthony -- Author of C++ Concurrency in Action | http://www.manning.com/williams just::thread C++0x thread library | http://www.stdthread.co.uk Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

On Wed, May 20, 2009 at 2:45 AM, Peter Bindels <dascandy@gmail.com> wrote:
Hi,
2009/5/18 Anthony Williams <anthony.ajw@gmail.com>:
I don't think exception objects are allocated on the stack in MSVC, and I don't see how they could be --- if an exception is caught then before the handler is entered the stack needs to be unwound and all the destructors run. Having an exception object lurking halfway down the empty stack space would just confuse things no end.
I debugged this once to find out what's what exactly and it is halfway down the stack. The stack below it is unwound but it is not freed until the end of the exception handler. The exception handler executes on the stack just above (below) the exception, and the exception is destroyed and the stack below it freed when it's done. This all is based on empirical measurement.
When I figured it out it seemed like a good solution, except for the case where you have just unwound a big stack and build up a new big stack inside an exception handler. That seems an off-case that isn't worth the trouble though.
It's possible that the compiler uses some logic at run-time, after the exception has been caught, to determine if the exception should be copied elsewhere (as in "would it leave too big of a gap in the stack if it's left there?) I'm saying this because, if I remember correctly, MSVC is careful to keep a pointer to the exception object copy constructor (so it can clone it) which seems pointless if the object is created on the stack and never copied elsewhere. Also, I've been wondering why the C++ standard requires that exceptions have nothrow copy constructor -- that isn't necessary if the object is copied once only at the time of the throw -- but this requirement enables the behavior I described. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (9)
-
Adam Badura
-
Anthony Williams
-
Emil Dotchevski
-
Emil Dotchevski
-
Jeffrey Bosboom
-
Nevin ":-]" Liber
-
Peter Bindels
-
Sebastian Redl
-
Steven Watanabe