1

When an exception is thrown stack unwinding is initiated until handling code is encountered, but I am a little unclear on the mechanics of the whole process.

1 - where is the exception stored? I don't mean the actual exception object, which may be quite big, e.g. have a message string or something, but the actual reference or pointer if you will. It must be some uniform storage location so that it can survive going down as the stack is unwinding and reach a handling location?

2 - how does the program flow determine whether to it has to unwind the particular function frame and call the appropriate destructors associated with the program counter indicated location or seek exception handing before it unwinds further?

3 - how is the actual check between what is thrown and what exceptions are being couth happening?

I am aware that the answer might include platform specific stuff, in which case such will be appreciated. No need to go beyond x86/x64 and ARM though.

  • All the questions have completely implementation-specific answers, and in particular have very different answers for Linux/GCC builds and 32-bit Microsoft Windows builds. – Sebastian Redl Oct 30 '14 at 12:29
  • But for reference: here's the description of the standard Linux C++ ABI exception handling mechanism. Note that ARM is slightly different. http://mentorembedded.github.io/cxx-abi/abi-eh.html – Sebastian Redl Oct 30 '14 at 12:30
  • @SebastianRedl - I don't have a problem with different answers as long as they are informative. I'd appreciate any informative answer, regardless of which implementation it addresses. –  Oct 30 '14 at 12:32
  • 1
    Problem is, I think that's somehow against the guidelines. – Sebastian Redl Oct 30 '14 at 12:45
  • @SebastianRedl - it is against the guidelines to ask implementation specific questions? Or maybe asking "multi-implementation" questions? In case of the latter - will it really be better to ask the same question for each implementation? –  Oct 30 '14 at 12:48
  • @user3735658: It is certainly not against guidelines to ask implementation-specific questions. However, it also requires that the question be objective and not vague. Vague because of talking about no specific platform, implementation, etc. Even within a platform there're different exception handling mechanisms like SEH, sjlj, etc. – legends2k Oct 30 '14 at 13:19
  • @legends2k - that's true, but my question is more in the context of a simple synopsis rather than intricate implementation details. One could write a 100 page answer on the subject, but clearly that is not what I except. So I don't think it is "too broad", it is just the right amount of broad. –  Oct 30 '14 at 13:24

2 Answers2

2

These are all implementation details, to be decided during the (non-trivial) process of designing an exception handling mechanism. I can only give a sketch of how one might (or might not) choose to implement this.

If you want a detailed description of one implementation, you could read the specification for the Itanium ABI used by GCC and other popular compilers.

1 - The exception object is stored in an unspecified place, which must last until the exception has been handled. Pointers or references are passed around within the exception handling code like any other variable, before being passed to the handler (if it takes a reference) by some mechanism similar to passing a function argument.

2 - There are two common approaches: a static data structure mapping the program location to information about the stack frame; or a dynamic stack-like data structure containing information about active handlers and non-trivial stack objects that need destroying.

In the first case, on throwing it will look at that information to see if there are any local objects to destroy, and any local handlers; if not, it will find the function return address on the local stack frame and apply the same process to the calling function's stack frame until a handler is found. Once the handler is found, the CPU registers are updated to refer to that stack frame, and the program can jump to the handler's code.

In the second case it will pop entries from the stack structure, using them to tell it how to destroy stack objects, until it finds a suitable handler. Once the handler is found, and all unwound stack objects destroyed, it can use longjmp or a similar mechanism to jump to the handler.

Other approaches are possible.

3 - The exception handling code will use some kind of data structure to identify a type, allowing it to compare the type being thrown with the type for a handler. This is somewhat complicated by inheritance; the test can't be a simple comparison. I don't know the details for any particular implementation.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • I was focusing on the table approach, i.e. the "call the appropriate destructors associated with the program counter". But it is still unclear how a "handler is found". I mean searching for handlers involves kind of "continuing execution" from the stored PC whereas frame unwinding will only call the destructors for objects that were present at the "moment" and go to the previous frame. –  Oct 30 '14 at 13:07
  • @user3735658: There will be descriptors in the data structure for active handlers within the function, as well as objects to destroy. Once a handler has been identified, "continuing execution" involves setting CPU registers to refer to the appropriate stack frame, which has been found by reading the run-time stack at the time of throwing, then jumping to the appropriate location for the handler. This is a similar mechanism to using `setjmp/longjmp` to store and retrieve an execution context. – Mike Seymour Oct 30 '14 at 13:15
0

Source: How do exceptions work (behind the scenes) in c++ (I read the assembly and answered the questions by what I understood)

Question 1#:

movl    $1, (%esp)
call    __cxa_allocate_exception
movl    $_ZN11MyExceptionD1Ev, 8(%esp)
movl    $_ZTI11MyException, 4(%esp)

_ZTI11MyException is the exception. It looks as if it has it's own allocation not in the stack and it places the pointer in register named eax.

Question 2#:

.LFE9:
.size   _Z20my_catching_functionv, .-_Z20my_catching_functionv
.section    .gcc_except_table,"a",@progbits
.align 4

It looks like table that is stored in static data in the program. So it can know where it can catch. There was nothing about how objects destruct themself after unwinding frames so this is from Visual Studio: (The link at the top is from Linux)

        MyClass s, s2, s3, s4;
 mov         dword ptr [ebp-4],3  
        try {
            {
                MyClass s, s2, s3, s4;
 mov         byte ptr [ebp-4],7  
            }

It looks like it saves the number of objects to destroy. For example when it finishes:

call        MyClass::~MyClass (0DC1163h)
mov         dword ptr [ebp-4],0FFFFFFFFh

0FFFFFFFFh means nothing's to destruct. If I find something about how it actually finds and destroyes them I will add here.

Question 3#:

As in the previous question, you see there's table for it, it can know whatever it's in the right function.

Community
  • 1
  • 1
KugBuBu
  • 630
  • 5
  • 21