mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-20 18:55:31 +02:00 
			
		
		
		
	In some cases, like when given ```cpp std::vector<char>* str = reinterpret_cast<std::vector<char>*>(0x1234458); CHECK(*str == std::vector<char>()); ``` reconstructing the expression to report it would cause another fatal error. Instead we just put together an AssertionResult without reconstructing the expression fully. This should fully fix #810
		
			
				
	
	
		
			201 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  *  Created by Phil on 21/08/2014
 | |
|  *  Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
 | |
|  *
 | |
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 | |
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
|  *
 | |
|  */
 | |
| #ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
 | |
| #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
 | |
| 
 | |
| 
 | |
| namespace Catch {
 | |
| 
 | |
|     // Report the error condition
 | |
|     inline void reportFatal( std::string const& message ) {
 | |
|         IContext& context = Catch::getCurrentContext();
 | |
|         IResultCapture* resultCapture = context.getResultCapture();
 | |
|         resultCapture->handleFatalErrorCondition( message );
 | |
|     }
 | |
| 
 | |
| } // namespace Catch
 | |
| 
 | |
| #if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
 | |
| #include "catch_windows_h_proxy.h"
 | |
| 
 | |
| #  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
 | |
| 
 | |
| namespace Catch {
 | |
|     struct FatalConditionHandler {
 | |
|         void reset() {}        
 | |
|     };
 | |
| }
 | |
| 
 | |
| #  else // CATCH_CONFIG_WINDOWS_SEH is defined
 | |
| 
 | |
| namespace Catch {
 | |
| 
 | |
|     struct SignalDefs { DWORD id; const char* name; };
 | |
|     extern SignalDefs signalDefs[];
 | |
|     // There is no 1-1 mapping between signals and windows exceptions.
 | |
|     // Windows can easily distinguish between SO and SigSegV,
 | |
|     // but SigInt, SigTerm, etc are handled differently.
 | |
|     SignalDefs signalDefs[] = {
 | |
|         { EXCEPTION_ILLEGAL_INSTRUCTION,  "SIGILL - Illegal instruction signal" },
 | |
|         { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
 | |
|         { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
 | |
|         { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
 | |
|     };
 | |
| 
 | |
|     struct FatalConditionHandler {
 | |
| 
 | |
|         static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
 | |
|             for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
 | |
|                 if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
 | |
|                     reportFatal(signalDefs[i].name);
 | |
|                 }
 | |
|             }
 | |
|             // If its not an exception we care about, pass it along.
 | |
|             // This stops us from eating debugger breaks etc.
 | |
|             return EXCEPTION_CONTINUE_SEARCH;
 | |
|         }
 | |
| 
 | |
|         FatalConditionHandler() {
 | |
|             isSet = true;
 | |
|             // 32k seems enough for Catch to handle stack overflow,
 | |
|             // but the value was found experimentally, so there is no strong guarantee
 | |
|             guaranteeSize = 32 * 1024;
 | |
|             exceptionHandlerHandle = CATCH_NULL;
 | |
|             // Register as first handler in current chain
 | |
|             exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
 | |
|             // Pass in guarantee size to be filled
 | |
|             SetThreadStackGuarantee(&guaranteeSize);
 | |
|         }
 | |
| 
 | |
|         static void reset() {
 | |
|             if (isSet) {
 | |
|                 // Unregister handler and restore the old guarantee
 | |
|                 RemoveVectoredExceptionHandler(exceptionHandlerHandle);
 | |
|                 SetThreadStackGuarantee(&guaranteeSize);
 | |
|                 exceptionHandlerHandle = CATCH_NULL;
 | |
|                 isSet = false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         ~FatalConditionHandler() {
 | |
|             reset();
 | |
|         }
 | |
|     private:
 | |
|         static bool isSet;
 | |
|         static ULONG guaranteeSize;
 | |
|         static PVOID exceptionHandlerHandle;
 | |
|     };
 | |
| 
 | |
|     bool FatalConditionHandler::isSet = false;
 | |
|     ULONG FatalConditionHandler::guaranteeSize = 0;
 | |
|     PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
 | |
| 
 | |
| } // namespace Catch
 | |
| 
 | |
| #  endif // CATCH_CONFIG_WINDOWS_SEH
 | |
| 
 | |
| #else // Not Windows - assumed to be POSIX compatible //////////////////////////
 | |
| 
 | |
| #  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
 | |
| 
 | |
| namespace Catch {
 | |
|     struct FatalConditionHandler {
 | |
|         void reset() {}        
 | |
|     };
 | |
| }
 | |
| 
 | |
| 
 | |
| #  else // CATCH_CONFIG_POSIX_SIGNALS is defined
 | |
| 
 | |
| #include <signal.h>
 | |
| 
 | |
| namespace Catch {
 | |
| 
 | |
|     struct SignalDefs {
 | |
|         int id;
 | |
|         const char* name;
 | |
|     };
 | |
|     extern SignalDefs signalDefs[];
 | |
|     SignalDefs signalDefs[] = {
 | |
|             { SIGINT,  "SIGINT - Terminal interrupt signal" },
 | |
|             { SIGILL,  "SIGILL - Illegal instruction signal" },
 | |
|             { SIGFPE,  "SIGFPE - Floating point error signal" },
 | |
|             { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
 | |
|             { SIGTERM, "SIGTERM - Termination request signal" },
 | |
|             { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
 | |
|     };
 | |
| 
 | |
|     struct FatalConditionHandler {
 | |
| 
 | |
|         static bool isSet;
 | |
|         static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
 | |
|         static stack_t oldSigStack;
 | |
|         static char altStackMem[SIGSTKSZ];
 | |
| 
 | |
|         static void handleSignal( int sig ) {
 | |
|             std::string name = "<unknown signal>";
 | |
|             for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
 | |
|                 SignalDefs &def = signalDefs[i];
 | |
|                 if (sig == def.id) {
 | |
|                     name = def.name;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             reset();
 | |
|             reportFatal(name);
 | |
|             raise( sig );
 | |
|         }
 | |
| 
 | |
|         FatalConditionHandler() {
 | |
|             isSet = true;
 | |
|             stack_t sigStack;
 | |
|             sigStack.ss_sp = altStackMem;
 | |
|             sigStack.ss_size = SIGSTKSZ;
 | |
|             sigStack.ss_flags = 0;
 | |
|             sigaltstack(&sigStack, &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, &oldSigActions[i]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         ~FatalConditionHandler() {
 | |
|             reset();
 | |
|         }
 | |
|         static void reset() {
 | |
|             if( isSet ) {
 | |
|                 // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
 | |
|                 for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
 | |
|                     sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
 | |
|                 }
 | |
|                 // Return the old stack
 | |
|                 sigaltstack(&oldSigStack, CATCH_NULL);
 | |
|                 isSet = false;
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     bool FatalConditionHandler::isSet = false;
 | |
|     struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
 | |
|     stack_t FatalConditionHandler::oldSigStack = {};
 | |
|     char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
 | |
| 
 | |
| 
 | |
| } // namespace Catch
 | |
| 
 | |
| #  endif // CATCH_CONFIG_POSIX_SIGNALS
 | |
| 
 | |
| #endif // not Windows
 | |
| 
 | |
| #endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
 |