void NORETURN sm_crash( std::string const &reason ) { #if ( defined(_WINDOWS) && defined(CRASH_HANDLER) ) || defined(MACOSX) || defined(_XDBG) /* If we're being debugged, throw a debug break so it'll suspend the process. */ if( IsDebuggerPresent() ) { DebugBreak(); for(;;); /* don't return */ } #endif #if defined(CRASH_HANDLER) CrashHandler::ForceCrash( reason ); #else *(char*)0=0; /* This isn't actually reached. We just do this to convince the compiler that the * function really doesn't return. */ for(;;); #endif #if defined(_WINDOWS) /* Do something after the above, so the call/return isn't optimized to a jmp; that * way, this function will appear in backtrace stack traces. */ #if defined(_MSC_VER) _asm nop; #elif defined(__GNUC__) // MinGW or similar asm("nop"); #endif #else _exit( 1 ); #endif }
/* This is no longer actually implemented by throwing an exception, but it acts * the same way to code in practice. */ void RageException::Throw( const char *sFmt, ... ) { va_list va; va_start( va, sFmt ); RString error = vssprintf( sFmt, va ); va_end( va ); RString msg = ssprintf( "\n" "//////////////////////////////////////////////////////\n" "Exception: %s\n" "//////////////////////////////////////////////////////\n", error.c_str() ); if( LOG ) { LOG->Trace( "%s", msg.c_str() ); LOG->Flush(); } else { puts( msg ); fflush( stdout ); } #if (defined(WINDOWS) && defined(DEBUG)) || defined(_XDBG) || defined(MACOSX) if( IsDebuggerPresent() ) DebugBreak(); #endif ASSERT_M( g_HandlerThreadID == RageThread::GetInvalidThreadID() || g_HandlerThreadID == RageThread::GetCurrentThreadID(), ssprintf("RageException::Throw() on another thread: %s", error.c_str()) ); if( g_CleanupHandler != NULL ) g_CleanupHandler( error ); exit(1); }