0024533: Use 0 to check null handle instead of UndefinedHandleAccess
[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
6 // under the terms of the GNU Lesser General Public 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 #include <OSD.ixx>
15
16 #ifndef WNT
17
18 //---------- All Systems except Windows NT : ----------------------------------
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 # include <stdio.h>
25
26 #include <OSD_WhoAmI.hxx>
27 #include <OSD_SIGHUP.hxx>
28 #include <OSD_SIGINT.hxx>
29 #include <OSD_SIGQUIT.hxx>
30 #include <OSD_SIGILL.hxx>
31 #include <OSD_SIGKILL.hxx>
32 #include <OSD_SIGBUS.hxx>
33 #include <OSD_SIGSEGV.hxx>
34 #include <OSD_SIGSYS.hxx>
35 #include <OSD_Exception_CTRL_BREAK.hxx>
36 #include <Standard_NumericError.hxx>
37 #include <Standard_DivideByZero.hxx>
38 #include <Standard_Overflow.hxx>
39
40 #include <Standard_ErrorHandler.hxx>
41
42 // POSIX threads
43 #ifdef HAVE_PTHREAD_H
44  #include <pthread.h>
45 #endif
46
47 #ifdef HAVE_PTHREAD_H
48 static pthread_t getOCCThread () {
49   static pthread_t TheOCCThread = 0;
50   return TheOCCThread ;
51 }
52 #endif
53
54 #ifdef linux
55 #include <fenv.h>
56 #include <fpu_control.h>
57 static Standard_Boolean fFltExceptions = Standard_False;
58 #endif
59
60 // variable signalling that Control-C has been pressed (SIGINT signal)
61 static Standard_Boolean fCtrlBrk;
62
63 //const OSD_WhoAmI Iam = OSD_WPackage;
64
65 typedef void (ACT_SIGIO_HANDLER)(void) ;
66 ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
67
68 #if defined(HAVE_FLOATINGPOINT_H) && defined(HAVE_SYS_MACHSIG_H)
69 # include <floatingpoint.h>
70 # include <sys/machsig.h>
71 // JPT : Difference between SUN/SUNOS and SUN/SOLARIS 
72 # define FPE_FLTDIV_TRAP FPE_FLTDIV 
73 # define FPE_INTDIV_TRAP FPE_INTDIV 
74 # define FPE_FLTOVF_TRAP FPE_FLTOVF 
75 # define FPE_INTOVF_TRAP FPE_INTOVF
76 # define FPE_FLTUND_TRAP FPE_FLTUND 
77
78 #define FPE_FLTRES_TRAP FPE_FLTRES      /* floating point inexact result */
79 #define FPE_FLTINV_TRAP FPE_FLTINV      /* invalid floating point operation */
80 #define FPE_FLTSUB_TRAP FPE_FLTSUB      /* subscript out of range */
81
82 extern "C" {int ieee_handler(char *,char *, sigfpe_handler_type&);}
83 # include <stdlib.h>
84 #endif
85
86 #ifdef DECOSF1
87 typedef void (* SIG_PFV) (int);
88 #endif
89
90 #if defined(HAVE_SIGFPE_H) && defined(HAVE_SYS_SIGINFO_H)
91 # include <sigfpe.h>
92 # include <sys/siginfo.h>
93 # define FPE_FLTDIV_TRAP FPE_FLTDIV 
94 # define FPE_INTDIV_TRAP FPE_INTDIV 
95 # define FPE_FLTOVF_TRAP FPE_FLTOVF 
96 # define FPE_INTOVF_TRAP FPE_INTOVF
97 # define FPE_FLTUND_TRAP FPE_FLTUND 
98 #endif 
99
100 #ifdef __GNUC__
101 # include <stdlib.h>
102 # include <stdio.h>
103 #else
104 #  ifdef SA_SIGINFO 
105 #    ifndef _AIX
106 #  include <sys/siginfo.h>
107 #     endif
108 #  endif
109 #endif
110 typedef void (* SIG_PFV) (int);
111
112 #ifdef HAVE_SIGNAL_H
113 # include <signal.h>
114 #endif
115
116 #ifdef HAVE_SYS_SIGNAL_H
117 # include <sys/signal.h>
118 #endif
119
120 #if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION) 
121 //============================================================================
122 //====  GetOldSigAction
123 //====     get previous 
124 //============================================================================
125
126 static struct sigaction *GetOldSigAction() 
127 {
128   static struct sigaction oldSignals[NSIG];
129   return oldSignals;
130 }
131
132 #ifdef SOLARIS
133 static sigfpe_handler_type *GetOldFPE()
134 {
135   static sigfpe_handler_type aIEEEHandler[5] = { NULL, NULL, NULL, NULL, NULL } ;
136   return aIEEEHandler;
137 }
138 #endif
139 #endif
140
141 //============================================================================
142 //==== Handler
143 //====     Catche the differents signals:
144 //====          1- The Fatal signals, which cause the end of process:
145 //====          2- The exceptions which are "signaled" by Raise.
146 //====     The Fatal Signals:
147 //====        SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGKILL, SIGBUS, SIGSYS
148 //====     The Exceptions:
149 //====        SIGFPE
150 //====         (SUN versions)
151 //====           FPE_INTOVF_TRAP    // ..... integer overflow
152 //====           FPE_INTDIV_TRAP    // ..... integer divide by zero
153 //====           FPE_FLTINEX_TRAP   // ..... [floating inexact result]
154 //====           FPE_FLTDIV_TRAP    // ..... [floating divide by zero]
155 //====           FPE_FLTUND_TRAP    // ..... [floating underflow]
156 //====           FPE_FLTOPER_TRAP   // ..... [floating inexact result]
157 //====           FPE_FLTOVF_TRAP    // ..... [floating overflow]
158 //==== SIGSEGV is handled by "SegvHandler()"
159 //============================================================================
160 #ifdef SA_SIGINFO
161 static void Handler (const int theSignal, siginfo_t *theSigInfo, const Standard_Address theContext)
162 #else
163 static void Handler (const int theSignal)
164 #endif
165 {
166   struct sigaction oldact, act;
167   // re-install the signal
168   if ( ! sigaction (theSignal, NULL, &oldact) ) {
169     // cout << " signal is " << theSignal << " handler is " <<  oldact.sa_handler << endl;
170     if (sigaction (theSignal, &oldact, &act)) perror ("sigaction");
171   }
172   else {
173     perror ("sigaction");
174   }
175
176   siginfo_t * aSigInfo = NULL;
177 #ifdef SA_SIGINFO
178   aSigInfo = theSigInfo;
179 #endif
180
181 #if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION)
182   if (pthread_self() != getOCCThread()  || !Standard_ErrorHandler::IsInTryBlock()) {
183     // use the previous signal handler
184     // cout << "OSD::Handler: signal " << (int) theSignal << " occured outside a try block " <<  endl ;
185     struct sigaction *oldSignals = GetOldSigAction();
186     struct sigaction  asigacthandler =  oldSignals[theSignal >= 0 && theSignal < NSIG ? theSignal : 0];
187
188     if (asigacthandler.sa_flags & SA_SIGINFO) {
189       void (*aCurInfoHandle)(int, siginfo_t *, void *) = asigacthandler.sa_sigaction;
190       if (aSigInfo) {
191         switch (aSigInfo->si_signo) {
192           case SIGFPE:
193           {
194 #ifdef SOLARIS
195             sigfpe_handler_type *aIEEEHandlerTab = GetOldFPE();
196             sigfpe_handler_type  aIEEEHandler = NULL;
197             switch (aSigInfo->si_code) {
198               case FPE_INTDIV_TRAP :
199               case FPE_FLTDIV_TRAP :
200                aIEEEHandler = aIEEEHandlerTab[1];
201                 break;
202               case FPE_INTOVF_TRAP :
203               case FPE_FLTOVF_TRAP :
204                 aIEEEHandler = aIEEEHandlerTab[2];
205                 break;
206               case FPE_FLTUND_TRAP :
207                 aIEEEHandler = aIEEEHandlerTab[4];
208                 break;
209               case FPE_FLTRES_TRAP :
210                 aIEEEHandler = aIEEEHandlerTab[3];
211                 break;
212               case FPE_FLTINV_TRAP :
213                 aIEEEHandler = aIEEEHandlerTab[0];
214                 break;
215               case FPE_FLTSUB_TRAP :
216               default:
217                 break;
218             }
219             if (aIEEEHandler) {
220               // cout << "OSD::Handler: calling previous IEEE signal handler with info" <<  endl ;
221               (*aIEEEHandler) (theSignal, aSigInfo, theContext);
222               return;
223             }
224 #endif
225             break;
226           }
227           default:
228             break;
229         }
230       }
231       if (aCurInfoHandle) {
232         // cout << "OSD::Handler: calling previous signal handler with info " << aCurInfoHandle <<  endl ;
233         (*aCurInfoHandle) (theSignal, aSigInfo, theContext);
234         cerr << " previous signal handler return" <<  endl ;
235         return;
236       }
237       else {
238         // cout << "OSD::Handler: no handler with info for the signal" << endl;
239       }
240     }
241     else {
242       // no siginfo needed for the signal
243       void (*aCurHandler) (int) = asigacthandler.sa_handler;
244       if(aCurHandler) {
245         // cout << "OSD::Handler: calling previous signal handler" <<  endl ;
246         (*aCurHandler) (theSignal);
247         cerr << " previous signal handler return" <<  endl ;
248         return;
249       }
250     }
251     // cout << " Signal occured outside a try block, but no handler for it" <<endl;
252     return;
253   }
254 #endif
255
256   // cout << "OSD::Handler: signal " << (int) theSignal << " occured inside a try block " <<  endl ;
257   if ( ADR_ACT_SIGIO_HANDLER != NULL )
258     (*ADR_ACT_SIGIO_HANDLER)() ;
259 #ifdef linux
260   if (fFltExceptions)
261     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
262     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
263 #endif
264   sigset_t set;
265   sigemptyset(&set);
266   switch (theSignal) {
267   case SIGHUP:
268     OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
269     exit(SIGHUP);
270     break;
271   case SIGINT:
272     // For safe handling of Control-C as stop event, arm a variable but do not
273     // generate longjump (we are out of context anyway)
274     fCtrlBrk = Standard_True;
275     // OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
276     // exit(SIGINT);
277     break;
278   case SIGQUIT:
279     OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
280     exit(SIGQUIT);
281     break;
282   case SIGILL:
283     OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
284     exit(SIGILL);
285     break;
286   case SIGKILL:
287     OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
288     exit(SIGKILL);
289     break;
290   case SIGBUS:
291     sigaddset(&set, SIGBUS);
292     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
293     OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
294     exit(SIGBUS);
295     break;
296   case SIGSEGV:
297     OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
298     exit(SIGSEGV);
299     break;
300 #ifdef SIGSYS
301   case SIGSYS:
302     OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
303     exit(SIGSYS);
304     break;
305 #endif
306   case SIGFPE:
307     sigaddset(&set, SIGFPE);
308     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
309 #ifdef DECOSF1
310     // Pour DEC/OSF1 SIGFPE = Division par zero.
311     // should be clarified why in debug mode only?
312 #ifdef DEBUG
313     Standard_DivideByZero::NewInstance('')->Jump;
314 #endif
315     break;
316 #endif
317 #if (!defined (__sun)) && (!defined(SOLARIS))
318     Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
319     break;
320 #else
321     // Reste SOLARIS
322     if (aSigInfo) {
323       switch(aSigInfo->si_code) {
324       case FPE_FLTDIV_TRAP :
325         Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
326         break;
327       case FPE_INTDIV_TRAP :
328         Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
329         break;
330       case FPE_FLTOVF_TRAP :
331         Standard_Overflow::NewInstance("Floating Overflow")->Jump();
332         break;
333       case FPE_INTOVF_TRAP :
334         Standard_Overflow::NewInstance("Integer Overflow")->Jump();
335         break;
336       case FPE_FLTUND_TRAP :
337         Standard_NumericError::NewInstance("Floating Underflow")->Jump();
338         break;
339       case FPE_FLTRES_TRAP:
340         Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
341         break;
342       case FPE_FLTINV_TRAP :
343         Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
344         break;
345       default:
346         Standard_NumericError::NewInstance("Numeric Error")->Jump();
347         break;
348       }
349     } else {
350       Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
351     }
352 #endif
353     break;
354 #if defined (__sgi) || defined(IRIX)
355   case SIGTRAP:
356     sigaddset(&set, SIGTRAP);
357     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
358     Standard_DivideByZero::NewInstance("SIGTRAP IntegerDivideByZero")->Jump(); break;
359 #endif
360   default:
361     cout << "Unexpected signal " << theSignal << endl ;
362     break;
363   }
364 }
365
366 //============================================================================
367 //==== SegvHandler
368 //============================================================================
369 #ifdef SA_SIGINFO
370
371 static void SegvHandler(const int theSignal,
372                         siginfo_t *ip,
373                         const Standard_Address theContext)
374 {
375 #ifdef NO_CXX_EXCEPTION
376   if (!Standard_ErrorHandler::IsInTryBlock()) {
377     Handler(theSignal, ip, theContext);
378     return;
379   }
380 #endif
381 #ifdef linux
382   if (fFltExceptions)
383     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
384     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
385 #endif
386 //  cout << "OSD::SegvHandler activated(SA_SIGINFO)" << endl ;
387   if ( ip != NULL ) {
388      sigset_t set;
389      sigemptyset(&set);
390      sigaddset(&set, SIGSEGV);
391      sigprocmask (SIG_UNBLOCK, &set, NULL) ;
392      void *address = ip->si_addr ;
393      {
394        char Msg[100];
395        sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",
396          (long ) address ) ;
397        OSD_SIGSEGV::NewInstance(Msg)->Jump();
398      }
399   }
400   else {
401     cout << "Wrong undefined address." << endl ;
402   }
403   exit(SIGSEGV);
404 }
405
406 #elif defined (_hpux) || defined(HPUX)
407 // Not ACTIVE ? SA_SIGINFO is defined on SUN, OSF, SGI and HP (and Linux) !
408 // pour version 09.07
409
410 static void SegvHandler(const int theSignal,
411                         siginfo_t *ip,
412                         const Standard_Address theContext)
413 {
414   unsigned long Space  ;
415   unsigned long Offset ;
416   char Msg[100] ;
417
418   if ( theContext != NULL ) {
419     Space = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20 ;
420     Offset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21 ;
421 //    cout << "Wrong address = " << hex(Offset) << endl ;
422     {
423       sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",Offset) ;
424       OSD_SIGSEGV::Jump(Msg);
425 //    scp->sc_pcoq_head = scp->sc_pcoq_tail ;       Permettrait de continuer a
426 //    scp->sc_pcoq_tail = scp->sc_pcoq_tail + 0x4 ; l'intruction suivant le segv.
427     }
428   }
429   else {
430     cout << "Wrong undefined address." << endl ;
431   }
432   exit(SIGSEGV);
433 }
434
435 #endif
436
437 //============================================================================
438 //==== SetSignal 
439 //====     Set the differents signals:
440 //============================================================================
441
442 void OSD::SetSignal(const Standard_Boolean aFloatingSignal) 
443 {
444   static int first_time = 3 ;
445   struct sigaction act, oact;
446   int              stat = 0;
447
448   if( aFloatingSignal ) {
449     //==== Enable the floating point exceptions ===============
450 #if defined (__sun) || defined (SOLARIS)
451     sigfpe_handler_type PHandler = (sigfpe_handler_type) Handler ;
452     stat = ieee_handler("set", "invalid",  PHandler);
453     stat = ieee_handler("set", "division", PHandler) || stat;
454     stat = ieee_handler("set", "overflow", PHandler) || stat;
455
456     //stat = ieee_handler("set", "underflow", PHandler) || stat;
457     //stat = ieee_handler("set", "inexact", PHandler) || stat;
458
459     if (stat) {
460       cerr << "ieee_handler does not work !!! KO " << endl;
461     }
462 #elif defined (linux)
463     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
464     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
465     fFltExceptions = Standard_True;
466 #endif
467   }
468   else if ( first_time & 1 ) {
469 //    cout << "SetSignal( Standard_False ) is not implemented..." << endl ;
470     first_time = first_time & (~ 1) ;
471   }
472
473 #if defined (sgi) || defined (IRIX )
474  if ( first_time & 2 ) {
475    char *TRAP_FPE = getenv("TRAP_FPE") ;
476    if ( TRAP_FPE == NULL ) {
477      cout << "On SGI you must set TRAP_FPE environment variable : " << endl ;
478      cout << "set env(TRAP_FPE) \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\" or" << endl ;
479      cout << "setenv TRAP_FPE \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\"" << endl ;
480 //     exit(1) ;
481      first_time = first_time & (~ 2) ;
482    }
483  }
484 #endif
485
486   //==== Save the old Signal Handler, and set the new one ===================
487
488   sigemptyset(&act.sa_mask) ;
489
490 #ifdef SA_RESTART
491   act.sa_flags   = SA_RESTART ;
492 #else
493   act.sa_flags   = 0 ;
494 #endif
495 #ifdef SA_SIGINFO
496   act.sa_flags = act.sa_flags | SA_SIGINFO ;
497   act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ Handler;
498 #else
499   act.sa_handler = /*(SIG_PFV)*/ Handler;
500 #endif
501
502   //==== Always detected the signal "SIGFPE" =================================
503   stat = sigaction(SIGFPE,&act,&oact);   // ...... floating point exception 
504   if (stat) {
505      cerr << "sigaction does not work !!! KO " << endl;
506      perror("sigaction ");
507   }
508
509   //==== Detected the only the "free" signals ================================
510   sigaction(SIGHUP,&act,&oact);    // ...... hangup  
511
512 #ifdef OBJS
513   if(oact.sa_handler) 
514         sigaction(SIGHUP,&oact,&oact);
515 #endif
516
517   sigaction(SIGINT,&act,&oact);   // ...... interrupt   
518
519 #ifdef OBJS
520   if(oact.sa_handler) 
521         sigaction(SIGINT,&oact,&oact);
522 #endif
523             
524   sigaction(SIGQUIT,&act,&oact);  // ...... quit
525
526 #ifdef OBJS
527   if(oact.sa_handler) 
528         sigaction(SIGQUIT,&oact,&oact);
529 #endif
530
531   sigaction(SIGILL,&act,&oact);   // ...... illegal instruction 
532
533 #ifdef OBJS
534   if(oact.sa_handler) 
535         sigaction(SIGILL,&oact,&oact);
536 #endif
537
538   sigaction(SIGBUS,&act,&oact);   // ...... bus error 
539
540 #ifdef OBJS
541   if(oact.sa_handler) 
542         sigaction(SIGBUS,&oact,&oact);
543 #endif
544
545 #if (!defined (linux)) && (!defined(LININTEL))
546   sigaction(SIGSYS,&act,&oact);   // ...... bad argument to system call
547
548 # ifdef OBJS
549   if(oact.sa_handler) 
550         sigaction(SIGSYS,&oact,&oact);
551 # endif
552 #endif
553
554 #if defined (__sgi) || defined(IRIX)
555   sigaction(SIGTRAP,&act,&oact);   // Integer Divide By Zero (IRIX)
556
557 # ifdef OBJS
558   if(oact.sa_handler) 
559         sigaction(SIGTRAP,&oact,&oact);
560 # endif
561 #endif
562
563 #ifdef SA_SIGINFO
564   act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
565 #else
566   act.sa_handler = /*(SIG_PFV)*/ SegvHandler;
567 #endif
568
569   if ( sigaction( SIGSEGV , &act , &oact ) )  // ...... segmentation violation
570     perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
571
572 #ifdef OBJS
573   if(oact.sa_handler) 
574         sigaction(SIGSEGV,&oact,&oact);
575 #endif
576 #if defined(__osf__) || defined(DECOSF1)
577    struct sigaction action, prev_action;
578    action.sa_handler = SIG_IGN;
579    action.sa_mask = 0;
580    action.sa_flags = 0;
581    
582    if (sigaction (SIGFPE, &action, &prev_action) == -1) {
583      perror ("sigaction");
584      exit (1);
585    }
586 #endif
587
588 }
589
590 //============================================================================
591 //==== ControlBreak 
592 //============================================================================
593
594 void OSD :: ControlBreak () 
595 {
596   if ( fCtrlBrk ) {
597     fCtrlBrk = Standard_False;
598     OSD_Exception_CTRL_BREAK::Raise ("*** INTERRUPT ***");
599   }
600 }
601
602 #endif