Skip to content

With asynchronous exception raised, thread.is_alive() unexpectedly blocks in Python 3.11 with coverage #1626

Open
@andersk

Description

@andersk

Describe the bug

This program (minimized from Zulip’s TimeoutTestCase.test_timeout_warn) succeeds in Python 3.10 without coverage, 3.10 with coverage, and 3.11 without coverage, but it fails in 3.11 with coverage.

import ctypes
import threading
import time

thread = threading.Thread(target=lambda: time.sleep(1))
thread.daemon = True
thread.start()
time.sleep(0.1)
ctypes.pythonapi.PyThreadState_SetAsyncExc(
    ctypes.c_ulong(thread.ident), ctypes.py_object(TimeoutError)
)
time.sleep(0.1)
thread.is_alive()
time.sleep(0.1)
assert thread.is_alive()

The program spawns sleep(1) in a thread, then uses the Python C API to raise an asynchronous exception within it, which has no immediate effect since it’s still sleeping. Both thread.is_alive() calls should immediately return True. But in Python 3.11 with coverage, it seems the first thread.is_alive() call unexpectedly blocks until the thread’s sleep(1) finishes before returning, so the second thread.is_alive() call returns False.

A git bisect of Python shows that this started failing with

To Reproduce

Run python3.11 -m coverage run test.py. I’m using the latest coverage==7.2.5 on Linux x86-64 (NixOS 23.05).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions