Potential race condition in HTTP11Connection._expire_at with GIL disabled #1027
Replies: 1 comment
|
The race in the report is consistent with current main.
keepalive_expired = self._expire_at is not None and now > self._expire_atUnder the GIL that compound expression effectively got more serialization than the code actually guarantees. In a free-threaded build, another thread can set The lock-based workaround is therefore correct in principle, but the critical section can stay very small: take I would also audit the equivalent state-inspection methods rather than fixing only this expression. Free-threading turns previously-benign repeated attribute reads into real synchronization points, and the invariant here is that pool-facing state queries should observe a coherent state transition. A regression test does not need to rely on winning a probabilistic race: a test double or synchronization barrier can pause between the relevant state observations while another thread starts a request, making the old implementation deterministically exercise the invalid transition. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hi,
I'm running httpcore (1.0.9) through httpx (0.28.1) in Python 3.140rc1 free-threaded (ie, with the GIL disabled).
I've noticed an intermittent bug when sending a request in the sync interface:
Seems to be that there is some sort of race condition where the check for
self._expire_at is not Noneinitially returns true but thenself._expire_atis set to None at handle_request:76 before thenow > self._expire_atcheck runs as that part of the code is not protected by a lockI did this workaround here and it is now working:
Thanks for the awesome library. I wasn't able to isolate the issue in a reproductible snippet yet but let me know if you need it.
All reactions