1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
19 //---------------------------- Windows NT System --------------------------------
27 #include <OSD_Exception_ACCESS_VIOLATION.hxx>
28 #include <OSD_Exception_ARRAY_BOUNDS_EXCEEDED.hxx>
29 #include <OSD_Exception_ILLEGAL_INSTRUCTION.hxx>
30 #include <OSD_Exception_IN_PAGE_ERROR.hxx>
31 #include <OSD_Exception_INT_DIVIDE_BY_ZERO.hxx>
32 #include <OSD_Exception_INT_OVERFLOW.hxx>
33 #include <OSD_Exception_INVALID_DISPOSITION.hxx>
34 #include <OSD_Exception_NONCONTINUABLE_EXCEPTION.hxx>
35 #include <OSD_Exception_PRIV_INSTRUCTION.hxx>
36 #include <OSD_Exception_STACK_OVERFLOW.hxx>
37 #include <OSD_Exception_STATUS_NO_MEMORY.hxx>
38 #include <OSD_Exception_CTRL_BREAK.hxx>
40 #include <OSD_Environment.hxx>
41 #include <Standard_Underflow.hxx>
42 #include <Standard_DivideByZero.hxx>
43 #include <Standard_Overflow.hxx>
44 #include <Standard_ProgramError.hxx>
45 #include <Standard_Mutex.hxx>
47 #include <OSD_WNT_1.hxx>
58 static Standard_Boolean fMsgBox;
59 static Standard_Boolean fFltExceptions;
60 static Standard_Boolean fDbgLoaded;
61 static Standard_Boolean fCtrlBrk;
63 // used to forbid simultaneous execution of setting / executing handlers
64 static Standard_Mutex THE_SIGNAL_MUTEX;
66 static LONG __fastcall _osd_raise ( DWORD, LPSTR );
67 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD );
69 static LONG _osd_debug ( void );
71 //# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
72 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
74 //=======================================================================
75 //function : CallHandler
77 //=======================================================================
78 static LONG CallHandler (DWORD dwExceptionCode,
79 ptrdiff_t ExceptionInformation1,
80 ptrdiff_t ExceptionInformation0)
83 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
85 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
86 static char buffer[ 2048 ];
91 // cout << "CallHandler " << dwExceptionCode << endl ;
92 switch ( dwExceptionCode ) {
94 case EXCEPTION_FLT_DENORMAL_OPERAND:
95 // cout << "CallHandler : EXCEPTION_FLT_DENORMAL_OPERAND:" << endl ;
96 lstrcpyA ( buffer, "FLT DENORMAL OPERAND" );
99 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
100 // cout << "CallHandler : EXCEPTION_FLT_DIVIDE_BY_ZERO:" << endl ;
101 lstrcpyA ( buffer, "FLT DIVIDE BY ZERO" );
104 case EXCEPTION_FLT_INEXACT_RESULT:
105 // cout << "CallHandler : EXCEPTION_FLT_INEXACT_RESULT:" << endl ;
106 lstrcpyA ( buffer, "FLT INEXACT RESULT" );
109 case EXCEPTION_FLT_INVALID_OPERATION:
110 // cout << "CallHandler : EXCEPTION_FLT_INVALID_OPERATION:" << endl ;
111 lstrcpyA ( buffer, "FLT INVALID OPERATION" );
114 case EXCEPTION_FLT_OVERFLOW:
115 // cout << "CallHandler : EXCEPTION_FLT_OVERFLOW:" << endl ;
116 lstrcpyA ( buffer, "FLT OVERFLOW" );
119 case EXCEPTION_FLT_STACK_CHECK:
120 // cout << "CallHandler : EXCEPTION_FLT_STACK_CHECK:" << endl ;
121 lstrcpyA ( buffer, "FLT STACK CHECK" );
124 case EXCEPTION_FLT_UNDERFLOW:
125 // cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
126 lstrcpyA ( buffer, "FLT UNDERFLOW" );
129 case STATUS_FLOAT_MULTIPLE_TRAPS:
130 // cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
131 lstrcpyA ( buffer, "FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)" );
134 case STATUS_FLOAT_MULTIPLE_FAULTS:
135 // cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
136 lstrcpyA ( buffer, "FLT MULTIPLE FAULTS" );
140 case STATUS_NO_MEMORY:
141 // cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
142 OSD_Exception_STATUS_NO_MEMORY ::
143 Raise ( "MEMORY ALLOCATION ERROR ( no room in the process heap )" );
145 case EXCEPTION_ACCESS_VIOLATION:
146 // cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
147 wsprintf ( buffer, "%s%s%s0x%.8p%s%s%s", "ACCESS VIOLATION",
148 fMsgBox ? "\n" : " ", "at address ",
149 ExceptionInformation1 ,
151 ExceptionInformation0 ? "WRITE" : "READ",
155 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
156 // cout << "CallHandler : EXCEPTION_ARRAY_BOUNDS_EXCEEDED:" << endl ;
157 lstrcpyA ( buffer, "ARRAY BOUNDS EXCEEDED" );
160 case EXCEPTION_DATATYPE_MISALIGNMENT:
161 // cout << "CallHandler : EXCEPTION_DATATYPE_MISALIGNMENT:" << endl ;
162 lstrcpyA ( buffer, "DATATYPE MISALIGNMENT" );
165 case EXCEPTION_ILLEGAL_INSTRUCTION:
166 // cout << "CallHandler : EXCEPTION_ILLEGAL_INSTRUCTION:" << endl ;
167 lstrcpyA ( buffer, "ILLEGAL INSTRUCTION" );
170 case EXCEPTION_IN_PAGE_ERROR:
171 // cout << "CallHandler : EXCEPTION_IN_PAGE_ERROR:" << endl ;
172 lstrcpyA ( buffer, "IN_PAGE ERROR" );
175 case EXCEPTION_INT_DIVIDE_BY_ZERO:
176 // cout << "CallHandler : EXCEPTION_INT_DIVIDE_BY_ZERO:" << endl ;
177 lstrcpyA ( buffer, "INTEGER DIVISION BY ZERO" );
180 case EXCEPTION_INT_OVERFLOW:
181 // cout << "CallHandler : EXCEPTION_INT_OVERFLOW:" << endl ;
182 lstrcpyA ( buffer, "INTEGER OVERFLOW" );
185 case EXCEPTION_INVALID_DISPOSITION:
186 // cout << "CallHandler : EXCEPTION_INVALID_DISPOSITION:" << endl ;
187 lstrcpyA ( buffer, "INVALID DISPOSITION" );
190 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
191 // cout << "CallHandler : EXCEPTION_NONCONTINUABLE_EXCEPTION:" << endl ;
192 lstrcpyA ( buffer, "NONCONTINUABLE EXCEPTION" );
195 case EXCEPTION_PRIV_INSTRUCTION:
196 // cout << "CallHandler : EXCEPTION_PRIV_INSTRUCTION:" << endl ;
197 lstrcpyA ( buffer, "PRIVELEGED INSTRUCTION ENCOUNTERED" );
200 case EXCEPTION_STACK_OVERFLOW:
201 // cout << "CallHandler : EXCEPTION_STACK_OVERFLOW:" << endl ;
202 #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
203 // try recovering from stack overflow: available in MS VC++ 7.0
204 if (!_resetstkoflw())
205 lstrcpyA ( buffer, "Unrecoverable STACK OVERFLOW" );
208 lstrcpyA ( buffer, "STACK OVERFLOW" );
212 wsprintf( buffer, "unknown exception code 0x%x, params 0x%p 0x%p",
213 dwExceptionCode, ExceptionInformation1, ExceptionInformation0 );
217 // provide message to the user with possibility to stop
218 int idx = lstrlenA ( buffer );
219 if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) {
220 // reset FP operations before message box, otherwise it may fail to show up
224 MessageBeep ( MB_ICONHAND );
225 int aChoice = ::MessageBox (0, buffer, "OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
226 if (aChoice == IDRETRY)
231 else if (aChoice == IDABORT)
237 if ( !fFltExceptions )
238 return EXCEPTION_EXECUTE_HANDLER;
241 _controlfp ( 0, _OSD_FPX ) ; // JR add :
242 // cout << "OSD::WntHandler _controlfp( 0, _OSD_FPX ) " << hex << _controlfp(0,0) << dec << endl ;
244 return _osd_raise ( dwExceptionCode, buffer );
250 //=======================================================================
251 //function : SIGWntHandler
252 //purpose : Will only be used if user calls ::raise() function with
253 // signal type set in OSD::SetSignal() - SIGSEGV, SIGFPE, SIGILL
254 // (the latter will likely be removed in the future)
255 //=======================================================================
256 static void SIGWntHandler (int signum, int sub_code)
258 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
259 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
262 if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
263 cout << "signal error" << endl ;
266 CallHandler( EXCEPTION_FLT_INVALID_OPERATION ,0,0) ;
269 CallHandler( EXCEPTION_FLT_DENORMAL_OPERAND ,0,0) ;
271 case _FPE_ZERODIVIDE :
272 CallHandler( EXCEPTION_FLT_DIVIDE_BY_ZERO ,0,0) ;
275 CallHandler( EXCEPTION_FLT_OVERFLOW ,0,0) ;
277 case _FPE_UNDERFLOW :
278 CallHandler( EXCEPTION_FLT_UNDERFLOW ,0,0) ;
281 CallHandler( EXCEPTION_FLT_INEXACT_RESULT ,0,0) ;
284 cout << "SIGWntHandler(default) -> Standard_NumericError::Raise(\"Floating Point Error\");" << endl;
285 Standard_NumericError::Raise("Floating Point Error");
290 if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
291 cout << "signal error" << endl ;
292 CallHandler( EXCEPTION_ACCESS_VIOLATION ,0,0) ;
295 if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
296 cout << "signal error" << endl ;
297 CallHandler( EXCEPTION_ILLEGAL_INSTRUCTION ,0,0) ;
300 cout << "SIGWntHandler unexpected signal : " << signum << endl ;
307 //=======================================================================
308 //function : TranslateSE
309 //purpose : Translate Structural Exceptions into C++ exceptions
310 // Will be used when user's code is compiled with /EHa option
311 //=======================================================================
314 // If this file compiled with the default MSVC options for exception
315 // handling (/GX or /EHsc) then the following warning is issued:
316 // warning C4535: calling _set_se_translator() requires /EHa
317 // However it is correctly inserted and used when user's code compiled with /EHa.
318 // So, here we disable the warning.
319 #pragma warning (disable:4535)
321 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
323 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
324 ptrdiff_t info1 = 0, info0 = 0;
326 info1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
327 info0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
329 CallHandler(theCode, info1, info0);
332 //=======================================================================
333 //function : WntHandler
334 //purpose : Will be used when user's code is compiled with /EHs
335 // option and unless user sets his own exception handler with
336 // ::SetUnhandledExceptionFilter().
337 //=======================================================================
338 static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
340 DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
342 return CallHandler (dwExceptionCode,
343 lpXP->ExceptionRecord->ExceptionInformation[1],
344 lpXP->ExceptionRecord->ExceptionInformation[0]);
346 //=======================================================================
347 //function : SetSignal
349 //=======================================================================
350 void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
352 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
353 Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
354 LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
356 OSD_Environment env (TEXT("CSF_DEBUG_MODE"));
357 TCollection_AsciiString val = env.Value();
360 cout << "Environment variable CSF_DEBUG_MODE setted.\n";
361 fMsgBox = Standard_True;
365 fMsgBox = Standard_False;
368 // Set exception handler (ignored when running under debugger). It will be used in most cases
369 // when user's code is compiled with /EHs
370 // Replaces the existing top-level exception filter for all existing and all future threads
371 // in the calling process
372 aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
374 // Signal handlers will only be used when the method ::raise() will be used
375 // Handlers must be set for every thread
376 if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
377 cout << "signal(OSD::SetSignal) error\n";
378 if (signal (SIGFPE, (void(*)(int))SIGWntHandler) == SIG_ERR)
379 cout << "signal(OSD::SetSignal) error\n";
380 if (signal (SIGILL, (void(*)(int))SIGWntHandler) == SIG_ERR)
381 cout << "signal(OSD::SetSignal) error\n";
383 // Set Ctrl-C and Ctrl-Break handler
384 fCtrlBrk = Standard_False;
385 SetConsoleCtrlHandler (&_osd_ctrl_break_handler, TRUE);
388 // _se_translator_function pOldSeFunc =
389 _set_se_translator (TranslateSE);
392 fFltExceptions = theFloatingSignal;
393 if (theFloatingSignal)
395 _controlfp (0, _OSD_FPX); // JR add :
398 _controlfp (_OSD_FPX, _OSD_FPX); // JR add :
401 } // end OSD :: SetSignal
403 //============================================================================
405 //============================================================================
407 void OSD :: ControlBreak () {
411 fCtrlBrk = Standard_False;
412 OSD_Exception_CTRL_BREAK :: Raise ( TEXT( "*** INTERRUPT ***" ) );
416 } // end OSD :: ControlBreak
418 //============================================================================
419 //==== _osd_ctrl_break_handler
420 //============================================================================
422 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
424 if ( dwCode == CTRL_C_EVENT || dwCode == CTRL_BREAK_EVENT ) {
426 MessageBeep ( MB_ICONEXCLAMATION );
427 fCtrlBrk = Standard_True;
435 } // end _osd_ctrl_break_handler
437 //============================================================================
439 //============================================================================
441 static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
443 if (msg[0] == '\x03') ++msg;
447 case EXCEPTION_ACCESS_VIOLATION:
448 OSD_Exception_ACCESS_VIOLATION::Raise (msg);
450 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
451 OSD_Exception_ARRAY_BOUNDS_EXCEEDED::Raise (msg);
453 case EXCEPTION_DATATYPE_MISALIGNMENT:
454 Standard_ProgramError::Raise (msg);
456 case EXCEPTION_ILLEGAL_INSTRUCTION:
457 OSD_Exception_ILLEGAL_INSTRUCTION::Raise (msg);
459 case EXCEPTION_IN_PAGE_ERROR:
460 OSD_Exception_IN_PAGE_ERROR::Raise (msg);
462 case EXCEPTION_INT_DIVIDE_BY_ZERO:
463 Standard_DivideByZero::Raise (msg);
465 case EXCEPTION_INT_OVERFLOW:
466 OSD_Exception_INT_OVERFLOW::Raise (msg);
468 case EXCEPTION_INVALID_DISPOSITION:
469 OSD_Exception_INVALID_DISPOSITION::Raise (msg);
471 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
472 OSD_Exception_NONCONTINUABLE_EXCEPTION::Raise (msg);
474 case EXCEPTION_PRIV_INSTRUCTION:
475 OSD_Exception_PRIV_INSTRUCTION::Raise (msg);
477 case EXCEPTION_STACK_OVERFLOW:
478 OSD_Exception_STACK_OVERFLOW::Raise (msg);
480 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
481 Standard_DivideByZero::Raise (msg);
483 case EXCEPTION_FLT_STACK_CHECK:
484 case EXCEPTION_FLT_OVERFLOW:
485 Standard_Overflow::Raise (msg);
487 case EXCEPTION_FLT_UNDERFLOW:
488 Standard_Underflow::Raise (msg);
490 case EXCEPTION_FLT_INVALID_OPERATION:
491 case EXCEPTION_FLT_DENORMAL_OPERAND:
492 case EXCEPTION_FLT_INEXACT_RESULT:
493 case STATUS_FLOAT_MULTIPLE_TRAPS:
494 case STATUS_FLOAT_MULTIPLE_FAULTS:
495 Standard_NumericError::Raise (msg);
500 return EXCEPTION_EXECUTE_HANDLER;
503 //============================================================================
505 //============================================================================
507 #if defined(__CYGWIN32__) || defined(__MINGW32__)
510 #define __leave return 0
513 LONG _osd_debug ( void ) {
520 HANDLE hEvent = INVALID_HANDLE_VALUE;
523 TCHAR keyValue[ MAX_PATH ];
524 TCHAR cmdLine[ MAX_PATH ];
525 SECURITY_ATTRIBUTES sa;
526 PROCESS_INFORMATION pi;
533 TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
538 dwValueLen = sizeof ( keyValue );
540 if ( RegQueryValueEx (
541 hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
545 sa.nLength = sizeof ( SECURITY_ATTRIBUTES );
546 sa.lpSecurityDescriptor = NULL;
547 sa.bInheritHandle = TRUE;
549 if ( ( hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL ) ) == NULL ) __leave;
551 wsprintf ( cmdLine, keyValue, GetCurrentProcessId (), hEvent );
553 ZeroMemory ( &si, sizeof ( STARTUPINFO ) );
555 si.cb = sizeof ( STARTUPINFO );
556 si.dwFlags = STARTF_FORCEONFEEDBACK;
558 // cout << "_osd_debug -> CreateProcess" << endl ;
559 if ( !CreateProcess (
560 NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
565 // cout << "_osd_debug -> WaitForSingleObject " << endl ;
566 WaitForSingleObject ( hEvent, INFINITE );
567 // cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << endl ;
569 CloseHandle ( pi.hProcess );
570 CloseHandle ( pi.hThread );
572 // cout << "_osd_debug fDbgLoaded " << endl ;
579 // cout << "_osd_debug -> CloseHandle(hKey) " << endl ;
580 if ( hKey != INVALID_HANDLE_VALUE ) CloseHandle ( hKey );
581 // cout << "_osd_debug -> CloseHandle(hEvent) " << endl ;
582 if ( hEvent != INVALID_HANDLE_VALUE ) CloseHandle ( hEvent );
583 // cout << "_osd_debug end __finally " << endl ;
589 action = fDbgLoaded ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
590 // cout << "_osd_debug return " << action << " EXCEPTION_CONTINUE_EXECUTION("
591 // << EXCEPTION_CONTINUE_EXECUTION << ")" << endl ;
596 #if defined(__CYGWIN32__) || defined(__MINGW32__)