83
votes

I understand that when something is thrown, the stack is 'unwound' to the point where it is caught, and the destructors of class instances on the stack in each function context are run (which is why you should not throw an exception from a destructor - you could end up throwing a second one)...but I wonder where in memory the object that I have thrown is stored while this happens?

Is it implementation dependent? If so, is there a particular method used by most popular compilers?

5
Good question - it's probably not specified by the standard, since the standard doesn't even say that you have to have a stack. Practically, perhaps it's allocated on the heap and freed when the catch block exits?Kerrek SB
@Kerrek: I think more likely, the object is placed on the stack way down at the "bottom". Then unwind upwards, remembering where it was, and once you've finished unwinding (including giving any catch clauses the opportunity to address the exception by reference, and to re-raise it), destroy it. The issue with heap allocation is, what do you do if your attempt to allocate the exception fails? You'd have to abort (just as you would for stack overflow if putting it on the stack "fails" due to lack of space). Unlike Java the implementation isn't allowed to throw a different exception instead.Steve Jessop
@Steve: Also possible - Kiril's article says that the exception is allocated on the stack, and an auxiliary info structure records its address and deleter etc., but I imagine that implementations are free to do this in any way they like?Kerrek SB
@Kerrek: yes, subject to the constraint that it has to actually throw the exception, and the usual issue that running out of stack permits the implementation to evade such responsibilities :-) If you put it on the stack, then because exceptions are thrown by the static type of the throw expression, your stack frame for the whole function could include whatever space is needed to throw that type, although I don't know if MSVC does that.Steve Jessop

5 Answers

54
votes

Yes, the answer is compiler-dependent.

A quick experiment with my compiler (g++ 4.4.3) reveals that its runtime library first tries to malloc memory for the exception and, failing that, attempts to allocate space within a process-wide "emergency buffer" that lives on the data segment. If that doesn't work out, it calls std::terminate().

It would appear that the main purpose of the emergency buffer is to be able to throw std::bad_alloc after the process has run out of heap space (in which case the malloc call would fail).

The relevant function is __cxa_allocate_exception:

extern "C" void *
__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
{
  void *ret;

  thrown_size += sizeof (__cxa_refcounted_exception);
  ret = malloc (thrown_size);

  if (! ret)
    {
      __gnu_cxx::__scoped_lock sentry(emergency_mutex);

      bitmask_type used = emergency_used;
      unsigned int which = 0;

      if (thrown_size > EMERGENCY_OBJ_SIZE)
        goto failed;
      while (used & 1)
        {
          used >>= 1;
          if (++which >= EMERGENCY_OBJ_COUNT)
            goto failed;
        }

      emergency_used |= (bitmask_type)1 << which;
      ret = &emergency_buffer[which][0];

    failed:;

      if (!ret)
        std::terminate ();
    }

  // We have an uncaught exception as soon as we allocate memory.  This
  // yields uncaught_exception() true during the copy-constructor that
  // initializes the exception object.  See Issue 475.
  __cxa_eh_globals *globals = __cxa_get_globals ();
  globals->uncaughtExceptions += 1;

  memset (ret, 0, sizeof (__cxa_refcounted_exception));

  return (void *)((char *)ret + sizeof (__cxa_refcounted_exception));
}

I don't know how typical this scheme is.

22
votes

From this page:

Storage is needed for exceptions being thrown. This storage must persist while stack is being unwound, since it will be used by the handler, and must be thread-safe. Exception object storage will therefore normally be allocated in the heap, although implementations may provide an emergency buffer to support throwing bad_alloc exceptions under low memory conditions.

Now, this is only the Itanium ABI and I'm looking for details specific to GCC, Clang and MSVC. However, the standard doesn't specify anything and this seems to be the obvious way to implement exception storage, so...

6
votes

I don't know if this will answer your question, but this (How a C++ compiler implements exception handling) is excellent article about the exception handling at all: . I highly recommend it (:

Sorry for the short answer, but the whole information in the article is great, I can't pick and post some info here.

0
votes

The C++ standard generally specifies how the language behaves but not how the compiler should implement that behavior. I think this question falls into that category. The best way to implement something like this depends on the specifics of the machine -- some processors have lots of general purpose registers, some have very few. A processor might even be built with a special register just for exceptions, in which case the compiler should be free to take advantage of that feature.

-2
votes

Well, it can't be on the stack, since that's going to be unwound, and it can't be on the heap, since that would mean that the system likely couldn't throw std::bad_alloc. Other than that, it's completely up to the implementation: not implementation specified (which must be documented), but unspecified. (An implementation could use the heap most of the time, as long as it has some sort of emergency back-up that will allow a limited number of exceptions even when there's no more memory.)