Fix for sigsegv stack overflow behavior

Also stops Catch from assuming its the only signal user in the binary,
and makes it restore the signal handlers it has replaced. Same goes for
the signal stack.

The signal stack itself probably shouldn't be always reallocated for
fragmentation reasons, but that can be fixed later on.
This commit is contained in:
Martin Hořeňovský 2016-11-26 14:10:11 +01:00
parent e6aa1f4e4e
commit a281173099

View File

@ -60,22 +60,41 @@ namespace Catch {
fatal( "<unknown signal>", -sig ); fatal( "<unknown signal>", -sig );
} }
FatalConditionHandler() : m_isSet( true ) { FatalConditionHandler(): m_isSet(true), m_altStackMem(new char[SIGSTKSZ]) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) stack_t sigStack;
signal( signalDefs[i].id, handleSignal ); sigStack.ss_sp = m_altStackMem;
sigStack.ss_size = SIGSTKSZ;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &m_oldSigStack);
struct sigaction sa = { 0 };
sa.sa_handler = handleSignal;
sa.sa_flags = SA_ONSTACK;
for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &m_oldSigActions[i]);
}
} }
~FatalConditionHandler() { ~FatalConditionHandler() {
reset(); reset();
delete[] m_altStackMem;
} }
void reset() { void reset() {
if( m_isSet ) { if( m_isSet ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
signal( signalDefs[i].id, SIG_DFL ); for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &m_oldSigActions[i], CATCH_NULL);
}
// Return the old stack
sigaltstack(&m_oldSigStack, CATCH_NULL);
m_isSet = false; m_isSet = false;
} }
} }
bool m_isSet; bool m_isSet;
// C++03 doesn't allow auto_ptr<T[]>, so we have manage the memory ourselves
char* m_altStackMem;
struct sigaction m_oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
stack_t m_oldSigStack;
}; };
} // namespace Catch } // namespace Catch