I was just playing around with some C++ code at Compiler Explorer and noticed some unexpected behavior when compiling a simple try
/catch
block. Both of the following snippets were compiled with gcc using optimization flag -O3
(live example).
In the first program, the whole try
/catch
block gets removed, since there is no noticeable difference in the behavior, resulting in the same assembly as just a return 0;
. This is exactly what I would have expected the compiler to produce.
int main() {
try {
int x{ 10 };
}
catch (...) {
}
return 0;
}
main:
xor eax, eax
ret
In the second snippet I throw
an exception instead of just initializing an int
. After that exception got thrown, I would continue in the catch
-all handler, which is empty. After that there is only the return 0;
statement. This means that the observable behavior for this program would be the same as the first one. However, the assembly shows, that there is still the whole try
/catch
going on.
int main() {
try {
throw 10;
}
catch (...) {
}
return 0;
}
main:
push rcx
mov edi, 4
call __cxa_allocate_exception
xor edx, edx
mov esi, OFFSET FLAT:_ZTIi
mov DWORD PTR [rax], 10
mov rdi, rax
call __cxa_throw
mov rdi, rax
call __cxa_begin_catch
call __cxa_end_catch
xor eax, eax
pop rdx
ret
Now I am wondering why the compiler can't recognize that the whole try
/catch
block is "dead code" (or is it not?), or if it can recognize it, why it is not optimizing it away.
throw 10;
will copy that 10 literal to the in flightint
exception with the value 10. I recall that the exception machinery can be hooked into. Perhaps it can't be optimized out, even though your code is complete and self-contained, and doesn't hook into that exception machinery. – Metropolismain
just zeros EAX). – RubbishLN7@main
? In themain PROC
it's still throwing; though it does get rid of the catch. – Foucaultcatch(char c)
(which doesn't catch the throw of anint
so the program crashes instead), MSVC's code-gen is the same: godbolt.org/z/56nd1cffd – Inveigle