0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / OSD / OSD_signal.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
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.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14
15 #include <OSD.hxx>
16 #include <OSD_Exception_CTRL_BREAK.hxx>
17 #include <Standard_DivideByZero.hxx>
18 #include <Standard_Overflow.hxx>
19 #include <Standard_Assert.hxx>
20
21 #include <Standard_WarningDisableFunctionCast.hxx>
22
23 static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs;
24 static Standard_Integer OSD_SignalStackTraceLength = 0;
25
26 //=======================================================================
27 //function : SignalMode
28 //purpose  :
29 //=======================================================================
30 OSD_SignalMode OSD::SignalMode()
31 {
32   return OSD_WasSetSignal;
33 }
34
35 // =======================================================================
36 // function : SignalStackTraceLength
37 // purpose  :
38 // =======================================================================
39 Standard_Integer OSD::SignalStackTraceLength()
40 {
41   return OSD_SignalStackTraceLength;
42 }
43
44 // =======================================================================
45 // function : SetSignalStackTraceLength
46 // purpose  :
47 // =======================================================================
48 void OSD::SetSignalStackTraceLength (Standard_Integer theLength)
49 {
50   OSD_SignalStackTraceLength = theLength;
51 }
52
53 #ifdef _WIN32
54 //---------------------------- Windows NT System --------------------------------
55
56 #ifdef NOUSER
57 #undef NOUSER
58 #endif
59 #ifdef NONLS
60 #undef NONLS
61 #endif
62 #include <windows.h>
63
64 #include <strsafe.h>
65
66 #ifndef STATUS_FLOAT_MULTIPLE_FAULTS
67   // <ntstatus.h>
68   #define STATUS_FLOAT_MULTIPLE_FAULTS     (0xC00002B4L)
69   #define STATUS_FLOAT_MULTIPLE_TRAPS      (0xC00002B5L)
70 #endif
71
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>
82
83 #include <OSD_Environment.hxx>
84 #include <Standard_Underflow.hxx>
85 #include <Standard_ProgramError.hxx>
86 #include <Standard_Mutex.hxx>
87
88 #ifdef _MSC_VER
89 #include <eh.h>
90 #include <malloc.h>
91 #endif
92
93 #include <process.h>
94 #include <signal.h>
95 #include <float.h>
96
97 static Standard_Boolean fCtrlBrk;
98
99 static Standard_Boolean fMsgBox;
100
101 // used to forbid simultaneous execution of setting / executing handlers
102 static Standard_Mutex THE_SIGNAL_MUTEX;
103
104 static LONG __fastcall _osd_raise (DWORD theCode, const char* theMsg, const char* theStack);
105 static BOOL WINAPI     _osd_ctrl_break_handler ( DWORD );
106
107 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
108 static Standard_Boolean fDbgLoaded;
109 static LONG _osd_debug   ( void );
110 #endif
111
112 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
113
114 #ifdef OCC_CONVERT_SIGNALS
115 #define THROW_OR_JUMP(Type,Message,Stack) Type::NewInstance(Message,Stack)->Jump()
116 #else
117 #define THROW_OR_JUMP(Type,Message,Stack) throw Type(Message,Stack)
118 #endif
119
120 //=======================================================================
121 //function : CallHandler
122 //purpose  :
123 //=======================================================================
124 static LONG CallHandler (DWORD theExceptionCode,
125                          EXCEPTION_POINTERS* theExcPtr)
126 {
127   ptrdiff_t ExceptionInformation1 = 0, ExceptionInformation0 = 0;
128   if (theExcPtr != NULL)
129   {
130     ExceptionInformation1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
131     ExceptionInformation0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
132   }
133
134   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
135   static char aBuffer[2048];
136
137   bool isFloatErr = false;
138   aBuffer[0] = '\0';
139   switch (theExceptionCode)
140   {
141     case EXCEPTION_FLT_DENORMAL_OPERAND:
142     {
143       strcat_s (aBuffer, sizeof(aBuffer), "FLT DENORMAL OPERAND");
144       isFloatErr = true;
145       break;
146     }
147     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
148     {
149       strcat_s (aBuffer, sizeof(aBuffer), "FLT DIVIDE BY ZERO");
150       isFloatErr = true;
151       break;
152      }
153     case EXCEPTION_FLT_INEXACT_RESULT:
154     {
155       strcat_s (aBuffer, sizeof(aBuffer), "FLT INEXACT RESULT");
156       isFloatErr = true;
157       break;
158     }
159     case EXCEPTION_FLT_INVALID_OPERATION:
160     {
161       strcat_s (aBuffer, sizeof(aBuffer), "FLT INVALID OPERATION");
162       isFloatErr = true;
163       break;
164     }
165     case EXCEPTION_FLT_OVERFLOW:
166     {
167       strcat_s (aBuffer, sizeof(aBuffer), "FLT OVERFLOW");
168       isFloatErr = true;
169       break;
170     }
171     case EXCEPTION_FLT_STACK_CHECK:
172     {
173       strcat_s (aBuffer, sizeof(aBuffer), "FLT STACK CHECK");
174       isFloatErr = true;
175       break;
176     }
177     case EXCEPTION_FLT_UNDERFLOW:
178     {
179       strcat_s (aBuffer, sizeof(aBuffer), "FLT UNDERFLOW");
180       isFloatErr = true;
181       break;
182     }
183     case STATUS_FLOAT_MULTIPLE_TRAPS:
184     {
185       strcat_s (aBuffer, sizeof(aBuffer), "FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)");
186       isFloatErr = true;
187       break;
188     }
189     case STATUS_FLOAT_MULTIPLE_FAULTS:
190     {
191       strcat_s (aBuffer, sizeof(aBuffer), "FLT MULTIPLE FAULTS");
192       isFloatErr = true;
193       break;
194     }
195     case STATUS_NO_MEMORY:
196     {
197       THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )", NULL);
198       break;
199     }
200     case EXCEPTION_ACCESS_VIOLATION:
201     {
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");
206       break;
207     }
208     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
209     {
210       strcat_s (aBuffer, sizeof(aBuffer), "ARRAY BOUNDS EXCEEDED");
211       break;
212     }
213     case EXCEPTION_DATATYPE_MISALIGNMENT:
214     {
215       strcat_s (aBuffer, sizeof(aBuffer), "DATATYPE MISALIGNMENT");
216       break;
217     }
218     case EXCEPTION_ILLEGAL_INSTRUCTION:
219     {
220       strcat_s (aBuffer, sizeof(aBuffer), "ILLEGAL INSTRUCTION");
221       break;
222     }
223     case EXCEPTION_IN_PAGE_ERROR:
224     {
225       strcat_s (aBuffer, sizeof(aBuffer), "IN_PAGE ERROR");
226       break;
227     }
228     case EXCEPTION_INT_DIVIDE_BY_ZERO:
229     {
230       strcat_s (aBuffer, sizeof(aBuffer), "INTEGER DIVISION BY ZERO");
231       break;
232     }
233     case EXCEPTION_INT_OVERFLOW:
234     {
235       strcat_s (aBuffer, sizeof(aBuffer), "INTEGER OVERFLOW");
236       break;
237     }
238     case EXCEPTION_INVALID_DISPOSITION:
239     {
240       strcat_s (aBuffer, sizeof(aBuffer), "INVALID DISPOSITION");
241       break;
242     }
243     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
244     {
245       strcat_s (aBuffer, sizeof(aBuffer), "NONCONTINUABLE EXCEPTION");
246       break;
247     }
248     case EXCEPTION_PRIV_INSTRUCTION:
249     {
250       strcat_s (aBuffer, sizeof(aBuffer), "PRIVILEGED INSTRUCTION ENCOUNTERED");
251       break;
252     }
253     case EXCEPTION_STACK_OVERFLOW:
254     {
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())
258       {
259         strcat_s (aBuffer, sizeof(aBuffer), "Unrecoverable STACK OVERFLOW");
260       }
261       else
262 #endif
263       {
264         strcat_s (aBuffer, sizeof(aBuffer), "STACK OVERFLOW");
265       }
266       break;
267     }
268     default:
269     {
270       _snprintf_s (aBuffer, sizeof(aBuffer), _TRUNCATE, "unknown exception code 0x%x, params 0x%p 0x%p",
271                    theExceptionCode, (void* )ExceptionInformation1, (void* )ExceptionInformation0);
272     }
273   }
274
275   // reset FPE state (before message box, otherwise it may fail to show up)
276   if (isFloatErr)
277   {
278     OSD::SetFloatingSignal (Standard_True);
279   }
280
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)
285   {
286     memset (aStackBuffer, 0, aStackBufLen);
287     Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength, theExcPtr->ContextRecord);
288   }
289
290 #if !defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
291   // provide message to the user with possibility to stop
292   if (aBuffer[0] != '\0'
293    && fMsgBox
294    && theExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION)
295   {
296     MessageBeep (MB_ICONHAND);
297     char aMsgBoxBuffer[2048];
298     strcat_s (aMsgBoxBuffer, sizeof(aMsgBoxBuffer), aBuffer);
299     if (aStackBuffer != NULL)
300     {
301       strcat_s (aMsgBoxBuffer, sizeof(aMsgBoxBuffer), aStackBuffer);
302     }
303     int aChoice = ::MessageBoxA (0, aMsgBoxBuffer, "OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
304     if (aChoice == IDRETRY)
305     {
306       _osd_debug();
307       DebugBreak();
308     }
309     else if (aChoice == IDABORT)
310     {
311       exit (0xFFFF);
312     }
313   }
314 #endif
315
316   return _osd_raise (theExceptionCode, aBuffer, aStackBuffer);
317 }
318
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)
326 {
327   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
328   switch( signum ) {
329     case SIGFPE :
330       if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
331         std::cout << "signal error" << std::endl ;
332       switch( sub_code ) {
333         case _FPE_INVALID :
334           CallHandler (EXCEPTION_FLT_INVALID_OPERATION, NULL);
335           break ;
336         case _FPE_DENORMAL :
337           CallHandler (EXCEPTION_FLT_DENORMAL_OPERAND, NULL);
338           break ;
339         case _FPE_ZERODIVIDE :
340           CallHandler (EXCEPTION_FLT_DIVIDE_BY_ZERO, NULL);
341           break ;
342         case _FPE_OVERFLOW :
343           CallHandler (EXCEPTION_FLT_OVERFLOW, NULL);
344           break ;
345         case _FPE_UNDERFLOW :
346           CallHandler (EXCEPTION_FLT_UNDERFLOW, NULL);
347           break ;
348         case _FPE_INEXACT :
349           CallHandler (EXCEPTION_FLT_INEXACT_RESULT, NULL);
350           break ;
351         default:
352           std::cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << std::endl;
353           THROW_OR_JUMP (Standard_NumericError, "Floating Point Error", NULL);
354           break ;
355       }
356       break ;
357     case SIGSEGV :
358       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
359         std::cout << "signal error" << std::endl ;
360       CallHandler (EXCEPTION_ACCESS_VIOLATION, NULL);
361       break ;
362     case SIGILL :
363       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
364         std::cout << "signal error" << std::endl ;
365       CallHandler (EXCEPTION_ILLEGAL_INSTRUCTION, NULL);
366       break ;
367     default:
368       std::cout << "SIGWntHandler unexpected signal : " << signum << std::endl ;
369       break ;
370   }
371 #ifndef OCCT_UWP
372   DebugBreak ();
373 #endif
374 }
375
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 //=======================================================================
381 #ifdef _MSC_VER
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)
388
389 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
390 {
391   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
392   CallHandler (theCode, theExcPtr);
393 }
394 #endif
395
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)
403 {
404   DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
405   return CallHandler (dwExceptionCode, lpXP);
406 }
407
408 //=======================================================================
409 //function : SetFloatingSignal
410 //purpose  :
411 //=======================================================================
412 void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal)
413 {
414   _fpreset();
415   _clearfp();
416   
417   // Note: zero bit means exception will be raised
418   _controlfp (theFloatingSignal ? 0 : _OSD_FPX, _OSD_FPX);
419 }
420
421 //=======================================================================
422 //function : ToCatchFloatingSignals
423 //purpose  :
424 //=======================================================================
425 Standard_Boolean OSD::ToCatchFloatingSignals()
426 {
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;
431 }
432
433 //=======================================================================
434 //function : SetThreadLocalSignal
435 //purpose  :
436 //=======================================================================
437 void OSD::SetThreadLocalSignal (OSD_SignalMode theSignalMode,
438                                 Standard_Boolean theFloatingSignal)
439 {
440 #ifdef _MSC_VER
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);
446 #else
447   (void)theSignalMode;
448 #endif
449   SetFloatingSignal (theFloatingSignal);
450 }
451
452 //=======================================================================
453 //function : SetSignal
454 //purpose  :
455 //=======================================================================
456 void OSD::SetSignal (OSD_SignalMode theSignalMode,
457                      Standard_Boolean theFloatingSignal)
458 {
459   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
460   OSD_WasSetSignal = theSignalMode;
461
462 #if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
463   OSD_Environment env ("CSF_DEBUG_MODE");
464   TCollection_AsciiString val = env.Value();
465   if (!env.Failed())
466   {
467     std::cout << "Environment variable CSF_DEBUG_MODE set.\n";
468     fMsgBox = Standard_True;
469     if (OSD_SignalStackTraceLength == 0)
470     {
471       // enable stack trace if CSF_DEBUG_MODE is set
472       OSD_SignalStackTraceLength = 10;
473     }
474   }
475   else
476   {
477     fMsgBox = Standard_False;
478   }
479
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
484   {
485     LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFunc = NULL;
486     if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
487     {
488       aPreviousFunc = ::SetUnhandledExceptionFilter(WntHandler);
489     }
490     if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL))
491     {
492       ::SetUnhandledExceptionFilter(aPreviousFunc);
493     }
494   }
495 #endif // NTDDI_WIN10_TH2
496
497   // Signal handlers will only be used when function ::raise() is called
498   const int NBSIG = 3;
499   const int aSignalTypes[NBSIG] = { SIGSEGV, SIGILL, SIGFPE };
500   for (int i = 0; i < NBSIG; ++i)
501   {
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)
505     {
506       aPreviousFunc = signal(aSignalTypes[i], (SignalFuncType)SIGWntHandler);
507     }
508     if (theSignalMode == OSD_SignalMode_Unset ||
509         (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != SIG_DFL && aPreviousFunc != SIG_ERR))
510     {
511       aPreviousFunc = signal(aSignalTypes[i], aPreviousFunc);
512     }
513     Standard_ASSERT(aPreviousFunc != SIG_ERR, "signal() failed", std::cout << "OSD::SetSignal(): signal() returns SIG_ERR");
514   }
515
516   // Set Ctrl-C and Ctrl-Break handler
517   fCtrlBrk = Standard_False;
518 #ifndef OCCT_UWP
519   if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
520   {
521     SetConsoleCtrlHandler(&_osd_ctrl_break_handler, true);
522   }
523   else if (theSignalMode == OSD_SignalMode_Unset)
524   {
525     SetConsoleCtrlHandler(&_osd_ctrl_break_handler, false);
526   }
527 #endif
528
529   SetThreadLocalSignal (theSignalMode, theFloatingSignal);
530 }
531
532 //============================================================================
533 //==== ControlBreak
534 //============================================================================
535 void OSD::ControlBreak () {
536   if ( fCtrlBrk ) {
537     fCtrlBrk = Standard_False;
538     throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
539   }
540 }  // end OSD :: ControlBreak
541
542 #ifndef OCCT_UWP
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;
550   } else
551     exit ( 254 );
552
553   return TRUE;
554 }  // end _osd_ctrl_break_handler
555 #endif
556
557 //============================================================================
558 //==== _osd_raise
559 //============================================================================
560 static LONG __fastcall _osd_raise (DWORD theCode, const char* theMsg, const char* theStack)
561 {
562   const char* aMsg = theMsg;
563   if (aMsg[0] == '\x03')
564   {
565     ++aMsg;
566   }
567
568   switch (theCode)
569   {
570     case EXCEPTION_ACCESS_VIOLATION:
571       THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, aMsg, theStack);
572       break;
573     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
574       THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, aMsg, theStack);
575       break;
576     case EXCEPTION_DATATYPE_MISALIGNMENT:
577       THROW_OR_JUMP (Standard_ProgramError, aMsg, theStack);
578       break;
579     case EXCEPTION_ILLEGAL_INSTRUCTION:
580       THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, aMsg, theStack);
581       break;
582     case EXCEPTION_IN_PAGE_ERROR:
583       THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, aMsg, theStack);
584       break;
585     case EXCEPTION_INT_DIVIDE_BY_ZERO:
586       THROW_OR_JUMP (Standard_DivideByZero, aMsg, theStack);
587       break;
588     case EXCEPTION_INT_OVERFLOW:
589       THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, aMsg, theStack);
590       break;
591     case EXCEPTION_INVALID_DISPOSITION:
592       THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, aMsg, theStack);
593       break;
594     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
595       THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, aMsg, theStack);
596       break;
597     case EXCEPTION_PRIV_INSTRUCTION:
598       THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, aMsg, theStack);
599       break;
600     case EXCEPTION_STACK_OVERFLOW:
601       THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, aMsg, theStack);
602       break;
603     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
604       THROW_OR_JUMP (Standard_DivideByZero, aMsg, theStack);
605       break;
606     case EXCEPTION_FLT_STACK_CHECK:
607     case EXCEPTION_FLT_OVERFLOW:
608       THROW_OR_JUMP (Standard_Overflow, aMsg, theStack);
609       break;
610     case EXCEPTION_FLT_UNDERFLOW:
611       THROW_OR_JUMP (Standard_Underflow, aMsg, theStack);
612       break;
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);
619       break;
620     default:
621       break;
622   }
623   return EXCEPTION_EXECUTE_HANDLER;
624 }
625
626 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
627 //============================================================================
628 //==== _osd_debug
629 //============================================================================
630 LONG _osd_debug ( void ) {
631
632   LONG action ;
633
634   if ( !fDbgLoaded ) {
635
636     HKEY                hKey = NULL;
637     HANDLE              hEvent = INVALID_HANDLE_VALUE;
638     DWORD               dwKeyType;
639     DWORD               dwValueLen;
640     TCHAR               keyValue[ MAX_PATH ];
641     TCHAR               cmdLine[ MAX_PATH ];
642     SECURITY_ATTRIBUTES sa;
643     PROCESS_INFORMATION pi;
644     STARTUPINFO         si;
645
646     __try {
647
648       if (  RegOpenKey (
649               HKEY_LOCAL_MACHINE,
650               TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
651               &hKey
652             ) != ERROR_SUCCESS
653       ) __leave;
654
655       dwValueLen = sizeof ( keyValue );
656
657       if (  RegQueryValueEx (
658              hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
659             ) != ERROR_SUCCESS
660       ) __leave;
661
662       sa.nLength              = sizeof ( SECURITY_ATTRIBUTES );
663       sa.lpSecurityDescriptor = NULL;
664       sa.bInheritHandle       = TRUE;
665
666       if (   (  hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL )  ) == NULL   ) __leave;
667
668       StringCchPrintf(cmdLine, _countof(cmdLine), keyValue, GetCurrentProcessId(), hEvent);
669
670       ZeroMemory (  &si, sizeof ( STARTUPINFO )  );
671
672       si.cb      = sizeof ( STARTUPINFO );
673       si.dwFlags = STARTF_FORCEONFEEDBACK;
674
675   //   std::cout << "_osd_debug -> CreateProcess" << std::endl ;
676       if (  !CreateProcess (
677               NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
678               NULL, NULL, &si, &pi
679              )
680       ) __leave;
681
682   //   std::cout << "_osd_debug -> WaitForSingleObject " << std::endl ;
683       WaitForSingleObject ( hEvent, INFINITE );
684   //   std::cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << std::endl ;
685
686       CloseHandle ( pi.hProcess );
687       CloseHandle ( pi.hThread  );
688
689   //   std::cout << "_osd_debug fDbgLoaded  " << std::endl ;
690       fDbgLoaded = TRUE;
691
692     }  // end __try
693
694     __finally {
695
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 ;
701
702     }  // end __finally
703
704   }  /* end if */
705
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 ;
709   return action ;
710
711 }  // end _osd_debug
712 #endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
713
714 #else /* ! _WIN32 */
715
716 //---------- All Systems except Windows NT : ----------------------------------
717
718 # include <stdio.h>
719
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>
730
731 #include <Standard_ErrorHandler.hxx>
732
733 // POSIX threads
734 #include <pthread.h>
735
736 #ifdef __linux__
737 #include  <cfenv>
738 //#include  <fenv.h>
739 #endif
740
741 // variable signalling that Control-C has been pressed (SIGINT signal)
742 static Standard_Boolean fCtrlBrk;
743
744 //const OSD_WhoAmI Iam = OSD_WPackage;
745
746 typedef void (ACT_SIGIO_HANDLER)(void) ;
747 ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
748
749 #ifdef __GNUC__
750 # include <stdlib.h>
751 # include <stdio.h>
752 #else
753 #  ifdef SA_SIGINFO
754 #  include <sys/siginfo.h>
755 #  endif
756 #endif
757 typedef void (* SIG_PFV) (int);
758
759 #include <signal.h>
760
761 #if !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
762   #include <sys/signal.h>
763 #endif
764
765 # define _OSD_FPX (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW)
766
767 //============================================================================
768 //==== Handler
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:
775 //====        SIGFPE
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 //============================================================================
786 #ifdef SA_SIGINFO
787 static void Handler (const int theSignal, siginfo_t */*theSigInfo*/, const Standard_Address /*theContext*/)
788 #else
789 static void Handler (const int theSignal)
790 #endif
791 {
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");
797   }
798   else {
799     perror ("sigaction");
800   }
801
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)() ;
805
806   sigset_t set;
807   sigemptyset(&set);
808   switch (theSignal) {
809   case SIGHUP:
810     OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
811     exit(SIGHUP);
812     break;
813   case SIGINT:
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();
818     // exit(SIGINT);
819     break;
820   case SIGQUIT:
821     OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
822     exit(SIGQUIT);
823     break;
824   case SIGILL:
825     OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
826     exit(SIGILL);
827     break;
828   case SIGKILL:
829     OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
830     exit(SIGKILL);
831     break;
832   case SIGBUS:
833     sigaddset(&set, SIGBUS);
834     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
835     OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
836     exit(SIGBUS);
837     break;
838   case SIGSEGV:
839     OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
840     exit(SIGSEGV);
841     break;
842 #ifdef SIGSYS
843   case SIGSYS:
844     OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
845     exit(SIGSYS);
846     break;
847 #endif
848   case SIGFPE:
849     sigaddset(&set, SIGFPE);
850     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
851 #ifdef __linux__
852     OSD::SetFloatingSignal (Standard_True);
853 #endif
854 #if (!defined (__sun)) && (!defined(SOLARIS))
855     Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
856     break;
857 #else
858     // Reste SOLARIS
859     if (aSigInfo) {
860       switch(aSigInfo->si_code) {
861       case FPE_FLTDIV_TRAP :
862         Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
863         break;
864       case FPE_INTDIV_TRAP :
865         Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
866         break;
867       case FPE_FLTOVF_TRAP :
868         Standard_Overflow::NewInstance("Floating Overflow")->Jump();
869         break;
870       case FPE_INTOVF_TRAP :
871         Standard_Overflow::NewInstance("Integer Overflow")->Jump();
872         break;
873       case FPE_FLTUND_TRAP :
874         Standard_NumericError::NewInstance("Floating Underflow")->Jump();
875         break;
876       case FPE_FLTRES_TRAP:
877         Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
878         break;
879       case FPE_FLTINV_TRAP :
880         Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
881         break;
882       default:
883         Standard_NumericError::NewInstance("Numeric Error")->Jump();
884         break;
885       }
886     } else {
887       Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
888     }
889 #endif
890     break;
891   default:
892 #ifdef OCCT_DEBUG
893     std::cout << "Unexpected signal " << theSignal << std::endl ;
894 #endif
895     break;
896   }
897 }
898
899 //============================================================================
900 //==== SegvHandler
901 //============================================================================
902 #ifdef SA_SIGINFO
903
904 static void SegvHandler(const int theSignal,
905                         siginfo_t* theSigInfo,
906                         const Standard_Address theContext)
907 {
908   (void)theSignal;
909   (void)theContext;
910   if (theSigInfo != NULL)
911   {
912     sigset_t set;
913     sigemptyset (&set);
914     sigaddset (&set, SIGSEGV);
915     sigprocmask (SIG_UNBLOCK, &set, NULL);
916     void* anAddress = theSigInfo->si_addr;
917     {
918       char aMsg[100];
919       sprintf (aMsg, "SIGSEGV 'segmentation violation' detected. Address %lx.", (long )anAddress);
920
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)
925       {
926         memset (aStackBuffer, 0, aStackBufLen);
927         Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength);
928       }
929
930       OSD_SIGSEGV::NewInstance (aMsg, aStackBuffer)->Jump();
931     }
932   }
933 #ifdef OCCT_DEBUG
934   else
935   {
936     std::cout << "Wrong undefined address." << std::endl;
937   }
938 #endif
939   exit (SIGSEGV);
940 }
941
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
945
946 static void SegvHandler(const int theSignal,
947                         siginfo_t* theSigInfo,
948                         const Standard_Address theContext)
949 {
950   if (theContext != NULL)
951   {
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;
954     {
955       char aMsg[100];
956       sprintf (aMsg, "SIGSEGV 'segmentation violation' detected. Address %lx", anOffset);
957       OSD_SIGSEGV::NewInstance (aMsg)->Jump();
958     }
959   }
960 #ifdef OCCT_DEBUG
961   else
962   {
963     std::cout << "Wrong undefined address." << std::endl;
964   }
965 #endif
966   exit (SIGSEGV);
967 }
968
969 #endif
970
971 //=======================================================================
972 //function : SetFloatingSignal
973 //purpose  :
974 //=======================================================================
975 void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal)
976 {
977 #if defined (__linux__)
978   feclearexcept (FE_ALL_EXCEPT);
979   if (theFloatingSignal)
980   {
981     feenableexcept (_OSD_FPX);
982   }
983   else
984   {
985     fedisableexcept (_OSD_FPX);
986   }
987 #elif defined (__sun) || defined (SOLARIS)
988   int aSunStat = 0;
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;
993   if (aSunStat)
994   {
995 #ifdef OCCT_DEBUG
996     std::cerr << "ieee_handler does not work !!! KO\n";
997 #endif
998   }
999 #else
1000   (void)theFloatingSignal;
1001 #endif
1002 }
1003
1004 //=======================================================================
1005 //function : ToCatchFloatingSignals
1006 //purpose  :
1007 //=======================================================================
1008 Standard_Boolean OSD::ToCatchFloatingSignals()
1009 {
1010 #if defined (__linux__)
1011   return (fegetexcept() & _OSD_FPX) != 0;
1012 #else
1013   return Standard_False;
1014 #endif
1015 }
1016
1017 //=======================================================================
1018 //function : SetThreadLocalSignal
1019 //purpose  :
1020 //=======================================================================
1021 void OSD::SetThreadLocalSignal (OSD_SignalMode /*theSignalMode*/,
1022                                 Standard_Boolean theFloatingSignal)
1023 {
1024   SetFloatingSignal (theFloatingSignal);
1025 }
1026
1027 //============================================================================
1028 //==== SetSignal
1029 //====     Set the different signals:
1030 //============================================================================
1031
1032 void OSD::SetSignal (OSD_SignalMode theSignalMode,
1033                      Standard_Boolean theFloatingSignal)
1034 {
1035   SetFloatingSignal (theFloatingSignal);
1036
1037   OSD_WasSetSignal = theSignalMode;
1038   if (theSignalMode == OSD_SignalMode_AsIs)
1039   {
1040     return; // nothing to be done with signal handlers
1041   }
1042
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);
1048 #ifdef SA_RESTART
1049   anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = SA_RESTART;
1050 #else
1051   anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = 0;
1052 #endif
1053 #ifdef SA_SIGINFO
1054   anActSet.sa_flags = anActSet.sa_flags | SA_SIGINFO;
1055   anActSet.sa_sigaction = Handler;
1056 #else
1057   anActSet.sa_handler = Handler;
1058 #endif
1059   anActDfl.sa_handler = SIG_DFL;
1060
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)
1065   {
1066     // SIGSEGV has special handler
1067     if (aSignalTypes[i] == SIGSEGV)
1068     {
1069 #ifdef SA_SIGINFO
1070       anActSet.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
1071 #else
1072       anActSet.sa_handler = /*(SIG_PFV)*/ SegvHandler;
1073 #endif
1074     }
1075
1076     // set handler according to specified mode and current handler
1077     int retcode = -1;
1078     if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
1079     {
1080       retcode = sigaction (aSignalTypes[i], &anActSet, &anActOld);
1081     }
1082     else if (theSignalMode == OSD_SignalMode_Unset)
1083     {
1084       retcode = sigaction (aSignalTypes[i], &anActDfl, &anActOld);
1085     }
1086     if (theSignalMode == OSD_SignalMode_SetUnhandled && retcode == 0 && anActOld.sa_handler != SIG_DFL)
1087     {
1088       struct sigaction anActOld2;
1089       sigemptyset(&anActOld2.sa_mask);
1090       retcode = sigaction (aSignalTypes[i], &anActOld, &anActOld2);
1091     }
1092     Standard_ASSERT(retcode == 0, "sigaction() failed", std::cout << "OSD::SetSignal(): sigaction() failed for " << aSignalTypes[i] << std::endl);
1093   }
1094 }
1095
1096 //============================================================================
1097 //==== ControlBreak
1098 //============================================================================
1099
1100 void OSD :: ControlBreak ()
1101 {
1102   if ( fCtrlBrk ) {
1103     fCtrlBrk = Standard_False;
1104     throw OSD_Exception_CTRL_BREAK ("*** INTERRUPT ***");
1105   }
1106 }
1107
1108 #endif