1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
16 #include <OSD_Exception_CTRL_BREAK.hxx>
17 #include <Standard_DivideByZero.hxx>
18 #include <Standard_Overflow.hxx>
19 #include <Standard_Assert.hxx>
21 #include <Standard_WarningDisableFunctionCast.hxx>
23 static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs;
24 static Standard_Integer OSD_SignalStackTraceLength = 0;
26 //=======================================================================
27 //function : SignalMode
29 //=======================================================================
30 OSD_SignalMode OSD::SignalMode()
32 return OSD_WasSetSignal;
35 // =======================================================================
36 // function : SignalStackTraceLength
38 // =======================================================================
39 Standard_Integer OSD::SignalStackTraceLength()
41 return OSD_SignalStackTraceLength;
44 // =======================================================================
45 // function : SetSignalStackTraceLength
47 // =======================================================================
48 void OSD::SetSignalStackTraceLength (Standard_Integer theLength)
50 OSD_SignalStackTraceLength = theLength;
54 //---------------------------- Windows NT System --------------------------------
66 #ifndef STATUS_FLOAT_MULTIPLE_FAULTS
68 #define STATUS_FLOAT_MULTIPLE_FAULTS (0xC00002B4L)
69 #define STATUS_FLOAT_MULTIPLE_TRAPS (0xC00002B5L)
72 #include <OSD_Exception_ACCESS_VIOLATION.hxx>
73 #include <OSD_Exception_ARRAY_BOUNDS_EXCEEDED.hxx>
74 #include <OSD_Exception_ILLEGAL_INSTRUCTION.hxx>
75 #include <OSD_Exception_IN_PAGE_ERROR.hxx>
76 #include <OSD_Exception_INT_OVERFLOW.hxx>
77 #include <OSD_Exception_INVALID_DISPOSITION.hxx>
78 #include <OSD_Exception_NONCONTINUABLE_EXCEPTION.hxx>
79 #include <OSD_Exception_PRIV_INSTRUCTION.hxx>
80 #include <OSD_Exception_STACK_OVERFLOW.hxx>
81 #include <OSD_Exception_STATUS_NO_MEMORY.hxx>
83 #include <OSD_Environment.hxx>
84 #include <Standard_Underflow.hxx>
85 #include <Standard_ProgramError.hxx>
86 #include <Standard_Mutex.hxx>
97 static Standard_Boolean fCtrlBrk;
99 static Standard_Boolean fMsgBox;
101 // used to forbid simultaneous execution of setting / executing handlers
102 static Standard_Mutex THE_SIGNAL_MUTEX;
104 static LONG __fastcall _osd_raise (DWORD theCode, const char* theMsg, const char* theStack);
105 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD );
107 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
108 static Standard_Boolean fDbgLoaded;
109 static LONG _osd_debug ( void );
112 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
114 #ifdef OCC_CONVERT_SIGNALS
115 #define THROW_OR_JUMP(Type,Message,Stack) Type::NewInstance(Message,Stack)->Jump()
117 #define THROW_OR_JUMP(Type,Message,Stack) throw Type(Message,Stack)
120 //=======================================================================
121 //function : CallHandler
123 //=======================================================================
124 static LONG CallHandler (DWORD theExceptionCode,
125 EXCEPTION_POINTERS* theExcPtr)
127 ptrdiff_t ExceptionInformation1 = 0, ExceptionInformation0 = 0;
128 if (theExcPtr != NULL)
130 ExceptionInformation1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
131 ExceptionInformation0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
134 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
135 static char aBuffer[2048];
137 bool isFloatErr = false;
139 switch (theExceptionCode)
141 case EXCEPTION_FLT_DENORMAL_OPERAND:
143 strcat_s (aBuffer, sizeof(aBuffer), "FLT DENORMAL OPERAND");
147 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
149 strcat_s (aBuffer, sizeof(aBuffer), "FLT DIVIDE BY ZERO");
153 case EXCEPTION_FLT_INEXACT_RESULT:
155 strcat_s (aBuffer, sizeof(aBuffer), "FLT INEXACT RESULT");
159 case EXCEPTION_FLT_INVALID_OPERATION:
161 strcat_s (aBuffer, sizeof(aBuffer), "FLT INVALID OPERATION");
165 case EXCEPTION_FLT_OVERFLOW:
167 strcat_s (aBuffer, sizeof(aBuffer), "FLT OVERFLOW");
171 case EXCEPTION_FLT_STACK_CHECK:
173 strcat_s (aBuffer, sizeof(aBuffer), "FLT STACK CHECK");
177 case EXCEPTION_FLT_UNDERFLOW:
179 strcat_s (aBuffer, sizeof(aBuffer), "FLT UNDERFLOW");
183 case STATUS_FLOAT_MULTIPLE_TRAPS:
185 strcat_s (aBuffer, sizeof(aBuffer), "FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)");
189 case STATUS_FLOAT_MULTIPLE_FAULTS:
191 strcat_s (aBuffer, sizeof(aBuffer), "FLT MULTIPLE FAULTS");
195 case STATUS_NO_MEMORY:
197 THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )", NULL);
200 case EXCEPTION_ACCESS_VIOLATION:
202 _snprintf_s (aBuffer, sizeof(aBuffer), _TRUNCATE, "%s%s%s0x%.8p%s%s%s", "ACCESS VIOLATION",
203 fMsgBox ? "\n" : " ",
204 "at address ", (void* )ExceptionInformation1,
205 " during '", ExceptionInformation0 ? "WRITE" : "READ", "' operation");
208 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
210 strcat_s (aBuffer, sizeof(aBuffer), "ARRAY BOUNDS EXCEEDED");
213 case EXCEPTION_DATATYPE_MISALIGNMENT:
215 strcat_s (aBuffer, sizeof(aBuffer), "DATATYPE MISALIGNMENT");
218 case EXCEPTION_ILLEGAL_INSTRUCTION:
220 strcat_s (aBuffer, sizeof(aBuffer), "ILLEGAL INSTRUCTION");
223 case EXCEPTION_IN_PAGE_ERROR:
225 strcat_s (aBuffer, sizeof(aBuffer), "IN_PAGE ERROR");
228 case EXCEPTION_INT_DIVIDE_BY_ZERO:
230 strcat_s (aBuffer, sizeof(aBuffer), "INTEGER DIVISION BY ZERO");
233 case EXCEPTION_INT_OVERFLOW:
235 strcat_s (aBuffer, sizeof(aBuffer), "INTEGER OVERFLOW");
238 case EXCEPTION_INVALID_DISPOSITION:
240 strcat_s (aBuffer, sizeof(aBuffer), "INVALID DISPOSITION");
243 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
245 strcat_s (aBuffer, sizeof(aBuffer), "NONCONTINUABLE EXCEPTION");
248 case EXCEPTION_PRIV_INSTRUCTION:
250 strcat_s (aBuffer, sizeof(aBuffer), "PRIVILEGED INSTRUCTION ENCOUNTERED");
253 case EXCEPTION_STACK_OVERFLOW:
255 #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) && !defined(OCCT_UWP)
256 // try recovering from stack overflow: available in MS VC++ 7.0
257 if (!_resetstkoflw())
259 strcat_s (aBuffer, sizeof(aBuffer), "Unrecoverable STACK OVERFLOW");
264 strcat_s (aBuffer, sizeof(aBuffer), "STACK OVERFLOW");
270 _snprintf_s (aBuffer, sizeof(aBuffer), _TRUNCATE, "unknown exception code 0x%x, params 0x%p 0x%p",
271 theExceptionCode, (void* )ExceptionInformation1, (void* )ExceptionInformation0);
275 // reset FPE state (before message box, otherwise it may fail to show up)
278 OSD::SetFloatingSignal (Standard_True);
281 const int aStackLength = OSD_SignalStackTraceLength;
282 const int aStackBufLen = Max (aStackLength * 200, 2048);
283 char* aStackBuffer = aStackLength != 0 ? (char* )alloca (aStackBufLen) : NULL;
284 if (aStackBuffer != NULL)
286 memset (aStackBuffer, 0, aStackBufLen);
287 Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength, theExcPtr->ContextRecord);
290 #if !defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
291 // provide message to the user with possibility to stop
292 if (aBuffer[0] != '\0'
294 && theExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION)
296 MessageBeep (MB_ICONHAND);
297 char aMsgBoxBuffer[2048];
298 strcat_s (aMsgBoxBuffer, sizeof(aMsgBoxBuffer), aBuffer);
299 if (aStackBuffer != NULL)
301 strcat_s (aMsgBoxBuffer, sizeof(aMsgBoxBuffer), aStackBuffer);
303 int aChoice = ::MessageBoxA (0, aMsgBoxBuffer, "OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
304 if (aChoice == IDRETRY)
309 else if (aChoice == IDABORT)
316 return _osd_raise (theExceptionCode, aBuffer, aStackBuffer);
319 //=======================================================================
320 //function : SIGWntHandler
321 //purpose : Will only be used if user calls ::raise() function with
322 // signal type set in OSD::SetSignal() - SIGSEGV, SIGFPE, SIGILL
323 // (the latter will likely be removed in the future)
324 //=======================================================================
325 static void SIGWntHandler (int signum, int sub_code)
327 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
330 if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
331 std::cout << "signal error" << std::endl ;
334 CallHandler (EXCEPTION_FLT_INVALID_OPERATION, NULL);
337 CallHandler (EXCEPTION_FLT_DENORMAL_OPERAND, NULL);
339 case _FPE_ZERODIVIDE :
340 CallHandler (EXCEPTION_FLT_DIVIDE_BY_ZERO, NULL);
343 CallHandler (EXCEPTION_FLT_OVERFLOW, NULL);
345 case _FPE_UNDERFLOW :
346 CallHandler (EXCEPTION_FLT_UNDERFLOW, NULL);
349 CallHandler (EXCEPTION_FLT_INEXACT_RESULT, NULL);
352 std::cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << std::endl;
353 THROW_OR_JUMP (Standard_NumericError, "Floating Point Error", NULL);
358 if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
359 std::cout << "signal error" << std::endl ;
360 CallHandler (EXCEPTION_ACCESS_VIOLATION, NULL);
363 if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
364 std::cout << "signal error" << std::endl ;
365 CallHandler (EXCEPTION_ILLEGAL_INSTRUCTION, NULL);
368 std::cout << "SIGWntHandler unexpected signal : " << signum << std::endl ;
376 //=======================================================================
377 //function : TranslateSE
378 //purpose : Translate Structural Exceptions into C++ exceptions
379 // Will be used when user's code is compiled with /EHa option
380 //=======================================================================
382 // If this file compiled with the default MSVC options for exception
383 // handling (/GX or /EHsc) then the following warning is issued:
384 // warning C4535: calling _set_se_translator() requires /EHa
385 // However it is correctly inserted and used when user's code compiled with /EHa.
386 // So, here we disable the warning.
387 #pragma warning (disable:4535)
389 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
391 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
392 CallHandler (theCode, theExcPtr);
396 //=======================================================================
397 //function : WntHandler
398 //purpose : Will be used when user's code is compiled with /EHs
399 // option and unless user sets his own exception handler with
400 // ::SetUnhandledExceptionFilter().
401 //=======================================================================
402 static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
404 DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
405 return CallHandler (dwExceptionCode, lpXP);
408 //=======================================================================
409 //function : SetFloatingSignal
411 //=======================================================================
412 void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal)
417 // Note: zero bit means exception will be raised
418 _controlfp (theFloatingSignal ? 0 : _OSD_FPX, _OSD_FPX);
421 //=======================================================================
422 //function : ToCatchFloatingSignals
424 //=======================================================================
425 Standard_Boolean OSD::ToCatchFloatingSignals()
427 // return true if at least one of bits within _OSD_FPX
428 // is unset, which means relevant FPE will raise exception
429 int aControlWord = _controlfp (0, 0);
430 return (_OSD_FPX & ~aControlWord) != 0;
433 //=======================================================================
434 //function : SetThreadLocalSignal
436 //=======================================================================
437 void OSD::SetThreadLocalSignal (OSD_SignalMode theSignalMode,
438 Standard_Boolean theFloatingSignal)
441 _se_translator_function aPreviousFunc = NULL;
442 if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
443 aPreviousFunc = _set_se_translator(TranslateSE);
444 if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL))
445 _set_se_translator(aPreviousFunc);
449 SetFloatingSignal (theFloatingSignal);
452 //=======================================================================
453 //function : SetSignal
455 //=======================================================================
456 void OSD::SetSignal (OSD_SignalMode theSignalMode,
457 Standard_Boolean theFloatingSignal)
459 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
460 OSD_WasSetSignal = theSignalMode;
462 #if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
463 OSD_Environment env ("CSF_DEBUG_MODE");
464 TCollection_AsciiString val = env.Value();
467 std::cout << "Environment variable CSF_DEBUG_MODE set.\n";
468 fMsgBox = Standard_True;
469 if (OSD_SignalStackTraceLength == 0)
471 // enable stack trace if CSF_DEBUG_MODE is set
472 OSD_SignalStackTraceLength = 10;
477 fMsgBox = Standard_False;
480 // Set exception handler (ignored when running under debugger). It will be used in most cases
481 // when user's code is compiled with /EHs
482 // Replaces the existing top-level exception filter for all existing and all future threads
483 // in the calling process
485 LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFunc = NULL;
486 if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
488 aPreviousFunc = ::SetUnhandledExceptionFilter(WntHandler);
490 if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL))
492 ::SetUnhandledExceptionFilter(aPreviousFunc);
495 #endif // NTDDI_WIN10_TH2
497 // Signal handlers will only be used when function ::raise() is called
499 const int aSignalTypes[NBSIG] = { SIGSEGV, SIGILL, SIGFPE };
500 for (int i = 0; i < NBSIG; ++i)
502 typedef void (*SignalFuncType)(int); // same as _crt_signal_t available since vc14
503 SignalFuncType aPreviousFunc = SIG_DFL;
504 if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
506 aPreviousFunc = signal(aSignalTypes[i], (SignalFuncType)SIGWntHandler);
508 if (theSignalMode == OSD_SignalMode_Unset ||
509 (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != SIG_DFL && aPreviousFunc != SIG_ERR))
511 aPreviousFunc = signal(aSignalTypes[i], aPreviousFunc);
513 Standard_ASSERT(aPreviousFunc != SIG_ERR, "signal() failed", std::cout << "OSD::SetSignal(): signal() returns SIG_ERR");
516 // Set Ctrl-C and Ctrl-Break handler
517 fCtrlBrk = Standard_False;
519 if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
521 SetConsoleCtrlHandler(&_osd_ctrl_break_handler, true);
523 else if (theSignalMode == OSD_SignalMode_Unset)
525 SetConsoleCtrlHandler(&_osd_ctrl_break_handler, false);
529 SetThreadLocalSignal (theSignalMode, theFloatingSignal);
532 //============================================================================
534 //============================================================================
535 void OSD::ControlBreak () {
537 fCtrlBrk = Standard_False;
538 throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
540 } // end OSD :: ControlBreak
543 //============================================================================
544 //==== _osd_ctrl_break_handler
545 //============================================================================
546 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
547 if ( dwCode == CTRL_C_EVENT || dwCode == CTRL_BREAK_EVENT ) {
548 MessageBeep ( MB_ICONEXCLAMATION );
549 fCtrlBrk = Standard_True;
554 } // end _osd_ctrl_break_handler
557 //============================================================================
559 //============================================================================
560 static LONG __fastcall _osd_raise (DWORD theCode, const char* theMsg, const char* theStack)
562 const char* aMsg = theMsg;
563 if (aMsg[0] == '\x03')
570 case EXCEPTION_ACCESS_VIOLATION:
571 THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, aMsg, theStack);
573 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
574 THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, aMsg, theStack);
576 case EXCEPTION_DATATYPE_MISALIGNMENT:
577 THROW_OR_JUMP (Standard_ProgramError, aMsg, theStack);
579 case EXCEPTION_ILLEGAL_INSTRUCTION:
580 THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, aMsg, theStack);
582 case EXCEPTION_IN_PAGE_ERROR:
583 THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, aMsg, theStack);
585 case EXCEPTION_INT_DIVIDE_BY_ZERO:
586 THROW_OR_JUMP (Standard_DivideByZero, aMsg, theStack);
588 case EXCEPTION_INT_OVERFLOW:
589 THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, aMsg, theStack);
591 case EXCEPTION_INVALID_DISPOSITION:
592 THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, aMsg, theStack);
594 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
595 THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, aMsg, theStack);
597 case EXCEPTION_PRIV_INSTRUCTION:
598 THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, aMsg, theStack);
600 case EXCEPTION_STACK_OVERFLOW:
601 THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, aMsg, theStack);
603 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
604 THROW_OR_JUMP (Standard_DivideByZero, aMsg, theStack);
606 case EXCEPTION_FLT_STACK_CHECK:
607 case EXCEPTION_FLT_OVERFLOW:
608 THROW_OR_JUMP (Standard_Overflow, aMsg, theStack);
610 case EXCEPTION_FLT_UNDERFLOW:
611 THROW_OR_JUMP (Standard_Underflow, aMsg, theStack);
613 case EXCEPTION_FLT_INVALID_OPERATION:
614 case EXCEPTION_FLT_DENORMAL_OPERAND:
615 case EXCEPTION_FLT_INEXACT_RESULT:
616 case STATUS_FLOAT_MULTIPLE_TRAPS:
617 case STATUS_FLOAT_MULTIPLE_FAULTS:
618 THROW_OR_JUMP (Standard_NumericError, aMsg, theStack);
623 return EXCEPTION_EXECUTE_HANDLER;
626 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
627 //============================================================================
629 //============================================================================
630 LONG _osd_debug ( void ) {
637 HANDLE hEvent = INVALID_HANDLE_VALUE;
640 TCHAR keyValue[ MAX_PATH ];
641 TCHAR cmdLine[ MAX_PATH ];
642 SECURITY_ATTRIBUTES sa;
643 PROCESS_INFORMATION pi;
650 TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
655 dwValueLen = sizeof ( keyValue );
657 if ( RegQueryValueEx (
658 hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
662 sa.nLength = sizeof ( SECURITY_ATTRIBUTES );
663 sa.lpSecurityDescriptor = NULL;
664 sa.bInheritHandle = TRUE;
666 if ( ( hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL ) ) == NULL ) __leave;
668 StringCchPrintf(cmdLine, _countof(cmdLine), keyValue, GetCurrentProcessId(), hEvent);
670 ZeroMemory ( &si, sizeof ( STARTUPINFO ) );
672 si.cb = sizeof ( STARTUPINFO );
673 si.dwFlags = STARTF_FORCEONFEEDBACK;
675 // std::cout << "_osd_debug -> CreateProcess" << std::endl ;
676 if ( !CreateProcess (
677 NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
682 // std::cout << "_osd_debug -> WaitForSingleObject " << std::endl ;
683 WaitForSingleObject ( hEvent, INFINITE );
684 // std::cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << std::endl ;
686 CloseHandle ( pi.hProcess );
687 CloseHandle ( pi.hThread );
689 // std::cout << "_osd_debug fDbgLoaded " << std::endl ;
696 // std::cout << "_osd_debug -> CloseHandle(hKey) " << std::endl ;
697 if ( hKey != INVALID_HANDLE_VALUE ) CloseHandle ( hKey );
698 // std::cout << "_osd_debug -> CloseHandle(hEvent) " << std::endl ;
699 if ( hEvent != INVALID_HANDLE_VALUE ) CloseHandle ( hEvent );
700 // std::cout << "_osd_debug end __finally " << std::endl ;
706 action = fDbgLoaded ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
707 // std::cout << "_osd_debug return " << action << " EXCEPTION_CONTINUE_EXECUTION("
708 // << EXCEPTION_CONTINUE_EXECUTION << ")" << std::endl ;
712 #endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
716 //---------- All Systems except Windows NT : ----------------------------------
720 #include <OSD_WhoAmI.hxx>
721 #include <OSD_SIGHUP.hxx>
722 #include <OSD_SIGINT.hxx>
723 #include <OSD_SIGQUIT.hxx>
724 #include <OSD_SIGILL.hxx>
725 #include <OSD_SIGKILL.hxx>
726 #include <OSD_SIGBUS.hxx>
727 #include <OSD_SIGSEGV.hxx>
728 #include <OSD_SIGSYS.hxx>
729 #include <Standard_NumericError.hxx>
731 #include <Standard_ErrorHandler.hxx>
741 // variable signalling that Control-C has been pressed (SIGINT signal)
742 static Standard_Boolean fCtrlBrk;
744 //const OSD_WhoAmI Iam = OSD_WPackage;
746 typedef void (ACT_SIGIO_HANDLER)(void) ;
747 ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
754 # include <sys/siginfo.h>
757 typedef void (* SIG_PFV) (int);
761 #if !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
762 #include <sys/signal.h>
765 # define _OSD_FPX (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW)
767 //============================================================================
769 //==== Catch the different signals:
770 //==== 1- The Fatal signals, which cause the end of process:
771 //==== 2- The exceptions which are "signaled" by Raise.
772 //==== The Fatal Signals:
773 //==== SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGKILL, SIGBUS, SIGSYS
774 //==== The Exceptions:
776 //==== (SUN versions)
777 //==== FPE_INTOVF_TRAP // ..... integer overflow
778 //==== FPE_INTDIV_TRAP // ..... integer divide by zero
779 //==== FPE_FLTINEX_TRAP // ..... [floating inexact result]
780 //==== FPE_FLTDIV_TRAP // ..... [floating divide by zero]
781 //==== FPE_FLTUND_TRAP // ..... [floating underflow]
782 //==== FPE_FLTOPER_TRAP // ..... [floating inexact result]
783 //==== FPE_FLTOVF_TRAP // ..... [floating overflow]
784 //==== SIGSEGV is handled by "SegvHandler()"
785 //============================================================================
787 static void Handler (const int theSignal, siginfo_t */*theSigInfo*/, const Standard_Address /*theContext*/)
789 static void Handler (const int theSignal)
792 struct sigaction oldact, act;
793 // re-install the signal
794 if ( ! sigaction (theSignal, NULL, &oldact) ) {
795 // std::cout << " signal is " << theSignal << " handler is " << oldact.sa_handler << std::endl;
796 if (sigaction (theSignal, &oldact, &act)) perror ("sigaction");
799 perror ("sigaction");
802 // std::cout << "OSD::Handler: signal " << (int) theSignal << " occurred inside a try block " << std::endl ;
803 if ( ADR_ACT_SIGIO_HANDLER != NULL )
804 (*ADR_ACT_SIGIO_HANDLER)() ;
810 OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
814 // For safe handling of Control-C as stop event, arm a variable but do not
815 // generate longjump (we are out of context anyway)
816 fCtrlBrk = Standard_True;
817 // OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
821 OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
825 OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
829 OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
833 sigaddset(&set, SIGBUS);
834 sigprocmask(SIG_UNBLOCK, &set, NULL) ;
835 OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
839 OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
844 OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
849 sigaddset(&set, SIGFPE);
850 sigprocmask(SIG_UNBLOCK, &set, NULL) ;
852 OSD::SetFloatingSignal (Standard_True);
854 #if (!defined (__sun)) && (!defined(SOLARIS))
855 Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
860 switch(aSigInfo->si_code) {
861 case FPE_FLTDIV_TRAP :
862 Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
864 case FPE_INTDIV_TRAP :
865 Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
867 case FPE_FLTOVF_TRAP :
868 Standard_Overflow::NewInstance("Floating Overflow")->Jump();
870 case FPE_INTOVF_TRAP :
871 Standard_Overflow::NewInstance("Integer Overflow")->Jump();
873 case FPE_FLTUND_TRAP :
874 Standard_NumericError::NewInstance("Floating Underflow")->Jump();
876 case FPE_FLTRES_TRAP:
877 Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
879 case FPE_FLTINV_TRAP :
880 Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
883 Standard_NumericError::NewInstance("Numeric Error")->Jump();
887 Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
893 std::cout << "Unexpected signal " << theSignal << std::endl ;
899 //============================================================================
901 //============================================================================
904 static void SegvHandler(const int theSignal,
905 siginfo_t* theSigInfo,
906 const Standard_Address theContext)
910 if (theSigInfo != NULL)
914 sigaddset (&set, SIGSEGV);
915 sigprocmask (SIG_UNBLOCK, &set, NULL);
916 void* anAddress = theSigInfo->si_addr;
919 sprintf (aMsg, "SIGSEGV 'segmentation violation' detected. Address %lx.", (long )anAddress);
921 const int aStackLength = OSD_SignalStackTraceLength;
922 const int aStackBufLen = Max (aStackLength * 200, 2048);
923 char* aStackBuffer = aStackLength != 0 ? (char* )alloca (aStackBufLen) : NULL;
924 if (aStackBuffer != NULL)
926 memset (aStackBuffer, 0, aStackBufLen);
927 Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength);
930 OSD_SIGSEGV::NewInstance (aMsg, aStackBuffer)->Jump();
936 std::cout << "Wrong undefined address." << std::endl;
942 #elif defined (_hpux) || defined(HPUX)
943 // Not ACTIVE ? SA_SIGINFO is defined on SUN, OSF, SGI and HP (and Linux) !
944 // pour version 09.07
946 static void SegvHandler(const int theSignal,
947 siginfo_t* theSigInfo,
948 const Standard_Address theContext)
950 if (theContext != NULL)
952 unsigned long aSpace = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20;
953 unsigned long anOffset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21;
956 sprintf (aMsg, "SIGSEGV 'segmentation violation' detected. Address %lx", anOffset);
957 OSD_SIGSEGV::NewInstance (aMsg)->Jump();
963 std::cout << "Wrong undefined address." << std::endl;
971 //=======================================================================
972 //function : SetFloatingSignal
974 //=======================================================================
975 void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal)
977 #if defined (__linux__)
978 feclearexcept (FE_ALL_EXCEPT);
979 if (theFloatingSignal)
981 feenableexcept (_OSD_FPX);
985 fedisableexcept (_OSD_FPX);
987 #elif defined (__sun) || defined (SOLARIS)
989 sigfpe_handler_type anFpeHandler = (theFloatingSignal ? (sigfpe_handler_type)Handler : NULL);
990 aSunStat = ieee_handler ("set", "invalid", anFpeHandler);
991 aSunStat = ieee_handler ("set", "division", anFpeHandler) || aSunStat;
992 aSunStat = ieee_handler ("set", "overflow", anFpeHandler) || aSunStat;
996 std::cerr << "ieee_handler does not work !!! KO\n";
1000 (void)theFloatingSignal;
1004 //=======================================================================
1005 //function : ToCatchFloatingSignals
1007 //=======================================================================
1008 Standard_Boolean OSD::ToCatchFloatingSignals()
1010 #if defined (__linux__)
1011 return (fegetexcept() & _OSD_FPX) != 0;
1013 return Standard_False;
1017 //=======================================================================
1018 //function : SetThreadLocalSignal
1020 //=======================================================================
1021 void OSD::SetThreadLocalSignal (OSD_SignalMode /*theSignalMode*/,
1022 Standard_Boolean theFloatingSignal)
1024 SetFloatingSignal (theFloatingSignal);
1027 //============================================================================
1029 //==== Set the different signals:
1030 //============================================================================
1032 void OSD::SetSignal (OSD_SignalMode theSignalMode,
1033 Standard_Boolean theFloatingSignal)
1035 SetFloatingSignal (theFloatingSignal);
1037 OSD_WasSetSignal = theSignalMode;
1038 if (theSignalMode == OSD_SignalMode_AsIs)
1040 return; // nothing to be done with signal handlers
1043 // Prepare signal descriptors
1044 struct sigaction anActSet, anActDfl, anActOld;
1045 sigemptyset(&anActSet.sa_mask);
1046 sigemptyset(&anActDfl.sa_mask);
1047 sigemptyset(&anActOld.sa_mask);
1049 anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = SA_RESTART;
1051 anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = 0;
1054 anActSet.sa_flags = anActSet.sa_flags | SA_SIGINFO;
1055 anActSet.sa_sigaction = Handler;
1057 anActSet.sa_handler = Handler;
1059 anActDfl.sa_handler = SIG_DFL;
1061 // Set signal handlers; NB: SIGSEGV must be the last one!
1062 const int NBSIG = 8;
1063 const int aSignalTypes[NBSIG] = { SIGFPE, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSYS, SIGSEGV };
1064 for (int i = 0; i < NBSIG; ++i)
1066 // SIGSEGV has special handler
1067 if (aSignalTypes[i] == SIGSEGV)
1070 anActSet.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
1072 anActSet.sa_handler = /*(SIG_PFV)*/ SegvHandler;
1076 // set handler according to specified mode and current handler
1078 if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
1080 retcode = sigaction (aSignalTypes[i], &anActSet, &anActOld);
1082 else if (theSignalMode == OSD_SignalMode_Unset)
1084 retcode = sigaction (aSignalTypes[i], &anActDfl, &anActOld);
1086 if (theSignalMode == OSD_SignalMode_SetUnhandled && retcode == 0 && anActOld.sa_handler != SIG_DFL)
1088 struct sigaction anActOld2;
1089 sigemptyset(&anActOld2.sa_mask);
1090 retcode = sigaction (aSignalTypes[i], &anActOld, &anActOld2);
1092 Standard_ASSERT(retcode == 0, "sigaction() failed", std::cout << "OSD::SetSignal(): sigaction() failed for " << aSignalTypes[i] << std::endl);
1096 //============================================================================
1098 //============================================================================
1100 void OSD :: ControlBreak ()
1103 fCtrlBrk = Standard_False;
1104 throw OSD_Exception_CTRL_BREAK ("*** INTERRUPT ***");