Skip to content
Open
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
00fe666
gh-141044: Fix ASan leak with small threading.stack_size()
KingLizard1020 Sep 17, 2026
3aef310
gh-141044: Require 6 stack margins on debug builds too
KingLizard1020 Sep 21, 2026
09dc0cb
gh-141044: Update NEWS for debug/sanitizer 6-margin floor
KingLizard1020 Sep 21, 2026
04ebedb
gh-141044: Portable 127 KiB stack_size rejection check
KingLizard1020 Sep 21, 2026
bfbf64c
gh-141044: Restore test_thread.py (undo accidental PLACEHOLDER)
KingLizard1020 Sep 21, 2026
7f942ca
gh-141044: Silence NEWS Sphinx nit for _thread.stack_size
KingLizard1020 Sep 21, 2026
1fac29a
gh-141044: Raise TSan stack_size floor to 12 margins
KingLizard1020 Sep 21, 2026
0f0971d
gh-141044: Update NEWS for TSan 12-margin stack_size floor
KingLizard1020 Sep 21, 2026
f2242a1
gh-141044: Allow stack_size tests to skip 256 KiB under TSan
KingLizard1020 Sep 21, 2026
4d72b7e
gh-141044: Skip 256 KiB stack tests when below TSan floor
KingLizard1020 Sep 21, 2026
c15bbbd
temp: canary for restore path (will remove)
KingLizard1020 Sep 21, 2026
ab3acf1
temp: escape-test canary (will remove)
KingLizard1020 Sep 21, 2026
c43e6b8
wip: restore test_threading.py (5KB partial)
KingLizard1020 Sep 21, 2026
d012c29
temp: remove restore canary
KingLizard1020 Sep 21, 2026
12213d2
test @file
KingLizard1020 Sep 21, 2026
bb6fe83
wip: restore test_threading.py (5KB partial, undo @path probe)
KingLizard1020 Sep 21, 2026
124b140
gh-141044: Fix Docs soft-deprecated KeyError in changes builder
KingLizard1020 Sep 21, 2026
f609ce4
Add cpy test_threading restore part _cpy_tt_part_0.b64 (no trigger)
KingLizard1020 Sep 21, 2026
fe78d4b
Add cpy test_threading restore part _cpy_tt_part_1.b64 (no trigger)
KingLizard1020 Sep 21, 2026
4eb90e5
Fix part1 chunk0 of cpy test_threading restore
KingLizard1020 Sep 21, 2026
6222f46
Restore threading regression tests and update from main
KingLizard1020 Sep 22, 2026
de3886e
Fix threading tests for sanitizer stack minimum
KingLizard1020 Sep 22, 2026
be750c5
Merge upstream main into PR #157691
KingLizard1020 Sep 23, 2026
af31989
Merge branch 'main' into cursor/fix-threading-stack-size-leak-a999
KingLizard1020 Sep 24, 2026
db9370d
Merge remote-tracking branch 'upstream/main' into cursor/fix-threadin…
KingLizard1020 Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
temp: escape-test canary (will remove)
  • Loading branch information
KingLizard1020 committed Sep 21, 2026
commit ab3acf17af550464564fbda57ee3f3b6bed99745
146 changes: 145 additions & 1 deletion Lib/test/_restore_canary.txt
Original file line number Diff line number Diff line change
@@ -1 +1,145 @@
canary-ok
:
x = C()
ready.release()
time.sleep(100)

_thread.start_new_thread(waitingThread, ())
ready.acquire() # Be sure the other thread is waiting.
sys.exit(42)
""")
self.assertEqual(rc, 42)

def test_finalize_with_trace(self):
# Issue1733757
# Avoid a deadlock when sys.settrace steps into threading._shutdown
if support.check_sanitizer(thread=True):
# the thread running `time.sleep(2)` below will still be alive
# at process exit
self.skipTest("TSAN would report thread leak")

assert_python_ok("-c", """if 1:
import sys, threading

# A deadlock-killer, to prevent the
# testsuite to hang forever
def killer():
import os, time
time.sleep(2)
print('program blocked; aborting')
os._exit(2)
t = threading.Thread(target=killer)
t.daemon = True
t.start()

# This is the trace function
def func(frame, event, arg):
threading.current_thread()
return func

sys.settrace(func)
""")

def test_join_nondaemon_on_shutdown(self):
# Issue 1722344
# Raising SystemExit skipped threading._shutdown
rc, out, err = assert_python_ok("-c", """if 1:
import threading
from time import sleep

def child():
sleep(1)
# As a non-daemon thread we SHOULD wake up and nothing
# should be torn down yet
print("Woke up, sleep function is:", sleep)

threading.Thread(target=child).start()
raise SystemExit
""")
self.assertEqual(out.strip(),
b"Woke up, sleep function is: <built-in function sleep>")
self.assertEqual(err, b"")

def test_enumerate_after_join(self):
# Try hard to trigger #1703448: a thread is still returned in
# threading.enumerate() after it has been join()ed.
enum = threading.enumerate
old_interval = sys.getswitchinterval()
try:
for i in range(1, 100):
support.setswitchinterval(i * 0.0002)
t = threading.Thread(target=lambda: None)
t.start()
t.join()
l = enum()
self.assertNotIn(t, l,
"#1703448 triggered after %d trials: %s" % (i, l))
finally:
sys.setswitchinterval(old_interval)

@support.bigmemtest(size=20, memuse=72*2**20, dry_run=False)
def test_join_from_multiple_threads(self, size):
# Thread.join() should be thread-safe
errors = []

def worker():
time.sleep(0.005)

def joiner(thread):
try:
thread.join()
except Exception as e:
errors.append(e)

for N in range(2, 20):
threads = [threading.Thread(target=worker)]
for i in range(N):
threads.append(threading.Thread(target=joiner,
args=(threads[0],)))
for t in threads:
t.start()
time.sleep(0.01)
for t in threads:
t.join()
if errors:
raise errors[0]

def test_join_with_timeout(self):
lock = _thread.allocate_lock()
lock.acquire()

def worker():
lock.acquire()

thread = threading.Thread(target=worker)
thread.start()
thread.join(timeout=0.01)
assert thread.is_alive()
lock.release()
thread.join()
assert not thread.is_alive()

def test_no_refcycle_through_target(self):
class RunSelfFunction(object):
def __init__(self, should_raise):
# The links in this refcycle from Thread back to self
# should be cleaned up when the thread completes.
self.should_raise = should_raise
self.thread = threading.Thread(target=self._run,
args=(self,),
kwargs={'yet_another':self})
self.thread.start()

def _run(self, other_ref, yet_another):
if self.should_raise:
raise SystemExit

restore_default_excepthook(self)

cyclic_object = RunSelfFunction(should_raise=False)
weak_cyclic_object = weakref.ref(cyclic_object)
cyclic_object.thread.join()
del cyclic_object
self.assertIsNone(weak_cyclic_object(),
msg=('%d references still around' %
sys.getrefcount(weak_cyclic_object())))

Loading