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().
This commit is contained in:
Victor Stinner 2017-04-21 18:06:13 +02:00 committed by GitHub
parent 2a1aed04b0
commit 46c2b81026
2 changed files with 31 additions and 24 deletions

View File

@ -754,6 +754,18 @@ class FaultHandlerTests(unittest.TestCase):
3,
name)
@unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
def test_disable_windows_exc_handler(self):
code = dedent("""
import faulthandler
faulthandler.enable()
faulthandler.disable()
code = faulthandler._EXCEPTION_ACCESS_VIOLATION
faulthandler._raise_exception(code)
""")
output, exitcode = self.get_output(code)
self.assertEqual(output, [])
self.assertEqual(exitcode, 0xC0000005)
if __name__ == "__main__":

View File

@ -55,6 +55,9 @@ static struct {
int fd;
int all_threads;
PyInterpreterState *interp;
#ifdef MS_WINDOWS
void *exc_handler;
#endif
} fatal_error = {0, NULL, -1, 0};
#ifdef FAULTHANDLER_LATER
@ -395,8 +398,7 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
if (code == EXCEPTION_ACCESS_VIOLATION) {
/* disable signal handler for SIGSEGV */
size_t i;
for (i=0; i < faulthandler_nsignals; i++) {
for (size_t i=0; i < faulthandler_nsignals; i++) {
fault_handler_t *handler = &faulthandler_handlers[i];
if (handler->signum == SIGSEGV) {
faulthandler_disable_fatal_handler(handler);
@ -418,14 +420,12 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
static int
faulthandler_enable(void)
{
size_t i;
if (fatal_error.enabled) {
return 0;
}
fatal_error.enabled = 1;
for (i=0; i < faulthandler_nsignals; i++) {
for (size_t i=0; i < faulthandler_nsignals; i++) {
fault_handler_t *handler;
#ifdef HAVE_SIGACTION
struct sigaction action;
@ -462,7 +462,8 @@ faulthandler_enable(void)
}
#ifdef MS_WINDOWS
AddVectoredExceptionHandler(1, faulthandler_exc_handler);
assert(fatal_error.exc_handler == NULL);
fatal_error.exc_handler = AddVectoredExceptionHandler(1, faulthandler_exc_handler);
#endif
return 0;
}
@ -504,17 +505,20 @@ faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
static void
faulthandler_disable(void)
{
unsigned int i;
fault_handler_t *handler;
if (fatal_error.enabled) {
fatal_error.enabled = 0;
for (i=0; i < faulthandler_nsignals; i++) {
for (size_t i=0; i < faulthandler_nsignals; i++) {
fault_handler_t *handler;
handler = &faulthandler_handlers[i];
faulthandler_disable_fatal_handler(handler);
}
}
#ifdef MS_WINDOWS
if (fatal_error.exc_handler != NULL) {
RemoveVectoredExceptionHandler(fatal_error.exc_handler);
fatal_error.exc_handler = NULL;
}
#endif
Py_CLEAR(fatal_error.file);
}
@ -777,9 +781,7 @@ faulthandler_user(int signum)
static int
check_signum(int signum)
{
unsigned int i;
for (i=0; i < faulthandler_nsignals; i++) {
for (size_t i=0; i < faulthandler_nsignals; i++) {
if (faulthandler_handlers[i].signum == signum) {
PyErr_Format(PyExc_RuntimeError,
"signal %i cannot be registered, "
@ -1122,16 +1124,12 @@ faulthandler_stack_overflow(PyObject *self)
static int
faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
{
#ifdef FAULTHANDLER_USER
unsigned int signum;
#endif
#ifdef FAULTHANDLER_LATER
Py_VISIT(thread.file);
#endif
#ifdef FAULTHANDLER_USER
if (user_signals != NULL) {
for (signum=0; signum < NSIG; signum++)
for (size_t signum=0; signum < NSIG; signum++)
Py_VISIT(user_signals[signum].file);
}
#endif
@ -1342,10 +1340,6 @@ int _PyFaulthandler_Init(void)
void _PyFaulthandler_Fini(void)
{
#ifdef FAULTHANDLER_USER
unsigned int signum;
#endif
#ifdef FAULTHANDLER_LATER
/* later */
if (thread.cancel_event) {
@ -1363,8 +1357,9 @@ void _PyFaulthandler_Fini(void)
#ifdef FAULTHANDLER_USER
/* user */
if (user_signals != NULL) {
for (signum=0; signum < NSIG; signum++)
for (size_t signum=0; signum < NSIG; signum++) {
faulthandler_unregister(&user_signals[signum], signum);
}
PyMem_Free(user_signals);
user_signals = NULL;
}