-
Notifications
You must be signed in to change notification settings - Fork 189
Description
If C++ exceptions are used in the project, then to use __try/__except it is necessary to build the project with the /EHa option!
Proof: https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160
When using C++ exceptions, the StackWalker cannot get information about the last call in which the exception occurred.
Here is the code to demonstrate this bug:
https://github.com/remittor-pr/StackWalker/blob/9be4790427145ba81adfd22188e591820f92a0ad/Main/StackWalker/main.cpp
Compiler: MSVC2015 (x64 Release)
Options with which the test project was built: /MT /Zi /O2 /EHa
DebugLog for: THROW_CPP_EXP = 0, CATCH_CPP_EXP = 0
THROW_CPP_EXP = 0, CATCH_CPP_EXP = 0
----- bar -----
===== main.__except =====
main.cpp (23): bar
main.cpp (30): foo
main.cpp (41): test
main.cpp (72): main
exe_common.inl (253): __scrt_common_main_seh
----- Foo destructor -----
***** END *****
DebugLog for: THROW_CPP_EXP = 1, CATCH_CPP_EXP = 0
THROW_CPP_EXP = 1, CATCH_CPP_EXP = 0
----- bar -----
===== main.__except =====
KERNELBASE: RaiseException
throw.cpp (136): _CxxThrowException
main.cpp (22): bar
main.cpp (30): foo
main.cpp (41): test
main.cpp (71): main
exe_common.inl (253): __scrt_common_main_seh
----- Foo destructor -----
***** END *****
DebugLog for: THROW_CPP_EXP = 0, CATCH_CPP_EXP = 1
THROW_CPP_EXP = 0, CATCH_CPP_EXP = 1
----- bar -----
----- Foo destructor -----
===== test.catch =====
stackwalker.cpp (1073): StackWalker::ShowCallstack
main.cpp (52): `test'::`1'::catch$1
handlers.asm (50): _CallSettingFrame
frame.cpp (1322): __CxxCallCatchBlock
ntdll: RtlRestoreContext
main.cpp (41): test
main.cpp (72): main
exe_common.inl (253): __scrt_common_main_seh
===== main.__except =====
KERNELBASE: RaiseException
frame.cpp (1342): __CxxCallCatchBlock
ntdll: RtlRestoreContext
main.cpp (41): test
main.cpp (72): main
exe_common.inl (253): __scrt_common_main_seh
***** END *****
DebugLog for: THROW_CPP_EXP = 1, CATCH_CPP_EXP = 1
THROW_CPP_EXP = 1, CATCH_CPP_EXP = 1
----- bar -----
----- Foo destructor -----
===== test.catch =====
stackwalker.cpp (1073): StackWalker::ShowCallstack
main.cpp (52): `test'::`1'::catch$1
handlers.asm (50): _CallSettingFrame
frame.cpp (1322): __CxxCallCatchBlock
ntdll: RtlRestoreContext
main.cpp (41): test
main.cpp (71): main
exe_common.inl (253): __scrt_common_main_seh
===== main.__except =====
KERNELBASE: RaiseException
frame.cpp (1342): __CxxCallCatchBlock
ntdll: RtlRestoreContext
main.cpp (41): test
main.cpp (71): main
exe_common.inl (253): __scrt_common_main_seh
***** END *****
DebugLog for: THROW_CPP_EXP = 1, CATCH_CPP_EXP = 2
THROW_CPP_EXP = 1, CATCH_CPP_EXP = 2
----- bar -----
----- Foo destructor -----
===== test.catch =====
KERNELBASE: RaiseException
throw.cpp (136): _CxxThrowException
main.cpp (22): bar
main.cpp (30): foo
main.cpp (41): test
main.cpp (71): main
exe_common.inl (253): __scrt_common_main_seh
===== main.__except =====
KERNELBASE: RaiseException
frame.cpp (1342): __CxxCallCatchBlock
ntdll: RtlRestoreContext
main.cpp (41): test
main.cpp (71): main
exe_common.inl (253): __scrt_common_main_seh
***** END *****
The last log shows how using the CATCH_CPP_EXP = 2 option allows you to fix the StackWalker bug.
But it is worth noting the following fact. If the test program is compiled with the /EHsc option, the StackWalker will work better (but not correctly). There will be an error in the line numbers (look to main and bar line numbers).
DebugLog for: /EHsc, THROW_CPP_EXP = 0, CATCH_CPP_EXP = 0
THROW_CPP_EXP = 0, CATCH_CPP_EXP = 0
----- bar -----
===== main.__except =====
main.cpp (23): bar
main.cpp (30): foo
main.cpp (41): test
main.cpp (72): main
exe_common.inl (253): __scrt_common_main_seh
***** END *****
DebugLog for: /EHsc, THROW_CPP_EXP = 0, CATCH_CPP_EXP = 1
THROW_CPP_EXP = 0, CATCH_CPP_EXP = 1
----- bar -----
===== main.__except =====
main.cpp (23): bar
main.cpp (30): foo
main.cpp (41): test
main.cpp (72): main
exe_common.inl (253): __scrt_common_main_seh
***** END *****
DebugLog for: /EHsc, THROW_CPP_EXP = 1, CATCH_CPP_EXP = 0
Same as for /EHa
DebugLog for: /EHsc, THROW_CPP_EXP = 1, CATCH_CPP_EXP = 1
Same as for /EHa
DebugLog for: /EHsc, THROW_CPP_EXP = 1, CATCH_CPP_EXP = 2
Same as for /EHa
It is necessary to explicitly write about this problem in the documentation!