Skip to content

An interpreter can start running during _interpreters.destroy #127041

Open

Description

@ZeroIntensity

Crash report

What happened?

Now that gh-126914 is out of the way, we can try and deal with some of the other issues related to multithreading and subinterpreters that couldn't get dealt with before. Namely, the is_running_main inside _interpreters.destroy doesn't account for the fact that the interpreter could start running again by another thread after that check has already passed.

Quick reproducer:

from threading import Thread
import _interpreters

interp = _interpreters.create()


def run():
    _interpreters.run_string(interp, "1")
    _interpreters.destroy(interp)


threads = [Thread(target=run) for _ in range(1000)]
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

I think the simplest fix would be to just disallow a subinterpreter from ever set "running main" again after that check has finished. I implemented this already in the (closed) gh-126696, but I'd like to try and refactor that a bit before just copying things over to a new PR.

cc @ericsnowcurrently, let me know if you have a better approach.

CPython versions tested on:

3.13, 3.14, CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

No response

Linked PRs

Activity

  1. utam-1 commented on Nov 12, 2026

    @utam-1
    Contributor

    Hello @ZeroIntensity and @ericsnowcurrently, I'd like to work on it (If neither of you are working on it, and if it's allowed to work on by newcomers). I have reproduced this on Windows 11, Version: 23H2 as well.
    I think this is what's happening in brief?

    Thread 1 (destroy):   check !is_running_main ─────────────> teardown (CRASH)
    Thread 2 (run_str):                           enter & run ───┘
    

    I want to explore something along the following lines:

    Thread 1 (destroy):   lock -> check !running & set destroying -> unlock -> teardown
    Thread 2 (run_str):   lock -> fail if destroying / running    -> unlock
    

    We guard threads.main and use destroying flag via a PyMutex in struct pythreads.

    I'd appreciate your feedback and guidance on this approach before proceeding further.

    Disclosure: I have utilized LLM agents to understand the issue better, and the flow of the program, along with understanding the changes made in earlier PR (in biref).

  2. ZeroIntensity commented on Nov 12, 2026

    @ZeroIntensity
    MemberAuthor

    You can take a stab at this. I would recommend looking into the PEP 788 APIs for fixing this rather than another locking layer.

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 fixes3.14bugs and security fixesextension-modulesC modules in the Modules dirtopic-subinterpreterstype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions