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