Skip to content

Commit 46c2b81

Browse files
authored
bpo-30125: Fix faulthandler.disable() on Windows (#1240)
* bpo-30125: Cleanup faulthandler.c * Use size_t type for iterators * Add { ... } * bpo-30125: Fix faulthandler.disable() on Windows On Windows, faulthandler.disable() now removes the exception handler installed by faulthandler.enable().
1 parent 2a1aed0 commit 46c2b81

File tree

2 files changed

+31
-24
lines changed

2 files changed

+31
-24
lines changed

Lib/test/test_faulthandler.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,18 @@ def test_raise_exception(self):
754754
3,
755755
name)
756756

757+
@unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
758+
def test_disable_windows_exc_handler(self):
759+
code = dedent("""
760+
import faulthandler
761+
faulthandler.enable()
762+
faulthandler.disable()
763+
code = faulthandler._EXCEPTION_ACCESS_VIOLATION
764+
faulthandler._raise_exception(code)
765+
""")
766+
output, exitcode = self.get_output(code)
767+
self.assertEqual(output, [])
768+
self.assertEqual(exitcode, 0xC0000005)
757769

758770

759771
if __name__ == "__main__":

Modules/faulthandler.c

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ static struct {
5555
int fd;
5656
int all_threads;
5757
PyInterpreterState *interp;
58+
#ifdef MS_WINDOWS
59+
void *exc_handler;
60+
#endif
5861
} fatal_error = {0, NULL, -1, 0};
5962

6063
#ifdef FAULTHANDLER_LATER
@@ -395,8 +398,7 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
395398

396399
if (code == EXCEPTION_ACCESS_VIOLATION) {
397400
/* disable signal handler for SIGSEGV */
398-
size_t i;
399-
for (i=0; i < faulthandler_nsignals; i++) {
401+
for (size_t i=0; i < faulthandler_nsignals; i++) {
400402
fault_handler_t *handler = &faulthandler_handlers[i];
401403
if (handler->signum == SIGSEGV) {
402404
faulthandler_disable_fatal_handler(handler);
@@ -418,14 +420,12 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
418420
static int
419421
faulthandler_enable(void)
420422
{
421-
size_t i;
422-
423423
if (fatal_error.enabled) {
424424
return 0;
425425
}
426426
fatal_error.enabled = 1;
427427

428-
for (i=0; i < faulthandler_nsignals; i++) {
428+
for (size_t i=0; i < faulthandler_nsignals; i++) {
429429
fault_handler_t *handler;
430430
#ifdef HAVE_SIGACTION
431431
struct sigaction action;
@@ -462,7 +462,8 @@ faulthandler_enable(void)
462462
}
463463

464464
#ifdef MS_WINDOWS
465-
AddVectoredExceptionHandler(1, faulthandler_exc_handler);
465+
assert(fatal_error.exc_handler == NULL);
466+
fatal_error.exc_handler = AddVectoredExceptionHandler(1, faulthandler_exc_handler);
466467
#endif
467468
return 0;
468469
}
@@ -504,17 +505,20 @@ faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
504505
static void
505506
faulthandler_disable(void)
506507
{
507-
unsigned int i;
508-
fault_handler_t *handler;
509-
510508
if (fatal_error.enabled) {
511509
fatal_error.enabled = 0;
512-
for (i=0; i < faulthandler_nsignals; i++) {
510+
for (size_t i=0; i < faulthandler_nsignals; i++) {
511+
fault_handler_t *handler;
513512
handler = &faulthandler_handlers[i];
514513
faulthandler_disable_fatal_handler(handler);
515514
}
516515
}
517-
516+
#ifdef MS_WINDOWS
517+
if (fatal_error.exc_handler != NULL) {
518+
RemoveVectoredExceptionHandler(fatal_error.exc_handler);
519+
fatal_error.exc_handler = NULL;
520+
}
521+
#endif
518522
Py_CLEAR(fatal_error.file);
519523
}
520524

@@ -777,9 +781,7 @@ faulthandler_user(int signum)
777781
static int
778782
check_signum(int signum)
779783
{
780-
unsigned int i;
781-
782-
for (i=0; i < faulthandler_nsignals; i++) {
784+
for (size_t i=0; i < faulthandler_nsignals; i++) {
783785
if (faulthandler_handlers[i].signum == signum) {
784786
PyErr_Format(PyExc_RuntimeError,
785787
"signal %i cannot be registered, "
@@ -1122,16 +1124,12 @@ faulthandler_stack_overflow(PyObject *self)
11221124
static int
11231125
faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
11241126
{
1125-
#ifdef FAULTHANDLER_USER
1126-
unsigned int signum;
1127-
#endif
1128-
11291127
#ifdef FAULTHANDLER_LATER
11301128
Py_VISIT(thread.file);
11311129
#endif
11321130
#ifdef FAULTHANDLER_USER
11331131
if (user_signals != NULL) {
1134-
for (signum=0; signum < NSIG; signum++)
1132+
for (size_t signum=0; signum < NSIG; signum++)
11351133
Py_VISIT(user_signals[signum].file);
11361134
}
11371135
#endif
@@ -1342,10 +1340,6 @@ int _PyFaulthandler_Init(void)
13421340

13431341
void _PyFaulthandler_Fini(void)
13441342
{
1345-
#ifdef FAULTHANDLER_USER
1346-
unsigned int signum;
1347-
#endif
1348-
13491343
#ifdef FAULTHANDLER_LATER
13501344
/* later */
13511345
if (thread.cancel_event) {
@@ -1363,8 +1357,9 @@ void _PyFaulthandler_Fini(void)
13631357
#ifdef FAULTHANDLER_USER
13641358
/* user */
13651359
if (user_signals != NULL) {
1366-
for (signum=0; signum < NSIG; signum++)
1360+
for (size_t signum=0; signum < NSIG; signum++) {
13671361
faulthandler_unregister(&user_signals[signum], signum);
1362+
}
13681363
PyMem_Free(user_signals);
13691364
user_signals = NULL;
13701365
}

0 commit comments

Comments
 (0)