I figured this would be the best suited place to post this since this isn't really language-specific...

So I'm wondering how a try/catch statement actually works (I know how to use them so that's not what I'm asking), like what happens on machine-level or runtime-level etc when a try/catch is trying to manage your code? How can your try-statement run a piece of code and find exceptions etc?...

I hope my question isn't too abstract

Let's take a look at a short piece of code that will always generate an exception.

int a = 100;
int b = 0;
int c = a / b;

The code generated by my compiler looks like this:

int a = 100;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  sub         esp,0Ch 
00000006  mov         dword ptr [ebp-4],ecx 
00000009  cmp         dword ptr ds:[00442330h],0 
00000010  je          00000017 
00000012  call        6EC0403F 
00000017  xor         edx,edx 
00000019  mov         dword ptr [ebp-8],edx 
0000001c  xor         edx,edx 
0000001e  mov         dword ptr [ebp-0Ch],edx 
00000021  mov         dword ptr [ebp-8],64h 
            int b = 0;
00000028  xor         edx,edx 
0000002a  mov         dword ptr [ebp-0Ch],edx 

            int c = a / b;
0000002d  mov         eax,dword ptr [ebp-8] 
00000030  cdq 
00000031  idiv        eax,dword ptr [ebp-0Ch]

Nothing in there for exception handling, but an exception is raised, so something behind the scene is dealing with it. Since the exception is raised in the idiv line, we take a look at the documentation for the processor (found here) and we note that is says "Overflow is indicated with the #DE (divide error) exception rather than with the OF (overflow) flag." So the processor itself has exceptions, so it must be the OS that is handling it in this case.

Now we put a try catch in there:

int a = 100;
int b = 0;

try {
    int c = a / b;
} catch {
}

Which gives us:

int a = 100;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        edi 
00000004  push        esi 
00000005  push        ebx 
00000006  sub         esp,20h 
00000009  xor         eax,eax 
0000000b  mov         dword ptr [ebp-20h],eax 
0000000e  mov         dword ptr [ebp-1Ch],eax 
00000011  mov         dword ptr [ebp-18h],eax 
00000014  mov         dword ptr [ebp-14h],eax 
00000017  xor         eax,eax 
00000019  mov         dword ptr [ebp-18h],eax 
0000001c  mov         dword ptr [ebp-24h],ecx 
0000001f  cmp         dword ptr ds:[00A12330h],0 
00000026  je          0000002D 
00000028  call        6E9543DF 
0000002d  xor         edx,edx 
0000002f  mov         dword ptr [ebp-28h],edx 
00000032  xor         edx,edx 
00000034  mov         dword ptr [ebp-2Ch],edx 
00000037  mov         dword ptr [ebp-28h],64h 
            int b = 0;
0000003e  xor         edx,edx 
00000040  mov         dword ptr [ebp-2Ch],edx 

            try {
                int c = a / b;
00000043  mov         eax,dword ptr [ebp-28h] 
00000046  cdq 
00000047  idiv        eax,dword ptr [ebp-2Ch] 
0000004a  nop 
0000004b  jmp         00000055 
            } catch {
0000004d  nop 
0000004e  call        6E6A0218 
00000053  jmp         00000055 
            }

Notice there is a lot more start-up code. I suspect that this code is setting up for telling the OS that if an exception happens, we want to continue execution at 0000004d and that line 00000028 is where we make a call into the OS.

I can't find any documentation of processor exceptions (and I have to admit I haven't looked very hard) so I can't tell you what is actually going on there, but I suspect that when the processor hits an exception, it looks at a certain memory location then runs the code that they memory location points to. The OS would be required to set up its exception handling code and establish the value at that memory location.

Good answer, thanks! I upvoted your post but will wait a day or so before I mark it as solved =)

Great article. A bit old, but still valid.

C++ exceptions are different from CPU exceptions and they don't interact. Momeranth's post is basically wrong.

nezachem is linking to an article that talks specifically about Windows structured exceptions, not C++ exceptions or other kinds. (So they're an example of a certain kind of exception mechanism.)

Ultimately the implementation of exceptions depends on the compiler and runtime you use. Microsoft's C++ compiler and GCC use different techniques for implementing exception handling. There are trade-offs between making exceptions fast and making code paths that lack exception flow fast. Your best bet for finding an answer to your question is to look for compiler-specific information and see how each compiler implements them.

nezachem is linking to an article that talks specifically about Windows structured exceptions, not C++ exceptions

Possibly. However, the article claims that
Under the hood, true C++ exception handling is implemented very similarly to what I'll describe here.

I still think it is a great introduction into exception handling.

C++ exceptions are different from CPU exceptions and they don't interact. Momeranth's post is basically wrong.

Please point out where in the first block of code I posted that the divide by zero exception is being handled by the compiler. There is no test for zero before the divide so the only way an exception can be raised is through the processor exception.

While it may be true that (some) C++ compilers handle exceptions differently, it isn't true that C++ is the only language that handles exceptions. The poster didn't specify what language he was using. All I was showing is how one particular language handled exceptions with the compiler I was using.

Please point out where in the first block of code I posted that the divide by zero exception is being handled by the compiler. There is no test for zero before the divide so the only way an exception can be raised is through the processor exception.

It was your second block of code (obviously) where you put a (malformed?) try catch block around a division operation. Which is an absurd thing to do, because it's impossible for that code to throw an exception.

Please stop trying to backpedal into some sort of interpretation of your post that would be barely correct and completely useless. It's clear you don't know what you're talking about. See:

Notice there is a lot more start-up code. I suspect that this code is setting up for telling the OS that if an exception happens, we want to continue execution at 0000004d and that line 00000028 is where we make a call into the OS.

I can't find any documentation of processor exceptions (and I have to admit I haven't looked very hard) so I can't tell you what is actually going on there, but I suspect that when the processor hits an exception, it looks at a certain memory location then runs the code that they memory location points to. The OS would be required to set up its exception handling code and establish the value at that memory location.

Nope. That's not what happens. Unless you set a compiler flag (on Windows) that enables Windows structured exceptions to be caught by the C++ exception mechanism. This flag is not on by default and was changed 7 years ago, and the assembly code you posted was not compiled under that setting.

I don't get why you're butthurt about somebody saying your post is wrong when you're explicitly guessing (and wrong).

While it may be true that (some) C++ compilers handle exceptions differently, it isn't true that C++ is the only language that handles exceptions. The poster didn't specify what language he was using. All I was showing is how one particular language handled exceptions with the compiler I was using.

What language is that you're showing there, which almost looks like C++ and compiles to machine code?

I still think it is a great introduction into exception handling.

Oh absolutely.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.