0030775: Foundation Classes - Preserve application-defined top-level exception filter
[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 static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs;
22
23 //=======================================================================
24 //function : SignalMode
25 //purpose  :
26 //=======================================================================
27 OSD_SignalMode OSD::SignalMode()
28 {
29   return OSD_WasSetSignal;
30 }
31
32 #ifdef _WIN32
33 //---------------------------- Windows NT System --------------------------------
34
35 #ifdef NOUSER
36 #undef NOUSER
37 #endif
38 #ifdef NONLS
39 #undef NONLS
40 #endif
41 #include <windows.h>
42
43 #include <strsafe.h>
44
45 #ifndef STATUS_FLOAT_MULTIPLE_FAULTS
46   // <ntstatus.h>
47   #define STATUS_FLOAT_MULTIPLE_FAULTS     (0xC00002B4L)
48   #define STATUS_FLOAT_MULTIPLE_TRAPS      (0xC00002B5L)
49 #endif
50
51 #include <OSD_Exception_ACCESS_VIOLATION.hxx>
52 #include <OSD_Exception_ARRAY_BOUNDS_EXCEEDED.hxx>
53 #include <OSD_Exception_ILLEGAL_INSTRUCTION.hxx>
54 #include <OSD_Exception_IN_PAGE_ERROR.hxx>
55 #include <OSD_Exception_INT_DIVIDE_BY_ZERO.hxx>
56 #include <OSD_Exception_INT_OVERFLOW.hxx>
57 #include <OSD_Exception_INVALID_DISPOSITION.hxx>
58 #include <OSD_Exception_NONCONTINUABLE_EXCEPTION.hxx>
59 #include <OSD_Exception_PRIV_INSTRUCTION.hxx>
60 #include <OSD_Exception_STACK_OVERFLOW.hxx>
61 #include <OSD_Exception_STATUS_NO_MEMORY.hxx>
62
63 #include <OSD_Environment.hxx>
64 #include <Standard_Underflow.hxx>
65 #include <Standard_ProgramError.hxx>
66 #include <Standard_Mutex.hxx>
67
68 #include <OSD_WNT.hxx>
69
70 #ifdef _MSC_VER
71 #include <eh.h>
72 #include <malloc.h>
73 #endif
74
75 #include <process.h>
76 #include <signal.h>
77 #include <float.h>
78
79 static Standard_Boolean fCtrlBrk;
80
81 static Standard_Boolean fMsgBox;
82
83 // used to forbid simultaneous execution of setting / executing handlers
84 static Standard_Mutex THE_SIGNAL_MUTEX;
85
86 static LONG __fastcall _osd_raise ( DWORD, LPSTR );
87 static BOOL WINAPI     _osd_ctrl_break_handler ( DWORD );
88
89 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
90 static Standard_Boolean fDbgLoaded;
91 static LONG _osd_debug   ( void );
92 #endif
93
94 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
95
96 #ifdef OCC_CONVERT_SIGNALS
97 #define THROW_OR_JUMP(Type,Message) Type::NewInstance(Message)->Jump()
98 #else
99 #define THROW_OR_JUMP(Type,Message) throw Type(Message)
100 #endif
101
102 //=======================================================================
103 //function : CallHandler
104 //purpose  :
105 //=======================================================================
106 static LONG CallHandler (DWORD dwExceptionCode,
107                          ptrdiff_t ExceptionInformation1,
108                          ptrdiff_t ExceptionInformation0)
109 {
110   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
111
112   static wchar_t         buffer[2048];
113
114   int                  flterr = 0;
115
116   buffer[0] = '\0' ;
117
118 // std::cout << "CallHandler " << dwExceptionCode << std::endl ;
119   switch ( dwExceptionCode ) {
120     case EXCEPTION_FLT_DENORMAL_OPERAND:
121 //      std::cout << "CallHandler : EXCEPTION_FLT_DENORMAL_OPERAND:" << std::endl ;
122       StringCchCopyW (buffer, _countof(buffer), L"FLT DENORMAL OPERAND");
123       flterr = 1 ;
124       break ;
125     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
126 //      std::cout << "CallHandler : EXCEPTION_FLT_DIVIDE_BY_ZERO:" << std::endl ;
127       StringCchCopyW (buffer, _countof(buffer), L"FLT DIVIDE BY ZERO");
128       flterr = 1 ;
129       break ;
130     case EXCEPTION_FLT_INEXACT_RESULT:
131 //      std::cout << "CallHandler : EXCEPTION_FLT_INEXACT_RESULT:" << std::endl ;
132       StringCchCopyW (buffer, _countof(buffer), L"FLT INEXACT RESULT");
133       flterr = 1 ;
134       break ;
135     case EXCEPTION_FLT_INVALID_OPERATION:
136 //      std::cout << "CallHandler : EXCEPTION_FLT_INVALID_OPERATION:" << std::endl ;
137       StringCchCopyW (buffer, _countof(buffer), L"FLT INVALID OPERATION");
138       flterr = 1 ;
139       break ;
140     case EXCEPTION_FLT_OVERFLOW:
141 //      std::cout << "CallHandler : EXCEPTION_FLT_OVERFLOW:" << std::endl ;
142       StringCchCopyW (buffer, _countof(buffer), L"FLT OVERFLOW");
143       flterr = 1 ;
144       break ;
145     case EXCEPTION_FLT_STACK_CHECK:
146 //      std::cout << "CallHandler : EXCEPTION_FLT_STACK_CHECK:" << std::endl ;
147       StringCchCopyW (buffer, _countof(buffer), L"FLT STACK CHECK");
148       flterr = 1 ;
149       break ;
150     case EXCEPTION_FLT_UNDERFLOW:
151 //      std::cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << std::endl ;
152       StringCchCopyW (buffer, _countof(buffer), L"FLT UNDERFLOW");
153       flterr = 1 ;
154       break ;
155     case STATUS_FLOAT_MULTIPLE_TRAPS:
156 //      std::cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << std::endl ;
157       StringCchCopyW (buffer, _countof(buffer), L"FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)");
158       flterr = 1 ;
159       break ;
160     case STATUS_FLOAT_MULTIPLE_FAULTS:
161 //      std::cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << std::endl ;
162       StringCchCopyW (buffer, _countof(buffer), L"FLT MULTIPLE FAULTS");
163       flterr = 1 ;
164       break ;
165     case STATUS_NO_MEMORY:
166 //      std::cout << "CallHandler : STATUS_NO_MEMORY:" << std::endl ;
167       THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )");
168       break;
169     case EXCEPTION_ACCESS_VIOLATION:
170 //      std::cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << std::endl ;
171       StringCchPrintfW (buffer, _countof(buffer), L"%s%s%s0x%.8p%s%s%s", L"ACCESS VIOLATION",
172                  fMsgBox ? L"\n" : L" ", L"at address ",
173                  ExceptionInformation1 ,
174                  L" during '",
175                  ExceptionInformation0 ? L"WRITE" : L"READ",
176                  L"' operation");
177       break;
178     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
179 //      std::cout << "CallHandler : EXCEPTION_ARRAY_BOUNDS_EXCEEDED:" << std::endl ;
180       StringCchCopyW (buffer, _countof(buffer), L"ARRAY BOUNDS EXCEEDED");
181       break;
182     case EXCEPTION_DATATYPE_MISALIGNMENT:
183 //      std::cout << "CallHandler : EXCEPTION_DATATYPE_MISALIGNMENT:" << std::endl ;
184       StringCchCopyW (buffer, _countof(buffer), L"DATATYPE MISALIGNMENT");
185       break;
186
187     case EXCEPTION_ILLEGAL_INSTRUCTION:
188 //      std::cout << "CallHandler : EXCEPTION_ILLEGAL_INSTRUCTION:" << std::endl ;
189       StringCchCopyW (buffer, _countof(buffer), L"ILLEGAL INSTRUCTION");
190       break;
191
192     case EXCEPTION_IN_PAGE_ERROR:
193 //      std::cout << "CallHandler : EXCEPTION_IN_PAGE_ERROR:" << std::endl ;
194       StringCchCopyW (buffer, _countof(buffer), L"IN_PAGE ERROR");
195       break;
196
197     case EXCEPTION_INT_DIVIDE_BY_ZERO:
198 //      std::cout << "CallHandler : EXCEPTION_INT_DIVIDE_BY_ZERO:" << std::endl ;
199       StringCchCopyW (buffer, _countof(buffer), L"INTEGER DIVISION BY ZERO");
200       break;
201
202     case EXCEPTION_INT_OVERFLOW:
203 //      std::cout << "CallHandler : EXCEPTION_INT_OVERFLOW:" << std::endl ;
204       StringCchCopyW (buffer, _countof(buffer), L"INTEGER OVERFLOW");
205       break;
206
207     case EXCEPTION_INVALID_DISPOSITION:
208 //      std::cout << "CallHandler : EXCEPTION_INVALID_DISPOSITION:" << std::endl ;
209       StringCchCopyW (buffer, _countof(buffer), L"INVALID DISPOSITION");
210       break;
211
212     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
213 //      std::cout << "CallHandler : EXCEPTION_NONCONTINUABLE_EXCEPTION:" << std::endl ;
214       StringCchCopyW (buffer, _countof(buffer), L"NONCONTINUABLE EXCEPTION");
215       break;
216
217     case EXCEPTION_PRIV_INSTRUCTION:
218 //      std::cout << "CallHandler : EXCEPTION_PRIV_INSTRUCTION:" << std::endl ;
219       StringCchCopyW (buffer, _countof(buffer), L"PRIVELEGED INSTRUCTION ENCOUNTERED");
220       break;
221
222     case EXCEPTION_STACK_OVERFLOW:
223 //      std::cout << "CallHandler : EXCEPTION_STACK_OVERFLOW:" << std::endl ;
224 #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) && !defined(OCCT_UWP)
225     // try recovering from stack overflow: available in MS VC++ 7.0
226       if (!_resetstkoflw())
227         StringCchCopyW (buffer, _countof(buffer), L"Unrecoverable STACK OVERFLOW");
228       else
229 #endif
230       StringCchCopyW (buffer, _countof(buffer), L"STACK OVERFLOW");
231       break;
232
233     default:
234       StringCchPrintfW (buffer, _countof(buffer), L"unknown exception code 0x%x, params 0x%p 0x%p",
235                 dwExceptionCode, ExceptionInformation1, ExceptionInformation0 );
236
237   }  // end switch
238
239   // reset FPE state (before message box, otherwise it may fail to show up)
240   if ( flterr ) {
241     OSD::SetFloatingSignal (Standard_True);
242   }
243
244 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
245  // provide message to the user with possibility to stop
246   size_t idx;
247   StringCchLengthW (buffer, _countof(buffer),&idx);
248   if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) {
249     MessageBeep ( MB_ICONHAND );
250     int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
251     if (aChoice == IDRETRY)
252     {
253       _osd_debug();
254       DebugBreak();
255     } else if (aChoice == IDABORT)
256       exit(0xFFFF);
257   }
258 #endif
259
260   char aBufferA[2048];
261   WideCharToMultiByte(CP_UTF8, 0, buffer, -1, aBufferA, sizeof(aBufferA), NULL, NULL);
262   return _osd_raise(dwExceptionCode, aBufferA);
263 }
264
265 //=======================================================================
266 //function : SIGWntHandler
267 //purpose  : Will only be used if user calls ::raise() function with
268 //           signal type set in OSD::SetSignal() - SIGSEGV, SIGFPE, SIGILL
269 //           (the latter will likely be removed in the future)
270 //=======================================================================
271 static void SIGWntHandler (int signum, int sub_code)
272 {
273   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
274   switch( signum ) {
275     case SIGFPE :
276       if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
277         std::cout << "signal error" << std::endl ;
278       switch( sub_code ) {
279         case _FPE_INVALID :
280           CallHandler( EXCEPTION_FLT_INVALID_OPERATION ,0,0) ;
281           break ;
282         case _FPE_DENORMAL :
283           CallHandler( EXCEPTION_FLT_DENORMAL_OPERAND ,0,0) ;
284           break ;
285         case _FPE_ZERODIVIDE :
286           CallHandler( EXCEPTION_FLT_DIVIDE_BY_ZERO ,0,0) ;
287           break ;
288         case _FPE_OVERFLOW :
289           CallHandler( EXCEPTION_FLT_OVERFLOW ,0,0) ;
290           break ;
291         case _FPE_UNDERFLOW :
292           CallHandler( EXCEPTION_FLT_UNDERFLOW ,0,0) ;
293           break ;
294         case _FPE_INEXACT :
295           CallHandler( EXCEPTION_FLT_INEXACT_RESULT ,0,0) ;
296           break ;
297         default:
298           std::cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << std::endl;
299           THROW_OR_JUMP (Standard_NumericError, "Floating Point Error");
300           break ;
301       }
302       break ;
303     case SIGSEGV :
304       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
305         std::cout << "signal error" << std::endl ;
306       CallHandler( EXCEPTION_ACCESS_VIOLATION ,0,0) ;
307       break ;
308     case SIGILL :
309       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
310         std::cout << "signal error" << std::endl ;
311       CallHandler( EXCEPTION_ILLEGAL_INSTRUCTION ,0,0) ;
312       break ;
313     default:
314       std::cout << "SIGWntHandler unexpected signal : " << signum << std::endl ;
315       break ;
316   }
317 #ifndef OCCT_UWP
318   DebugBreak ();
319 #endif
320 }
321
322 //=======================================================================
323 //function : TranslateSE
324 //purpose  : Translate Structural Exceptions into C++ exceptions
325 //           Will be used when user's code is compiled with /EHa option
326 //=======================================================================
327 #ifdef _MSC_VER
328 // If this file compiled with the default MSVC options for exception
329 // handling (/GX or /EHsc) then the following warning is issued:
330 //   warning C4535: calling _set_se_translator() requires /EHa
331 // However it is correctly inserted and used when user's code compiled with /EHa.
332 // So, here we disable the warning.
333 #pragma warning (disable:4535)
334
335 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
336 {
337   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
338   ptrdiff_t info1 = 0, info0 = 0;
339   if ( theExcPtr ) {
340     info1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
341     info0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
342   }
343   CallHandler(theCode, info1, info0);
344 }
345 #endif
346
347 //=======================================================================
348 //function : WntHandler
349 //purpose  : Will be used when user's code is compiled with /EHs
350 //           option and unless user sets his own exception handler with
351 //           ::SetUnhandledExceptionFilter().
352 //=======================================================================
353 static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
354 {
355   DWORD               dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
356
357   return CallHandler (dwExceptionCode,
358                       lpXP->ExceptionRecord->ExceptionInformation[1],
359                       lpXP->ExceptionRecord->ExceptionInformation[0]);
360 }
361
362 //=======================================================================
363 //function : SetFloatingSignal
364 //purpose  :
365 //=======================================================================
366 void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal)
367 {
368   _fpreset();
369   _clearfp();
370   
371   // Note: zero bit means exception will be raised
372   _controlfp (theFloatingSignal ? 0 : _OSD_FPX, _OSD_FPX);
373 }
374
375 //=======================================================================
376 //function : ToCatchFloatingSignals
377 //purpose  :
378 //=======================================================================
379 Standard_Boolean OSD::ToCatchFloatingSignals()
380 {
381   // return true if at least one of bits within _OSD_FPX
382   // is unset, which means relevant FPE will raise exception
383   int aControlWord = _controlfp (0, 0);
384   return (_OSD_FPX & ~aControlWord) != 0;
385 }
386
387 //=======================================================================
388 //function : SetThreadLocalSignal
389 //purpose  :
390 //=======================================================================
391 void OSD::SetThreadLocalSignal (OSD_SignalMode theSignalMode,
392                                 Standard_Boolean theFloatingSignal)
393 {
394 #ifdef _MSC_VER
395   _se_translator_function aPreviousFunc = NULL;
396   if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
397     aPreviousFunc = _set_se_translator(TranslateSE);
398   if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL))
399     _set_se_translator(aPreviousFunc);
400 #else
401   (void)theSignalMode;
402 #endif
403   SetFloatingSignal (theFloatingSignal);
404 }
405
406 //=======================================================================
407 //function : SetSignal
408 //purpose  :
409 //=======================================================================
410 void OSD::SetSignal (OSD_SignalMode theSignalMode,
411                      Standard_Boolean theFloatingSignal)
412 {
413   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
414   OSD_WasSetSignal = theSignalMode;
415
416 #if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
417   OSD_Environment env ("CSF_DEBUG_MODE");
418   TCollection_AsciiString val = env.Value();
419   if (!env.Failed())
420   {
421     std::cout << "Environment variable CSF_DEBUG_MODE setted.\n";
422     fMsgBox = Standard_True;
423   }
424   else
425   {
426     fMsgBox = Standard_False;
427   }
428
429   // Set exception handler (ignored when running under debugger). It will be used in most cases
430   // when user's code is compiled with /EHs
431   // Replaces the existing top-level exception filter for all existing and all future threads
432   // in the calling process
433   {
434     LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFunc = NULL;
435     if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
436     {
437       aPreviousFunc = ::SetUnhandledExceptionFilter(WntHandler);
438     }
439     if (theSignalMode == OSD_SignalMode_Unset || (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != NULL))
440     {
441       ::SetUnhandledExceptionFilter(aPreviousFunc);
442     }
443   }
444 #endif // NTDDI_WIN10_TH2
445
446   // Signal handlers will only be used when function ::raise() is called
447   const int NBSIG = 3;
448   const int aSignalTypes[NBSIG] = { SIGSEGV, SIGILL, SIGFPE };
449   for (int i = 0; i < NBSIG; ++i)
450   {
451     typedef void (*SignalFuncType)(int); // same as _crt_signal_t available since vc14
452     SignalFuncType aPreviousFunc = SIG_DFL;
453     if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
454     {
455       aPreviousFunc = signal(aSignalTypes[i], (SignalFuncType)SIGWntHandler);
456     }
457     if (theSignalMode == OSD_SignalMode_Unset ||
458         (theSignalMode == OSD_SignalMode_SetUnhandled && aPreviousFunc != SIG_DFL && aPreviousFunc != SIG_ERR))
459     {
460       aPreviousFunc = signal(aSignalTypes[i], aPreviousFunc);
461     }
462     Standard_ASSERT(aPreviousFunc != SIG_ERR, "signal() failed", std::cout << "OSD::SetSignal(): signal() returns SIG_ERR");
463   }
464
465   // Set Ctrl-C and Ctrl-Break handler
466   fCtrlBrk = Standard_False;
467 #ifndef OCCT_UWP
468   if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
469   {
470     SetConsoleCtrlHandler(&_osd_ctrl_break_handler, true);
471   }
472   else if (theSignalMode == OSD_SignalMode_Unset)
473   {
474     SetConsoleCtrlHandler(&_osd_ctrl_break_handler, false);
475   }
476 #endif
477
478   SetThreadLocalSignal (theSignalMode, theFloatingSignal);
479 }
480
481 //============================================================================
482 //==== ControlBreak
483 //============================================================================
484 void OSD::ControlBreak () {
485   if ( fCtrlBrk ) {
486     fCtrlBrk = Standard_False;
487     throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
488   }
489 }  // end OSD :: ControlBreak
490
491 #ifndef OCCT_UWP
492 //============================================================================
493 //==== _osd_ctrl_break_handler
494 //============================================================================
495 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
496   if ( dwCode == CTRL_C_EVENT || dwCode == CTRL_BREAK_EVENT ) {
497     MessageBeep ( MB_ICONEXCLAMATION );
498     fCtrlBrk = Standard_True;
499   } else
500     exit ( 254 );
501
502   return TRUE;
503 }  // end _osd_ctrl_break_handler
504 #endif
505
506 //============================================================================
507 //==== _osd_raise
508 //============================================================================
509 static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
510 {
511   if (msg[0] == '\x03') ++msg;
512
513   switch (dwCode)
514   {
515     case EXCEPTION_ACCESS_VIOLATION:
516       THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, msg);
517       break;
518     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
519       THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, msg);
520       break;
521     case EXCEPTION_DATATYPE_MISALIGNMENT:
522       THROW_OR_JUMP (Standard_ProgramError, msg);
523       break;
524     case EXCEPTION_ILLEGAL_INSTRUCTION:
525       THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, msg);
526       break;
527     case EXCEPTION_IN_PAGE_ERROR:
528       THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, msg);
529       break;
530     case EXCEPTION_INT_DIVIDE_BY_ZERO:
531       THROW_OR_JUMP (Standard_DivideByZero, msg);
532       break;
533     case EXCEPTION_INT_OVERFLOW:
534       THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, msg);
535       break;
536     case EXCEPTION_INVALID_DISPOSITION:
537       THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, msg);
538       break;
539     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
540       THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, msg);
541       break;
542     case EXCEPTION_PRIV_INSTRUCTION:
543       THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, msg);
544       break;
545     case EXCEPTION_STACK_OVERFLOW:
546       THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, msg);
547       break;
548     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
549       THROW_OR_JUMP (Standard_DivideByZero, msg);
550       break;
551     case EXCEPTION_FLT_STACK_CHECK:
552     case EXCEPTION_FLT_OVERFLOW:
553       THROW_OR_JUMP (Standard_Overflow, msg);
554       break;
555     case EXCEPTION_FLT_UNDERFLOW:
556       THROW_OR_JUMP (Standard_Underflow, msg);
557       break;
558     case EXCEPTION_FLT_INVALID_OPERATION:
559     case EXCEPTION_FLT_DENORMAL_OPERAND:
560     case EXCEPTION_FLT_INEXACT_RESULT:
561     case STATUS_FLOAT_MULTIPLE_TRAPS:
562     case STATUS_FLOAT_MULTIPLE_FAULTS:
563       THROW_OR_JUMP (Standard_NumericError, msg);
564       break;
565     default:
566       break;
567   }  // end switch
568   return EXCEPTION_EXECUTE_HANDLER;
569 }  // end _osd_raise
570
571 #if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
572 //============================================================================
573 //==== _osd_debug
574 //============================================================================
575 LONG _osd_debug ( void ) {
576
577   LONG action ;
578
579   if ( !fDbgLoaded ) {
580
581     HKEY                hKey = NULL;
582     HANDLE              hEvent = INVALID_HANDLE_VALUE;
583     DWORD               dwKeyType;
584     DWORD               dwValueLen;
585     TCHAR               keyValue[ MAX_PATH ];
586     TCHAR               cmdLine[ MAX_PATH ];
587     SECURITY_ATTRIBUTES sa;
588     PROCESS_INFORMATION pi;
589     STARTUPINFO         si;
590
591     __try {
592
593       if (  RegOpenKey (
594               HKEY_LOCAL_MACHINE,
595               TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
596               &hKey
597             ) != ERROR_SUCCESS
598       ) __leave;
599
600       dwValueLen = sizeof ( keyValue );
601
602       if (  RegQueryValueEx (
603              hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
604             ) != ERROR_SUCCESS
605       ) __leave;
606
607       sa.nLength              = sizeof ( SECURITY_ATTRIBUTES );
608       sa.lpSecurityDescriptor = NULL;
609       sa.bInheritHandle       = TRUE;
610
611       if (   (  hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL )  ) == NULL   ) __leave;
612
613       StringCchPrintf(cmdLine, _countof(cmdLine), keyValue, GetCurrentProcessId(), hEvent);
614
615       ZeroMemory (  &si, sizeof ( STARTUPINFO )  );
616
617       si.cb      = sizeof ( STARTUPINFO );
618       si.dwFlags = STARTF_FORCEONFEEDBACK;
619
620   //   std::cout << "_osd_debug -> CreateProcess" << std::endl ;
621       if (  !CreateProcess (
622               NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
623               NULL, NULL, &si, &pi
624              )
625       ) __leave;
626
627   //   std::cout << "_osd_debug -> WaitForSingleObject " << std::endl ;
628       WaitForSingleObject ( hEvent, INFINITE );
629   //   std::cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << std::endl ;
630
631       CloseHandle ( pi.hProcess );
632       CloseHandle ( pi.hThread  );
633
634   //   std::cout << "_osd_debug fDbgLoaded  " << std::endl ;
635       fDbgLoaded = TRUE;
636
637     }  // end __try
638
639     __finally {
640
641 //   std::cout << "_osd_debug -> CloseHandle(hKey) " << std::endl ;
642       if ( hKey   != INVALID_HANDLE_VALUE ) CloseHandle ( hKey   );
643 //   std::cout << "_osd_debug -> CloseHandle(hEvent) " << std::endl ;
644       if ( hEvent != INVALID_HANDLE_VALUE ) CloseHandle ( hEvent );
645 //   std::cout << "_osd_debug end __finally " << std::endl ;
646
647     }  // end __finally
648
649   }  /* end if */
650
651   action = fDbgLoaded ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
652 // std::cout << "_osd_debug return " << action << " EXCEPTION_CONTINUE_EXECUTION("
653 //      << EXCEPTION_CONTINUE_EXECUTION << ")" << std::endl ;
654   return action ;
655
656 }  // end _osd_debug
657 #endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
658
659 #else /* ! _WIN32 */
660
661 //---------- All Systems except Windows NT : ----------------------------------
662
663 # include <stdio.h>
664
665 #include <OSD_WhoAmI.hxx>
666 #include <OSD_SIGHUP.hxx>
667 #include <OSD_SIGINT.hxx>
668 #include <OSD_SIGQUIT.hxx>
669 #include <OSD_SIGILL.hxx>
670 #include <OSD_SIGKILL.hxx>
671 #include <OSD_SIGBUS.hxx>
672 #include <OSD_SIGSEGV.hxx>
673 #include <OSD_SIGSYS.hxx>
674 #include <Standard_NumericError.hxx>
675
676 #include <Standard_ErrorHandler.hxx>
677
678 // POSIX threads
679 #include <pthread.h>
680
681 #ifdef __linux__
682 #include  <cfenv>
683 //#include  <fenv.h>
684 #endif
685
686 // variable signalling that Control-C has been pressed (SIGINT signal)
687 static Standard_Boolean fCtrlBrk;
688
689 //const OSD_WhoAmI Iam = OSD_WPackage;
690
691 typedef void (ACT_SIGIO_HANDLER)(void) ;
692 ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
693
694 #ifdef __GNUC__
695 # include <stdlib.h>
696 # include <stdio.h>
697 #else
698 #  ifdef SA_SIGINFO
699 #  include <sys/siginfo.h>
700 #  endif
701 #endif
702 typedef void (* SIG_PFV) (int);
703
704 #include <signal.h>
705
706 #if !defined(__ANDROID__) && !defined(__QNX__)
707   #include <sys/signal.h>
708 #endif
709
710 # define _OSD_FPX (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW)
711
712 //============================================================================
713 //==== Handler
714 //====     Catche the differents signals:
715 //====          1- The Fatal signals, which cause the end of process:
716 //====          2- The exceptions which are "signaled" by Raise.
717 //====     The Fatal Signals:
718 //====        SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGKILL, SIGBUS, SIGSYS
719 //====     The Exceptions:
720 //====        SIGFPE
721 //====         (SUN versions)
722 //====           FPE_INTOVF_TRAP    // ..... integer overflow
723 //====           FPE_INTDIV_TRAP    // ..... integer divide by zero
724 //====           FPE_FLTINEX_TRAP   // ..... [floating inexact result]
725 //====           FPE_FLTDIV_TRAP    // ..... [floating divide by zero]
726 //====           FPE_FLTUND_TRAP    // ..... [floating underflow]
727 //====           FPE_FLTOPER_TRAP   // ..... [floating inexact result]
728 //====           FPE_FLTOVF_TRAP    // ..... [floating overflow]
729 //==== SIGSEGV is handled by "SegvHandler()"
730 //============================================================================
731 #ifdef SA_SIGINFO
732 static void Handler (const int theSignal, siginfo_t */*theSigInfo*/, const Standard_Address /*theContext*/)
733 #else
734 static void Handler (const int theSignal)
735 #endif
736 {
737   struct sigaction oldact, act;
738   // re-install the signal
739   if ( ! sigaction (theSignal, NULL, &oldact) ) {
740     // std::cout << " signal is " << theSignal << " handler is " <<  oldact.sa_handler << std::endl;
741     if (sigaction (theSignal, &oldact, &act)) perror ("sigaction");
742   }
743   else {
744     perror ("sigaction");
745   }
746
747   // std::cout << "OSD::Handler: signal " << (int) theSignal << " occured inside a try block " <<  std::endl ;
748   if ( ADR_ACT_SIGIO_HANDLER != NULL )
749     (*ADR_ACT_SIGIO_HANDLER)() ;
750
751   sigset_t set;
752   sigemptyset(&set);
753   switch (theSignal) {
754   case SIGHUP:
755     OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
756     exit(SIGHUP);
757     break;
758   case SIGINT:
759     // For safe handling of Control-C as stop event, arm a variable but do not
760     // generate longjump (we are out of context anyway)
761     fCtrlBrk = Standard_True;
762     // OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
763     // exit(SIGINT);
764     break;
765   case SIGQUIT:
766     OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
767     exit(SIGQUIT);
768     break;
769   case SIGILL:
770     OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
771     exit(SIGILL);
772     break;
773   case SIGKILL:
774     OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
775     exit(SIGKILL);
776     break;
777   case SIGBUS:
778     sigaddset(&set, SIGBUS);
779     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
780     OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
781     exit(SIGBUS);
782     break;
783   case SIGSEGV:
784     OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
785     exit(SIGSEGV);
786     break;
787 #ifdef SIGSYS
788   case SIGSYS:
789     OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
790     exit(SIGSYS);
791     break;
792 #endif
793   case SIGFPE:
794     sigaddset(&set, SIGFPE);
795     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
796 #ifdef __linux__
797     OSD::SetFloatingSignal (Standard_True);
798 #endif
799 #if (!defined (__sun)) && (!defined(SOLARIS))
800     Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
801     break;
802 #else
803     // Reste SOLARIS
804     if (aSigInfo) {
805       switch(aSigInfo->si_code) {
806       case FPE_FLTDIV_TRAP :
807         Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
808         break;
809       case FPE_INTDIV_TRAP :
810         Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
811         break;
812       case FPE_FLTOVF_TRAP :
813         Standard_Overflow::NewInstance("Floating Overflow")->Jump();
814         break;
815       case FPE_INTOVF_TRAP :
816         Standard_Overflow::NewInstance("Integer Overflow")->Jump();
817         break;
818       case FPE_FLTUND_TRAP :
819         Standard_NumericError::NewInstance("Floating Underflow")->Jump();
820         break;
821       case FPE_FLTRES_TRAP:
822         Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
823         break;
824       case FPE_FLTINV_TRAP :
825         Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
826         break;
827       default:
828         Standard_NumericError::NewInstance("Numeric Error")->Jump();
829         break;
830       }
831     } else {
832       Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
833     }
834 #endif
835     break;
836   default:
837 #ifdef OCCT_DEBUG
838     std::cout << "Unexpected signal " << theSignal << std::endl ;
839 #endif
840     break;
841   }
842 }
843
844 //============================================================================
845 //==== SegvHandler
846 //============================================================================
847 #ifdef SA_SIGINFO
848
849 static void SegvHandler(const int theSignal,
850                         siginfo_t *ip,
851                         const Standard_Address theContext)
852 {
853   (void)theSignal; // silence GCC warnings
854   (void)theContext;
855
856 //  std::cout << "OSD::SegvHandler activated(SA_SIGINFO)" << std::endl ;
857   if ( ip != NULL ) {
858      sigset_t set;
859      sigemptyset(&set);
860      sigaddset(&set, SIGSEGV);
861      sigprocmask (SIG_UNBLOCK, &set, NULL) ;
862      void *address = ip->si_addr ;
863      {
864        char Msg[100];
865        sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",
866          (long ) address ) ;
867        OSD_SIGSEGV::NewInstance(Msg)->Jump();
868      }
869   }
870 #ifdef OCCT_DEBUG
871   else {
872     std::cout << "Wrong undefined address." << std::endl ;
873   }
874 #endif
875   exit(SIGSEGV);
876 }
877
878 #elif defined (_hpux) || defined(HPUX)
879 // Not ACTIVE ? SA_SIGINFO is defined on SUN, OSF, SGI and HP (and Linux) !
880 // pour version 09.07
881
882 static void SegvHandler(const int theSignal,
883                         siginfo_t *ip,
884                         const Standard_Address theContext)
885 {
886   unsigned long Space  ;
887   unsigned long Offset ;
888   char Msg[100] ;
889
890   if ( theContext != NULL ) {
891     Space = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20 ;
892     Offset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21 ;
893 //    std::cout << "Wrong address = " << hex(Offset) << std::endl ;
894     {
895       sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",Offset) ;
896       OSD_SIGSEGV::Jump(Msg);
897 //    scp->sc_pcoq_head = scp->sc_pcoq_tail ;       Permettrait de continuer a
898 //    scp->sc_pcoq_tail = scp->sc_pcoq_tail + 0x4 ; l'intruction suivant le segv.
899     }
900   }
901 #ifdef OCCT_DEBUG
902   else {
903     std::cout << "Wrong undefined address." << std::endl ;
904   }
905 #endif
906   exit(SIGSEGV);
907 }
908
909 #endif
910
911 //=======================================================================
912 //function : SetFloatingSignal
913 //purpose  :
914 //=======================================================================
915 void OSD::SetFloatingSignal (Standard_Boolean theFloatingSignal)
916 {
917 #if defined (__linux__)
918   feclearexcept (FE_ALL_EXCEPT);
919   if (theFloatingSignal)
920   {
921     feenableexcept (_OSD_FPX);
922   }
923   else
924   {
925     fedisableexcept (_OSD_FPX);
926   }
927 #elif defined (__sun) || defined (SOLARIS)
928   int aSunStat = 0;
929   sigfpe_handler_type anFpeHandler = (theFloatingSignal ? (sigfpe_handler_type)Handler : NULL);
930   aSunStat = ieee_handler ("set", "invalid",  anFpeHandler);
931   aSunStat = ieee_handler ("set", "division", anFpeHandler) || aSunStat;
932   aSunStat = ieee_handler ("set", "overflow", anFpeHandler) || aSunStat;
933   if (aSunStat)
934   {
935 #ifdef OCCT_DEBUG
936     std::cerr << "ieee_handler does not work !!! KO\n";
937 #endif
938   }
939 #else
940   (void)theFloatingSignal;
941 #endif
942 }
943
944 //=======================================================================
945 //function : ToCatchFloatingSignals
946 //purpose  :
947 //=======================================================================
948 Standard_Boolean OSD::ToCatchFloatingSignals()
949 {
950 #if defined (__linux__)
951   return (fegetexcept() & _OSD_FPX) != 0;
952 #else
953   return Standard_False;
954 #endif
955 }
956
957 //=======================================================================
958 //function : SetThreadLocalSignal
959 //purpose  :
960 //=======================================================================
961 void OSD::SetThreadLocalSignal (OSD_SignalMode /*theSignalMode*/,
962                                 Standard_Boolean theFloatingSignal)
963 {
964   SetFloatingSignal (theFloatingSignal);
965 }
966
967 //============================================================================
968 //==== SetSignal
969 //====     Set the differents signals:
970 //============================================================================
971
972 void OSD::SetSignal (OSD_SignalMode theSignalMode,
973                      Standard_Boolean theFloatingSignal)
974 {
975   SetFloatingSignal (theFloatingSignal);
976
977   OSD_WasSetSignal = theSignalMode;
978   if (theSignalMode == OSD_SignalMode_AsIs)
979   {
980     return; // nothing to be done with signal handlers
981   }
982
983   // Prepare signal descriptors
984   struct sigaction anActSet, anActDfl, anActOld;
985   sigemptyset(&anActSet.sa_mask);
986   sigemptyset(&anActDfl.sa_mask);
987   sigemptyset(&anActOld.sa_mask);
988 #ifdef SA_RESTART
989   anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = SA_RESTART;
990 #else
991   anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = 0;
992 #endif
993 #ifdef SA_SIGINFO
994   anActSet.sa_flags = anActSet.sa_flags | SA_SIGINFO;
995   anActSet.sa_sigaction = Handler;
996 #else
997   anActSet.sa_handler = Handler;
998 #endif
999   anActDfl.sa_handler = SIG_DFL;
1000
1001   // Set signal handlers; NB: SIGSEGV must be the last one!
1002   const int NBSIG = 8;
1003   const int aSignalTypes[NBSIG] = { SIGFPE, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSYS, SIGSEGV };
1004   for (int i = 0; i < NBSIG; ++i)
1005   {
1006     // SIGSEGV has special handler
1007     if (aSignalTypes[i] == SIGSEGV)
1008     {
1009 #ifdef SA_SIGINFO
1010       anActSet.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
1011 #else
1012       anActSet.sa_handler = /*(SIG_PFV)*/ SegvHandler;
1013 #endif
1014     }
1015
1016     // set handler according to specified mode and current handler
1017     int retcode = -1;
1018     if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled)
1019     {
1020       retcode = sigaction (aSignalTypes[i], &anActSet, &anActOld);
1021     }
1022     else if (theSignalMode == OSD_SignalMode_Unset)
1023     {
1024       retcode = sigaction (aSignalTypes[i], &anActDfl, &anActOld);
1025     }
1026     if (theSignalMode == OSD_SignalMode_SetUnhandled && retcode == 0 && anActOld.sa_handler != SIG_DFL)
1027     {
1028       retcode = sigaction (aSignalTypes[i], &anActOld, &anActOld);
1029     }
1030     Standard_ASSERT(retcode == 0, "sigaction() failed", std::cout << "OSD::SetSignal(): sigaction() failed for " << aSignalTypes[i] << std::endl);
1031   }
1032 }
1033
1034 //============================================================================
1035 //==== ControlBreak
1036 //============================================================================
1037
1038 void OSD :: ControlBreak ()
1039 {
1040   if ( fCtrlBrk ) {
1041     fCtrlBrk = Standard_False;
1042     throw OSD_Exception_CTRL_BREAK ("*** INTERRUPT ***");
1043   }
1044 }
1045
1046 #endif