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 — Crash in `ThreadHandle_dealloc` after fork in free-threaded build · Issue #115035 · python/cpython

Crash in ThreadHandle_dealloc after fork in free-threaded build #115035

New issue
Copy link
New issue
Copy link
Closed
Closed
Crash in ThreadHandle_dealloc after fork in free-threaded build#115035
Copy link
Labels
3.13only security fixesonly security fixestopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@colesbury
colesbury
opened on Feb 5, 2024
Issue body actions

Bug report

I've seen this in the free-threaded build, but I think the problem can theoretically occur in the default build as well.

The problem is that after a fork(), an already dead ThreadHandle may be deallocated before it's marked as not joinable. The ThreadHandle_dealloc() function can crash in PyThread_detach_thread():

cpython/Modules/_threadmodule.c

Lines 66 to 70 in bcccf1f

ThreadHandle_dealloc(ThreadHandleObject *self)
{
PyObject *tp = (PyObject *) Py_TYPE(self);
if (self->joinable) {
int ret = PyThread_detach_thread(self->handle);

The steps leading to the crash are:

  1. A thread T2 starts and finishes, but is not joined. The ThreadHandle is not immediately deallocated, either because it's part of a larger reference cycle or due to biased reference counting (in the free-threaded build)
  2. The main thread calls fork()
  3. In the child process, during PyOS_AfterFork_Child(), the ThreadHandle is deallocated. I've seen this happen in the free-threaded build due to biased reference counting merging the thread states in PyThreadState_Clear(). I believe this can also happen in the default build if, for example, a GC is triggered early on during threading._after_fork() before we get to marking the ThreadHandle as not joinable.

Proposed fix

Early on in PyOS_AfterFork_Child(), we should fix up all ThreadHandle objects from C (without executing Python code) -- we should mark the dead ones as not joinable and update the remaining active thread.

I think it's important to do this without executing Python code. Once we start executing Python code, almost anything can happen, such as GC collections, destructors, etc.

cc @pitrou @gpshead @ericsnowcurrently

Linked PRs

  • gh-115035: Mark ThreadHandles as non-joinable earlier after forking #115042

Activity

  1. colesbury
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    3.13only security fixesonly security fixes
    topic-free-threading
    on Feb 5, 2024
  2. pitrou commented on Feb 5, 2024

    @pitrou
    pitrou
    on Feb 5, 2024
    Member
    More actions

    Early on in PyOS_AfterFork_Child(), we should fix up all ThreadHandle objects from C (without executing Python code) -- we should mark the dead ones as not joinable and update the remaining active thread.

    This looks reasonable to me.

  3. colesbury
    added 3 commits that reference this issue on Feb 5, 2024

    pythongh-115035: Mark ThreadHandles as non-joinable earlier

    fecb718

    pythongh-115035: Mark ThreadHandles as non-joinable earlier

    8130173

    gh-115035: Mark ThreadHandles as non-joinable earlier after forking (#…

    b6228b5
  4. fsc-eriker
    added a commit that references this issue on Feb 14, 2024

    pythongh-115035: Mark ThreadHandles as non-joinable earlier after for…

    dffd892
  5. colesbury
    closed this as completedon Feb 14, 2024
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

    3.13only security fixesonly security fixestopic-free-threadingtype-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.