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