GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Data race in `faulthandler.enable()` and `faulthandler.disable()` with free-threading · Issue #151363 · python/cpython

Data race in faulthandler.enable() and faulthandler.disable() with free-threading #151363

New issue
Copy link
New issue
Copy link
Open
Open
Data race in faulthandler.enable() and faulthandler.disable() with free-threading#151363
Copy link
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@Naserume
Naserume
opened on Jun 11, 2026
Issue body actions

Bug report

Bug description:

faulthandler.enable() and faulthandler.disable() read and write the global fatal_error state with no synchronization. enable() checks the enabled guard and then sets it,

cpython/Modules/faulthandler.c

Lines 536 to 541 in b18168c

faulthandler_enable(void)
{
if (fatal_error.enabled) {
return 0;
}
fatal_error.enabled = 1;

while disable() reads the same guard and tears the state back down, including Py_CLEAR(fatal_error.file),

cpython/Modules/faulthandler.c

Lines 641 to 658 in b18168c

faulthandler_disable(void)
{
if (fatal_error.enabled) {
fatal_error.enabled = 0;
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);
}

so two threads calling enable() and disable() concurrently race on the enabled flag, on the installed signal handlers, and on the fatal_error.file reference.

Reproducer:

import faulthandler, os
from threading import Thread, Event

def owner():
    f = open(os.devnull, 'w')
    for _ in range(200000):
        faulthandler.enable(file=f, all_threads=False)
        f.write('x')
        f.flush()
    f.close()

def toggler():
    for _ in range(200000):
        faulthandler.disable()

threads  = [Thread(target=owner)   for _ in range(4)]
threads += [Thread(target=toggler) for _ in range(4)]
for t in threads: t.start()
for t in threads: t.join()

With TSAN build, the owner thread's own f.write()/enable() raises ValueError: I/O operation on uninitialized object because a concurrent disable() dropped the last reference to f and finalized it.

TSAN Report:

WARNING: ThreadSanitizer: data race (pid=1671402)
  Write of size 4 at 0x555555e19478 by thread T5:
    #0 faulthandler_disable /cpython/./Modules/faulthandler.c:644:29 (python3.16t+0x57830e) 
    #1 faulthandler_disable_py_impl /cpython/./Modules/faulthandler.c:674:5  
    #2 faulthandler_disable_py /cpython/./Modules/clinic/faulthandler.c.h:299:12 
    #3 cfunction_vectorcall_NOARGS /cpython/Objects/methodobject.c:508:24  
    #4 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11  
    #5 PyObject_Vectorcall /cpython/Objects/call.c:327:12 
...

  Previous read of size 4 at 0x555555e19478 by thread T4:
    #0 faulthandler_enable /cpython/./Modules/faulthandler.c:538:21  
    #1 faulthandler_py_enable_impl /cpython/./Modules/faulthandler.c:633:9 
    #2 faulthandler_py_enable /cpython/./Modules/clinic/faulthandler.c.h:278:20 
    #3 cfunction_vectorcall_FASTCALL_KEYWORDS /cpython/Objects/methodobject.c:465:24  
    #4 _PyObject_VectorcallTstate /cpython/./Include/internal/pycore_call.h:144:11  
    #5 PyObject_Vectorcall /cpython/Objects/call.c:327:12 
...

  Location is global '_PyRuntime' of size 405824 at 0x555555e16c80 

SUMMARY: ThreadSanitizer: data race /cpython/./Modules/faulthandler.c:644:29 in faulthandler_disable
==================

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Activity

  1. Naserume
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Jun 11, 2026
  2. picnixz
    added
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    on Jun 13, 2026
  3. picnixz commented on Jun 13, 2026

    @picnixz
    picnixz
    on Jun 13, 2026
    Member
    More actions

    I'm not really sure it's common to enable/disable faulthandler concurrently.

    cc @vstinner @colesbury

  4. devdanzin
    added a commit that references this issue on Jul 15, 2026

    Triage faulthandler (known #151363) + tzset (new); track umbrella que…

    f84ec46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.