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 — Deadlock when calling PyGILState_Ensure() from a fresh C thread · Issue #96071 · python/cpython

Deadlock when calling PyGILState_Ensure() from a fresh C thread #96071

New issue
Copy link
New issue
Copy link
Closed
Closed
Deadlock when calling PyGILState_Ensure() from a fresh C thread#96071
Copy link
Assignees
ericsnowcurrentlykumaraditya303
Labels
3.11only security fixesonly security fixes3.12only security fixesonly security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@tom-pytel
tom-pytel
opened on Aug 18, 2022
Issue body actions

Bug report

This used to work with py 3.8, 3.9 and 3.10 but now fails. The failure is due to a deadlock condition due to the move of an alloc from before a HEAD_LOCK() to after causing a recursive call to PyGILState_Ensure() which eventually deadlocks on the HEAD_LOCK().

The following is a trace of calls from the initial call to PyGILState_Ensure() to the eventual deadlock:

pystate:PyGILState_Ensure()
pystate:PyThreadState_New()
pystate:new_threadstate()
  HEAD_LOCK()  <-- Initial head locked, the alloc_threadstate() call below used to happen before this in previous versions of Python.
pystate:alloc_threadstate()
obmalloc:PyMem_RawCalloc()
_tracemalloc:_PyMem_Raw.calloc()
_tracemalloc:tracemalloc_raw_calloc()
  get_reentrant() = 0
  set_reenterant(1)
pystate:PyGILState_Ensure()
pystate:PyThreadState_New()
pystate:new_threadstate()
  HEAD_LOCK()  <--   DEADLOCK HERE!

Steps to reproduce: In a Python C extension module, create a C thread then try to call PyGILState_Ensure() in that thread with no previous existing Python threadstate.

Your environment

Python 3.11.0rc1
Linux tom-VirtualBox 5.15.0-46-generic #49~20.04.1-Ubuntu SMP Thu Aug 4 19:15:44 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Activity

