GeezerVison is showing github.com — gh-161769: Preserve errno across release thread-state attachment by Robolightning · Pull Request #161770 · python/cpython
Conversation
Preserve the existing errno value across _PyThreadState_Attach() in release builds as well as debug builds. On a release free-threaded build, reattachment can change errno after a native wait, making valid directory EOF raise spurious EAGAIN.
The native change only removes the two Py_DEBUG conditionals around the existing save/restore. The regression now uses a 16-line method with four ordinary threads, GC and os.listdir, using the existing run_concurrently helper. No subinterpreter, FileFinder, JSON, ThreadPool or custom shutdown helper is needed.
The identical reduced test fails with errno 11 before the native fix and passes afterwards on native release free-threaded musl source builds of both main and 3.15. The complete test_os module then passes both tests on each corrected runtime, with natural GIL off. The earlier retained IO, GC, threading and import qualification covered 2,100 cases on 3.15 and 2,120 on main, with zero failures/errors and their original platform skips; the native patch has not changed. Upstream CI for aac344d completed successfully: all 48 jobs in the Tests workflow, the lint and label workflows, and all 56 check/status contexts were green when verified.
Fixes #161769. Includes a NEWS entry. No third-party module or installed SDK is changed.
AI assistance was used for investigation, patch/test preparation and this description. The before/after and standard-library results come from real native source builds.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Keep the existing _PyThreadState_Attach errno save/restore in release
builds as well as debug builds. A release free-threaded attachment can
wait for GC or critical-section resumption and change errno, causing valid
directory EOF and cold FileFinder operations to raise spurious EAGAIN.
Add a public directory/scandir/FileFinder regression under real child-local
GC, without native diagnostic modules or third-party code. The identical
test fails on current main 3.16 before the four-guard-line change and passes
afterwards. Original IO, GC, threading and import suites also pass on the
native musl release FT source build. No installed SDK is modified.
|
All commit authors signed the Contributor License Agreement.

|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Correct the new NEWS reference rejected by the actual Docs job. Keep the
qualified native source and public regression unchanged.
Actual upstream TSanFT reached the new hard30second worker-join timeout
before the scanners finished. Use test.support.LONG_TIMEOUT as recommended
for slow/instrumented buildbots. Keep all scan/GC workload and assertions.
Re-prove the identical adjusted test on both current3.15 andmain native
release FT cores: actual BlockingIOError before, PASS after unchanged errno
fix. Original failing CI log and native loaded-library hashes are retained.
|
Thank you for your interest in contributing to Python. This is a community-driven project, and we want it to be a welcoming place to learn and collaborate.
Contributors are responsible for reviewing and understanding what they submit, checking its claims, and being able to explain changes in their own words. This helps reviewers focus on the contribution and leaves more time to support other contributors.
This contribution appears to have been authored with AI assistance. Please explain your contribution in your own words and describe how you checked its correctness.
Please read our guidelines for using AI tools.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
I can only reproduce this on musl; elsewhere the new test passes without the fix. Please explain why and make sure your changes are minimal and focused.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Replace the directory/SI lifecycle helper with one public listdir test
using the existing run_concurrently helper. Four ordinary threads each
collect GC and check a real directory. No FileFinder, JSON, subinterpreters,
ThreadPool, custom stop/barrier or deadline logic is needed.
The exact smaller test reproduced BlockingIOError errno11 before and
passed after the unchanged native errno fix on both main and3.15 native
Release FT musl cores. The existing strerror test remains unchanged and
the full test_os module passes on both corrected runtimes.
|
AI-assisted technical explanation, posted at the author's request.
musl’s blocking semaphore path can return success while leaving errno set to EAGAIN: sem_trywait sets it when empty, and sem_timedwait, also used by sem_wait, can subsequently succeed without restoring the incoming value. A separate valid POSIX semaphore example returned 0 with errno 11 on musl 1.2.6; the identical program returned 0 with errno 0 on glibc. This is an observed libc difference, not a claim that glibc must always preserve errno.
In CPython, reattachment can park during GC and reach _PySemaphore_Wait. os.listdir checks errno after Py_END_ALLOW_THREADS, so reattachment can turn a successful readdir EOF into a spurious error. Debug builds already save/restore errno here; the native fix remains just the removal of four conditional-compilation lines.
The regression is now a 16-line method in aac344d, using four ordinary threads, GC, os.listdir, and the existing run_concurrently helper. The identical reduced test genuinely failed with errno 11 before and passed after the unchanged fix on both main and 3.15 native release free-threaded musl builds, once per phase, with mapped-library hashes checked. The full test_os module then passed both tests on each corrected runtime. This also explains why a passing pre-fix run on another libc does not rule out the bug.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|