When a C++ exception is thrown and stack unwinding occurs, there needs to be some storage area where the exception object is kept alive, until after execution leaves the scope of the outer-most catch block.
But where is this storage space exactly? Looking for answers on stackoverflow, I find: https://stackoverflow.com/a/27259902/2923952
This answer quotes the standard, saying:
The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1.
... [Note: In particular, a global allocation function is not called to allocate storage for [...] an exception object (15.1). — end note]
That makes sense. You wouldn't want the compiler generating calls to malloc
or new
behind the scenes, since you may be writing code that has specific Allocator
requirements.
Since the number of active exceptions is limited by the hard-coded stack depth, there doesn't seem to be any need to dynamically allocate space for exceptions anyway. The compiler could just have some stack-space or per-thread static storage to put active exceptions.
But now we have std::exception_ptr
. This is basically a shared_ptr to an active exception object that keeps the exception object alive as long as any instances of the std::exception_ptr
remain.
But the corollary of this that we can now indefinitely extend the lifetime of any active exception. So basically I could have a std::vector<std::exception_ptr>
, and then in a loop I could keep throwing exceptions and storing each pointer to the current exception in my vector. So I could dynamically generate millions of active exceptions this way.
std::vector<std::exception_ptr> active_exceptions;
for (;;)
{
try { throw int{}; }
catch (...) { active_exceptions.push_back(std::current_exception()); }
}
This would then force the compiler to somehow dynamically add more storage to keep these exceptions alive. So how does it do this? Does it just fall back on using malloc
/new
after it runs out of static storage?