gh-141044: Fix ASan leak with small threading.stack_size() - #157691
Open
KingLizard1020 wants to merge 1 commit into
Open
KingLizard1020 wants to merge 1 commit into
KingLizard1020 wants to merge 1 commit into
Conversation
KingLizard1020
requested review from
AA-Turner,
JacobCoffee,
ezio-melotti,
hugovk,
itamaro and
webknjaz
as code owners
September 17, 2026 17:34
AddressSanitizer instrumentation consumes extra C stack, so the old minimum left no working space above the soft recursion limit. threading.Thread bootstrap then leaked thread objects. Require 6 stack margins under ASan, matching TSan. Cover the unjoined original repro and confirm the new minimum does not leak. Move the NEWS blurb to Library, matching pythongh-143191.
github-actions
Bot
force-pushed
the
cursor/fix-threading-stack-size-leak-a999
branch
from
September 17, 2026 17:36
1f5b1e7 to
00fe666
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fix a LeakSanitizer / reference leak when creating a
threading.Threadafterthreading.stack_size()is set to a small value (the reported repro used 127 KiB and did not join).Issue: #141044
Diagnosis
This is a real reference leak, not an LSan false positive. With a debug + AddressSanitizer build:
threading.stack_size(127 * 1024)followed byThread.start()(with or withoutjoin()) leaksThread/_ThreadHandle/Contextobjects._thread.start_new_thread()at 127 KiB does not leak;threading.Threaddoes, because bootstrap runs_context.run(self.run)thenfinally: self._delete().C stack overflow protection (gh-130396) reserves soft/hard margins at the bottom of each thread stack. Under ASan, instrumentation consumes extra C frames, so the old 3-margin minimum left almost no working space above the soft limit. At 127 KiB,
_testinternalcapi.get_c_recursion_remaining()was already ~50 and bootstrap failed to finish cleanup.3.13 did not use
pthread_getattr_npstack limits, which is why it showed no leak.Fix
When built with AddressSanitizer or ThreadSanitizer, require 6 stack margins for
_PyOS_MIN_STACK_SIZE(same constant TSan already used). Reasons differ and are documented in the header: TSan only uses half the stack intstate_set_stack(); ASan uses the full stack but needs extra room for instrumentation._thread.stack_size()already rejects sizes below_PyOS_MIN_STACK_SIZE + SYSTEM_PAGE_SIZE, so 127 KiB is now aValueErroron ASan builds (~200704 byte minimum on this builder). Non-ASan / release builds are unchanged (still 3 margins).Tests
test_thread.ThreadRunningTests.test_stack_size: ASan-onlyValueErrorfor127 * 1024, and a failed set must leave size at 0.test_threading.ThreadTests.test_stack_size_no_leak: original unjoined 127 KiB repro (exits cleanly when rejected), unjoined + joined threads at the new minimum withgettotalrefcount()andASAN_OPTIONS=detect_leaks=1.Verification
Built with
./configure --with-address-sanitizer --with-pydebug && make -j.Before: LSan reported leaks on the issue reproducer. After:
threading.stack_size(127 * 1024)raisesValueError: size must be at least 200704 bytes. Threads at the new minimum are clean under refcount + LSan (joined and unjoined).Local:
./python -m test test_thread test_threading -v -m '*stack_size*'→ SUCCESS.