@@ -125,7 +125,13 @@ static fault_handler_t faulthandler_handlers[] = {
125
125
static const size_t faulthandler_nsignals = \
126
126
Py_ARRAY_LENGTH (faulthandler_handlers );
127
127
128
- #ifdef HAVE_SIGALTSTACK
128
+ /* Using an alternative stack requires sigaltstack()
129
+ and sigaction() SA_ONSTACK */
130
+ #if defined(HAVE_SIGALTSTACK ) && defined(HAVE_SIGACTION )
131
+ # define FAULTHANDLER_USE_ALT_STACK
132
+ #endif
133
+
134
+ #ifdef FAULTHANDLER_USE_ALT_STACK
129
135
static stack_t stack ;
130
136
static stack_t old_stack ;
131
137
#endif
@@ -427,6 +433,36 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
427
433
}
428
434
#endif
429
435
436
+
437
+ #ifdef FAULTHANDLER_USE_ALT_STACK
438
+ static int
439
+ faulthandler_allocate_stack (void )
440
+ {
441
+ if (stack .ss_sp != NULL ) {
442
+ return 0 ;
443
+ }
444
+ /* Allocate an alternate stack for faulthandler() signal handler
445
+ to be able to execute a signal handler on a stack overflow error */
446
+ stack .ss_sp = PyMem_Malloc (stack .ss_size );
447
+ if (stack .ss_sp == NULL ) {
448
+ PyErr_NoMemory ();
449
+ return -1 ;
450
+ }
451
+
452
+ int err = sigaltstack (& stack , & old_stack );
453
+ if (err ) {
454
+ /* Release the stack to retry sigaltstack() next time */
455
+ PyMem_Free (stack .ss_sp );
456
+ stack .ss_sp = NULL ;
457
+
458
+ PyErr_SetFromErrno (PyExc_OSError );
459
+ return -1 ;
460
+ }
461
+ return 0 ;
462
+ }
463
+ #endif
464
+
465
+
430
466
/* Install the handler for fatal signals, faulthandler_fatal_error(). */
431
467
432
468
static int
@@ -437,32 +473,35 @@ faulthandler_enable(void)
437
473
}
438
474
fatal_error .enabled = 1 ;
439
475
476
+ #ifdef FAULTHANDLER_USE_ALT_STACK
477
+ if (faulthandler_allocate_stack () < 0 ) {
478
+ return -1 ;
479
+ }
480
+ #endif
481
+
440
482
for (size_t i = 0 ; i < faulthandler_nsignals ; i ++ ) {
441
483
fault_handler_t * handler ;
442
- #ifdef HAVE_SIGACTION
443
- struct sigaction action ;
444
- #endif
445
484
int err ;
446
485
447
486
handler = & faulthandler_handlers [i ];
448
487
assert (!handler -> enabled );
449
488
#ifdef HAVE_SIGACTION
489
+ struct sigaction action ;
450
490
action .sa_handler = faulthandler_fatal_error ;
451
491
sigemptyset (& action .sa_mask );
452
492
/* Do not prevent the signal from being received from within
453
493
its own signal handler */
454
494
action .sa_flags = SA_NODEFER ;
455
- #ifdef HAVE_SIGALTSTACK
456
- if (stack .ss_sp != NULL ) {
457
- /* Call the signal handler on an alternate signal stack
458
- provided by sigaltstack() */
459
- action .sa_flags |= SA_ONSTACK ;
460
- }
495
+ #ifdef FAULTHANDLER_USE_ALT_STACK
496
+ assert (stack .ss_sp != NULL );
497
+ /* Call the signal handler on an alternate signal stack
498
+ provided by sigaltstack() */
499
+ action .sa_flags |= SA_ONSTACK ;
461
500
#endif
462
501
err = sigaction (handler -> signum , & action , & handler -> previous );
463
502
#else
464
503
handler -> previous = signal (handler -> signum ,
465
- faulthandler_fatal_error );
504
+ faulthandler_fatal_error );
466
505
err = (handler -> previous == SIG_ERR );
467
506
#endif
468
507
if (err ) {
@@ -676,17 +715,37 @@ faulthandler_dump_traceback_later(PyObject *self,
676
715
}
677
716
678
717
tstate = get_thread_state ();
679
- if (tstate == NULL )
718
+ if (tstate == NULL ) {
680
719
return NULL ;
720
+ }
681
721
682
722
fd = faulthandler_get_fileno (& file );
683
- if (fd < 0 )
723
+ if (fd < 0 ) {
684
724
return NULL ;
725
+ }
726
+
727
+ if (!thread .running ) {
728
+ thread .running = PyThread_allocate_lock ();
729
+ if (!thread .running ) {
730
+ return PyErr_NoMemory ();
731
+ }
732
+ }
733
+ if (!thread .cancel_event ) {
734
+ thread .cancel_event = PyThread_allocate_lock ();
735
+ if (!thread .cancel_event || !thread .running ) {
736
+ return PyErr_NoMemory ();
737
+ }
738
+
739
+ /* cancel_event starts to be acquired: it's only released to cancel
740
+ the thread. */
741
+ PyThread_acquire_lock (thread .cancel_event , 1 );
742
+ }
685
743
686
744
/* format the timeout */
687
745
header = format_timeout (timeout_us );
688
- if (header == NULL )
746
+ if (header == NULL ) {
689
747
return PyErr_NoMemory ();
748
+ }
690
749
header_len = strlen (header );
691
750
692
751
/* Cancel previous thread, if running */
@@ -728,9 +787,10 @@ faulthandler_cancel_dump_traceback_later_py(PyObject *self,
728
787
}
729
788
#endif /* FAULTHANDLER_LATER */
730
789
790
+
731
791
#ifdef FAULTHANDLER_USER
732
792
static int
733
- faulthandler_register (int signum , int chain , _Py_sighandler_t * p_previous )
793
+ faulthandler_register (int signum , int chain , _Py_sighandler_t * previous_p )
734
794
{
735
795
#ifdef HAVE_SIGACTION
736
796
struct sigaction action ;
@@ -745,19 +805,19 @@ faulthandler_register(int signum, int chain, _Py_sighandler_t *p_previous)
745
805
own signal handler */
746
806
action .sa_flags = SA_NODEFER ;
747
807
}
748
- #ifdef HAVE_SIGALTSTACK
749
- if (stack .ss_sp != NULL ) {
750
- /* Call the signal handler on an alternate signal stack
751
- provided by sigaltstack() */
752
- action .sa_flags |= SA_ONSTACK ;
753
- }
808
+ #ifdef FAULTHANDLER_USE_ALT_STACK
809
+ assert (stack .ss_sp != NULL );
810
+ /* Call the signal handler on an alternate signal stack
811
+ provided by sigaltstack() */
812
+ action .sa_flags |= SA_ONSTACK ;
754
813
#endif
755
- return sigaction (signum , & action , p_previous );
814
+ return sigaction (signum , & action , previous_p );
756
815
#else
757
816
_Py_sighandler_t previous ;
758
817
previous = signal (signum , faulthandler_user );
759
- if (p_previous != NULL )
760
- * p_previous = previous ;
818
+ if (previous_p != NULL ) {
819
+ * previous_p = previous ;
820
+ }
761
821
return (previous == SIG_ERR );
762
822
#endif
763
823
}
@@ -861,6 +921,12 @@ faulthandler_register_py(PyObject *self,
861
921
user = & user_signals [signum ];
862
922
863
923
if (!user -> enabled ) {
924
+ #ifdef FAULTHANDLER_USE_ALT_STACK
925
+ if (faulthandler_allocate_stack () < 0 ) {
926
+ return NULL ;
927
+ }
928
+ #endif
929
+
864
930
err = faulthandler_register (signum , chain , & previous );
865
931
if (err ) {
866
932
PyErr_SetFromErrno (PyExc_OSError );
@@ -1094,7 +1160,7 @@ faulthandler_fatal_error_py(PyObject *self, PyObject *args)
1094
1160
Py_RETURN_NONE ;
1095
1161
}
1096
1162
1097
- #if defined(HAVE_SIGALTSTACK ) && defined( HAVE_SIGACTION )
1163
+ #if defined(FAULTHANDLER_USE_ALT_STACK )
1098
1164
#define FAULTHANDLER_STACK_OVERFLOW
1099
1165
1100
1166
#ifdef __INTEL_COMPILER
@@ -1153,7 +1219,7 @@ faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
1153
1219
size , depth );
1154
1220
return NULL ;
1155
1221
}
1156
- #endif /* defined(HAVE_SIGALTSTACK ) && defined(HAVE_SIGACTION) */
1222
+ #endif /* defined(FAULTHANDLER_USE_ALT_STACK ) && defined(HAVE_SIGACTION) */
1157
1223
1158
1224
1159
1225
static int
@@ -1318,35 +1384,18 @@ faulthandler_init_enable(void)
1318
1384
PyStatus
1319
1385
_PyFaulthandler_Init (int enable )
1320
1386
{
1321
- #ifdef HAVE_SIGALTSTACK
1322
- int err ;
1323
-
1324
- /* Try to allocate an alternate stack for faulthandler() signal handler to
1325
- * be able to allocate memory on the stack, even on a stack overflow. If it
1326
- * fails, ignore the error. */
1387
+ #ifdef FAULTHANDLER_USE_ALT_STACK
1388
+ memset (& stack , 0 , sizeof (stack ));
1327
1389
stack .ss_flags = 0 ;
1328
1390
/* bpo-21131: allocate dedicated stack of SIGSTKSZ*2 bytes, instead of just
1329
1391
SIGSTKSZ bytes. Calling the previous signal handler in faulthandler
1330
1392
signal handler uses more than SIGSTKSZ bytes of stack memory on some
1331
1393
platforms. */
1332
1394
stack .ss_size = SIGSTKSZ * 2 ;
1333
- stack .ss_sp = PyMem_Malloc (stack .ss_size );
1334
- if (stack .ss_sp != NULL ) {
1335
- err = sigaltstack (& stack , & old_stack );
1336
- if (err ) {
1337
- PyMem_Free (stack .ss_sp );
1338
- stack .ss_sp = NULL ;
1339
- }
1340
- }
1341
1395
#endif
1396
+
1342
1397
#ifdef FAULTHANDLER_LATER
1343
- thread .file = NULL ;
1344
- thread .cancel_event = PyThread_allocate_lock ();
1345
- thread .running = PyThread_allocate_lock ();
1346
- if (!thread .cancel_event || !thread .running ) {
1347
- return _PyStatus_ERR ("failed to allocate locks for faulthandler" );
1348
- }
1349
- PyThread_acquire_lock (thread .cancel_event , 1 );
1398
+ memset (& thread , 0 , sizeof (thread ));
1350
1399
#endif
1351
1400
1352
1401
if (enable ) {
@@ -1386,7 +1435,8 @@ void _PyFaulthandler_Fini(void)
1386
1435
1387
1436
/* fatal */
1388
1437
faulthandler_disable ();
1389
- #ifdef HAVE_SIGALTSTACK
1438
+
1439
+ #ifdef FAULTHANDLER_USE_ALT_STACK
1390
1440
if (stack .ss_sp != NULL ) {
1391
1441
/* Fetch the current alt stack */
1392
1442
stack_t current_stack ;
0 commit comments