minidump
(for example, CrashRpt or google-breakpad ), so this article is more educational in nature.try-catch
construct, but using __try-__except
.catch
stack is already promoted, and in the constructor of the exception, we agreed not to receive the stack. But it turns out that if try-catch
wraps up __try-__except
, then even in the case of a program exception, we first go into the filter passed to __except
. Here we can get a call stack, but what should the filter return? If the filter returns EXCEPTION_EXECUTE_HANDLER
, then we will not get to try-catch
. Well, let's return EXCEPTION_CONTINUE_SEARCH
, which will cause the handler to look for the next filter, which will return EXCEPTION_EXECUTE_HANDLER
. In this case, with a software exception, we will go to try-catch
, and in the case of hardware exclusion, the exception-handling mechanism will go looking for a handler further down the stack, skip try-catch
and so on until it meets __except
with the argument EXCEPTION_EXECUTE_HANDLER
. Well, then we wrap try-catch
in __try-__except(EXCEPTION_EXECUTE_HANDLER)
. __except(filter()/*-> EXCEPTION_CONTINUE_SEARCH*/) { /* */ }
never be fulfilled. __try { try { __try { useful_unsafe_function(); } __except(filter()/*-> EXCEPTION_CONTINUE_SEARCH*/) { // this block will be never executed } } catch(const your_lib::Exception& ex) { } catch(const std::exception& ex) { } catch(...) { } } __except(EXCEPTION_EXECUTE_HANDLER) { }
function<void()>
)false
. struct SafeExecutor { typedef boost::function<void()> TDoDelegate; SafeExecutor(TDoDelegate doDelegate); // true - the everything is successful // false - otherwise bool Do(); private: bool DoCPlusPlusExceptionWrapper(); bool DoWorkWrapper(); private: TDoDelegate m_DoDelegate; };
Filter
function, in which we have to get a call stack, and which returns EXCEPTION_CONTINUE_SEARCH
: LONG Filter( PEXCEPTION_POINTERS pep ) { // pep->ExceptionRecord->ExceptionCode // pep->ExceptionRecord->ExceptionAddress // GetModules(); // GetCallStack(); return EXCEPTION_CONTINUE_SEARCH; }
bool SafeExecutor::Do() { bool AbnornalTermination = false; bool IsExecSuccessful = true; { __try { IsExecSuccessful = DoCPlusPlusExceptionWrapper(); } __except(EXCEPTION_EXECUTE_HANDLER) { AbnornalTermination = true; } } return !AbnornalTermination && IsExecSuccessful; }
bool SafeExecutor::DoCPlusPlusExceptionWrapper() { bool res = true; try { res = DoWorkWrapper(); } catch(std::exception& /*ex*/) { // smth like log(ex.what()); //assert(false); res = false; } catch(...) { // smth like log("unknown sw-exception); //assert(false); res = false; } return res; }
Filter
function in which we need to get the call stack. bool SafeExecutor::DoWorkWrapper() { bool res = false; if (!m_DoDelegate.empty()) { __try { m_DoDelegate(); res = true; } __except(Filter(GetExceptionInformation())) // we must dump callstack inside this Filter { // never be executed because Filter always returns `CONTINUE_SEARCH` } } return res; }
int HWUnsafe() { int z = 0; return 1/z; } TEST(HWUnsafe, SafeExecutor) { SafeExecutorNS::SafeExecutor se(HWUnsafe); ASSERT_FALSE(se.Do()); }
int SWUnsafe1() { int z = 1; throw std::exception(); return 1/z; } TEST(SW_std_ex, SafeExecutor) { SafeExecutorNS::SafeExecutor se(SWUnsafe1); ASSERT_FALSE(se.Do()); }
Source: https://habr.com/ru/post/163745/
All Articles