How is the C++ exception handling runtime implemented?

27,394

Solution 1

Implementations may differ, but there are some basic ideas that follow from requirements.

The exception object itself is an object created in one function, destroyed in a caller thereof. Hence, it's typically not feasible to create the object on the stack. On the other hand, many exception objects are not very big. Ergo, one can create e.g a 32 byte buffer and overflow to heap if a bigger exception object is actually needed.

As for the actual transfer of control, two strategies exist. One is to record enough information in the stack itself to unwind the stack. This is basically a list of destructors to run and exception handlers that might catch the exception. When an exception happens, run back the stack executing those destructors until you find a matching catch.

The second strategy moves this information into tables outside the stack. Now, when an exception occurs, the call stack is used to find out which scopes are entered but not exited. Those are then looked up in the static tables to determine where the thrown exception will be handled, and which destructors run in between. This means there is less exception overhead on the stack; return addresses are needed anyway. The tables are extra data, but the compiler can put them in a demand-loaded segment of the program.

Solution 2

This is defined in 15.1 Throwing an exception of the standard.

The throw creates a temporary object.
How the memory for this temporary object is allocated is unspecified.

After creation of the temporary object control is passed to the closest handler in the call stack. unwinding the stack between throw and catch point. As the stack is unwind any stack variables are destroyed in reverse order of creation.

Unless the exception is re-thrown the temporary is destroyed at the end of the handler where it was caught.

Note: If you catch by reference the reference will refer to the temporary, If you catch by value the temporary object is copied into the value (and thus requires a copy constructor).

Advice from S.Meyers (Catch by const reference).

try
{
    // do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}

Solution 3

You could take a look here for a detailed explanation.

It may also help to take a look at a trick used in plain C to implement some basic sort of exception handling. This entails using setjmp() and longjmp() in the following manner: the former saves the stack in order to mark the exception handler (like "catch"), while the latter is used to "throw" a value. The "thrown" value is seen as if it has been returned from a called function. The "try block" ends when setjmp() is called again or when the function returns.

Solution 4

I know this is an old question, but there's a very good exposition, explaining both the methods used in each of gcc and VC here: http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf

Share:
27,394
pjay
Author by

pjay

Updated on August 22, 2020

Comments

  • pjay
    pjay over 3 years

    I am intrigued by how the C++ exception handling mechanism works. Specifically, where is the exception object stored and how does it propagate through several scopes until it is caught? Is it stored in some global area?

    Since this could be compiler specific could somebody explain this in the context of the g++ compiler suite?