Next
  1. tom-pytel
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Aug 18, 2022
  2. ronaldoussoren
    added
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    on Aug 18, 2022
  3. ronaldoussoren commented on Aug 18, 2022

    @ronaldoussoren
    ronaldoussoren
    on Aug 18, 2022
    Contributor
    More actions

    Do you have a self-contained example that demonstrates the problem? I quickly checked using PyObjC on macOS (which basically does this when starting threads using the Cocoa interface), and that code did not deadlock.

  4. tom-pytel commented on Aug 18, 2022

    @tom-pytel
    tom-pytel
    on Aug 18, 2022
    ContributorAuthor
    More actions

    Do you have a self-contained example that demonstrates the problem? I quickly checked using PyObjC on macOS (which basically does this when starting threads using the Cocoa interface), and that code did not deadlock.

    Ok, I investigated a little deeper and admittedly I have a bit more going on in the environment where I found this. Tried duplicating until I found the difference: tracemalloc. When tracemalloc is imported and started the function flow is as shown in the header of this issue. When it is not, then after obmalloc:PyMem_RawCalloc() it goes to obmalloc:_PyMem_DebugRawCalloc() instead of _tracemalloc:_PyMem_Raw.calloc() which avoids the recursive call to PyGILState_Ensure() and works fine. I will see about getting some poc module code here tomorrow or after.

  5. ronaldoussoren commented on Aug 18, 2022

    @ronaldoussoren
    ronaldoussoren
    on Aug 18, 2022
    Contributor
    More actions

    I can reproduce using PyObjC by using python3.11 -X tracemalloc script.py to start the PyObjC using script I mentioned earlier.

    @pablogsal is this a release blocker?

  6. pablogsal commented on Aug 18, 2022

    @pablogsal
    pablogsal
    on Aug 18, 2022
    Member
    More actions

    @pablogsal is this a release blocker?

    Indeed it is. Thanks for pinging me.

  7. pablogsal
    added
    release-blocker
    on Aug 18, 2022
  8. ezio-melotti
    added this to Release and Deferred blockers 🚫on Aug 18, 2022
  9. ezio-melotti
    moved this to Todo in Release and Deferred blockers 🚫on Aug 18, 2022
  10. pablogsal commented on Aug 18, 2022

    @pablogsal
    pablogsal
    on Aug 18, 2022
    Member
    More actions

    @ronaldoussoren Can you share the reproducer?

  11. pablogsal
    assigned
    ericsnowcurrently
    on Aug 18, 2022
  12. pablogsal commented on Aug 18, 2022

    @pablogsal
    pablogsal
    on Aug 18, 2022
    Member
    More actions

    Or alternatively, could you bisect the issue?

  13. tom-pytel commented on Aug 18, 2022

    @tom-pytel
    tom-pytel
    on Aug 18, 2022
    ContributorAuthor
    More actions

    Or alternatively, could you bisect the issue?

    In previous versions the memory for the new PyThreadState was allocated before the HEAD_LOCK() in pystate:new_threadstate(), if you revert to that behavior the bug is fixed.

  14. ronaldoussoren commented on Aug 18, 2022

    @ronaldoussoren
    ronaldoussoren
    on Aug 18, 2022
    Contributor
    More actions

    The reproducer needs PyObjC (from v8.5-branch in https://github.com/ronaldoussoren/pyobjc because the latest release does not work with Python 3.11 yet).

    The reproducer script:

    from Cocoa import NSObject, NSThread
    import time
    
    class Runner(NSObject):
       def doit_(self, arg):
           print("hello world")
           print(NSThread.currentThread().isMainThread())
    
    
    runner = Runner.alloc().init()
    
    thread = NSThread.alloc().initWithTarget_selector_object_(runner, b"doit:", None)
    thread.start()
    print(thread)
    time.sleep(1)
    while thread.isExecuting():
        time.sleep(1)
    

    This script hangs when using "python3.11 -X tracemalloc script.pyand works fine when using an older version of Python or leaving out-X tracemalloc``.

    It is probably easier to reproduce this using a small C extension that uses pthread_create to launch a thread that call PyGILState_Ensure.

    I can look into this during the weekend at the earliest, but also need to get a release of PyObjC out to fix Python 3.11 support (which is needed due to documented API changes, nothing to worry about there).

  15. pablogsal commented on Aug 18, 2022

    @pablogsal
    pablogsal
    on Aug 18, 2022
    Member
    More actions

    I will prepare a patch tomorrow. I have enough information to produce a fix.

  16. 16 remaining items

  17. ericsnowcurrently commented on Aug 22, 2022

    @ericsnowcurrently
    ericsnowcurrently
    on Aug 22, 2022
    Member
    More actions

    We can close this once gh-96184 and gh-96185 are merged.

  18. kumaraditya303
    added 2 commits that reference this issue on Aug 23, 2022

    [3.10] pythonGH-96071: add regression test for pythonGH-96071 (python…

    43ee75d

    [3.10] pythonGH-96071: add regression test for pythonGH-96071 (python…

    10e5d8b
  19. miss-islington
    added a commit that references this issue on Aug 23, 2022

    GH-96071: add regression test for GH-96071 (GH-96137)

    0aed1e7
  20. pablogsal
    added a commit that references this issue on Aug 23, 2022

    [3.10] GH-96071: add regression test for GH-96071 (GH-96137) (#96205)

    e3c4a5b
  21. kumaraditya303 commented on Aug 24, 2022

    @kumaraditya303
    kumaraditya303
    on Aug 24, 2022
    Contributor
    More actions

    Closing as I have fixed both the issue and added tests to ensure no further regression. Thanks!

  22. kumaraditya303
    closed this as completedon Aug 24, 2022
  23. Repository owner moved this from In Progress to Done in Release and Deferred blockers 🚫on Aug 24, 2022
  24. ericsnowcurrently commented on Aug 24, 2022

    @ericsnowcurrently
    ericsnowcurrently
    on Aug 24, 2022
    Member
    More actions

    Thanks, @kumaraditya303!

    Reacted by Kumar Aditya
  25. mdboom
    added a commit that references this issue on Aug 24, 2022

    pythonGH-96071: add regression test for python#96071 (pythonGH-96137)

    0dc6d4e
  26. JanWielemaker
    added a commit that references this issue on Jul 25, 2023

    ADDED: py_with_gil/1 and use the GIL in pl_call/1,2

    3ddc1bb
  27. ericsnowcurrently
    added 2 commits that reference this issue on Nov 19, 2024

    gh-126914: Store the Preallocated Thread State's Pointer in a PyInter…

    1c0a104

    pythongh-126914: Store the Preallocated Thread State's Pointer in a P…

    9581448
  28. ericsnowcurrently
    added a commit that references this issue on Dec 2, 2024

    [3.13] gh-126914: Store the Preallocated Thread State's Pointer in a …

    219b826
  29. ebonnal
    added a commit that references this issue on Jan 12, 2025

    pythongh-126914: Store the Preallocated Thread State's Pointer in a P…

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

Metadata

Metadata

Assignees

  • @ericsnowcurrently
    ericsnowcurrently
  • @kumaraditya303
    kumaraditya303

Labels

3.11only security fixesonly security fixes3.12only security fixesonly security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Projects

  • Release and Deferred blockers 🚫
    Status
    Done
    Show more project fields

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.