When an import failed with a stack overflow RecursionError, releasing the import locks on the error path could itself raise RecursionError, because the cleanup runs in a new C frame. This left the global import lock or a module lock held forever, and later imports in other threads blocked indefinitely.
_imp.acquire_lock() now raises RecursionError when there is not enough stack left to release the lock. importlib calls it before taking any import lock, so this covers the per-module locks too. The module lock weakref callback skips cleanup in that case instead of
reporting an unraisable exception.
SSLProtocol.connection_lost() did not notify the application protocol
while a handshake was in progress, even when start_tls() had handed
over a protocol that had already seen connection_made(). With streams
this left StreamWriter.wait_closed() waiting forever.
ANT-2026-A6ZIAFVT
ANT-2026-4SKWM05E
AST nodes had an explicit `__dict__` slot, so every node built by
`ast.parse` allocated its own dict. With `Py_TPFLAGS_MANAGED_DICT`,
node attributes are stored as inline values with shared keys instead.
`ast.parse` is ~15.8% faster, walking trees is ~15.9% faster, and
the memory used by the AST trees is reduced by ~51.6%.
In the free-threaded build, compile() of a source string sets
suppress_co_const_immortalization so that its output is the same as in
the default build. The branch for AST objects returned before that, so
constants were replaced by the immortal ones of the interpreter's table
while a tuple of names (such as co_names) which was the same object was
not, and the marshal output depended on the code objects created before
in the process.
Keep the SSL shutdown timer running until connection_lost(), and start
it when the peer shuts down first, so that a peer which sends EOF but
does not read cannot keep a closed transport open indefinitely.
ANT-2026-81HUBBJ7
ZSTD_freeCCtx() frees a dictionary loaded with ZSTD_CCtx_loadDictionary()
before it stops the worker threads. Make libzstd wait for unfinished
jobs before freeing the compression context of a ZstdCompressor that
uses worker threads and a ZstdDict.
Works around https://github.com/facebook/zstd/issues/4862
The garbage collector could release a ZstdCompressor's dictionary, or
the digested dictionaries cached by the ZstdDict, while worker threads
of the compression context were still reading them. They are now only
released on deallocation, after the context has been freed.
ANT-2026-CT3P1CSJ
+ Visit the type in the compressor and decompressor traverse; move NEWS to Library
Since gh-83065 (3.15.0), the first import of pkg.mod kept pkg's module
lock until pkg/mod.py had finished executing. Threads that needed only
the finished pkg stayed blocked for that long, and concurrent first
imports could raise _DeadlockError or a spurious "partially initialized
module" ImportError, or hang, with no import cycle involved.
Parent packages are now imported, or waited for if another thread is
initializing them, before the submodule's module lock is taken, so only
that lock is held while the submodule executes. The lock ordering
deadlock fixed by gh-83065 stays fixed.
importlib.import_module() now returns the partially initialized module
in a circular import split across threads, as the import statement
already did, instead of raising _DeadlockError. That was long-standing
behavior rather than part of the 3.15.0 regression.
A cursor exposed its description tuple before filling in all the columns, so an allocation failure or a reader on a free-threaded build could encounter an unset tuple entry. An allocation failure could also clear lastrowid and crash the next execute. Build new metadata before replacing the old values and synchronize reads and writes. Keep a strong reference to each row or text factory while it is called so replacing the factory during a fetch cannot destroy an active callable.
A raw read can reinitialize a TextIOWrapper as write-only, and codec callbacks or finalizers can release an encoder, decoder, or decoded chunk while a read or write still needs it. This can crash the interpreter. Check that a decoder is still available after reading, keep codecs alive across calls, and read the chunk length before transferring ownership. Also recheck StringIO after converting the truncate size because __index__() can close the stream.
In the free-threaded build, dict() and dict.update() checked that a
list key/value pair had two items and then read them with borrowed
references without holding its lock, so another thread could empty
the list in between and the items were read from a freed or NULL
array.
The ssl module now rejects TLS certificate chains that contain any of a set of
compromised eMudhra intermediate CA keys. This is an extraordinary measure and
a last line of defense: removing trust is primarily the job of the platform root
store, and the built-in denylist only blocks connections while that update has
not yet reached the OS, a container image, or a bundled trust store in various
Python packages. Entries are added to the denylist only under a very high
threshold.
The denylist matches on the public key (the SHA-256 digest of the RFC-5280
SubjectPublicKeyInfo), so it also covers the cross-signed certificates that
reuse one of the distrusted keys.
---------
Signed-off-by: Christian Heimes <christian@python.org>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An external timer can run Python again when the profiler converts or releases its result or reports an unraisable exception. Calling clear() or disable() at that point could free a profiling context still in use. Calling Profiler.__init__() from the timer could also destroy the active callable. Keep the guard active through result handling and reject reinitialization while an external timer is running.
Literal parts of f-strings and t-strings are decoded only after the
whole string has been parsed, so a decode error took the location of
the last token. The resulting SyntaxError pointed at the closing quote,
and for multi-line strings it could be on the wrong line.
Raise the error at the literal part being decoded instead.
The deleted-`libpython` mapping test uses `LD_LIBRARY_PATH` to load a temporary copy of the library. On glibc, an interpreter's `DT_RPATH` can take precedence and load a different copy, so the test fails because the temporary copy was not mapped. Preload the temporary library explicitly so the subprocess maps the file that the test removes. Create the copy beneath the working directory and preload it through a relative path, since `LD_PRELOAD` treats spaces and colons as separators.
A bare name or number followed by a token that cannot extend an expression now produces its AST node directly. This avoids the expression precedence chain for common arguments, assignments, and subscripts.
Rules declare the hook with a fastpath flag. The Rule constructor exposes memo and fastpath attributes, and the C generator emits the hook call.
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
After a SIGKILL, the forkserver can no longer report the first child's
exit status, so proc.join() returns with exit code 255 while the child
may still be running. Wait for the event instead of checking it right
after join().
The HZ encoder can consume a tilde after writing only its first escape byte. A split ISO-2022 escape can exceed the incremental decoder’s pending buffer, and a reset can leave the previous character set selected. Reserve space for both HZ bytes before consuming the tilde, allow the full pending escape, and restore the initial ISO-2022 state on reset. Keep the native codec table and the active encoder error policy alive so replacing their Python owners cannot leave a codec using freed memory.
Goal is to make it faster to triage individual test failures while
keeping the full existing regrtest fidelity. Fairly minimal integration
to hopefully save some human eyeball time.
Setup so only the test summary process should output the summary,
subprocesses have the env var which will cause output unset.
Includes a couple of fixes to existing tests that produced false-positives.
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Deterministically get into the deadlock timeout by using mocked Raw I/O
that blocks on threading events. The test still takes quite a bit of
walltime as `_enter_buffered_busy` has a 1 second timeout on a lock
acquisition which this hits.
- Unify `_Py_ext_module_loader_info_init*` functions. The “core” one was entirely unused, and the difference between “builtin” and “extension” can be expressed in arguments.
- Consolidate getting & checking the module name from spec. (This improves error message wording for `imp.create_builtin` with empty name.)
- Allow non-ASCII names.
Core modules (`sys` and `builtins`) still don't go through the routine.
Co-authored-by: Itamar Oren <itamarost@gmail.com>
Add an @include meta to pegen: the rules of an included grammar file are
appended to the including file's rules. The C generator emits the rules
of each included file into a separate C file next to the main output.
Use it to move the invalid_* rules from Grammar/python.gram into
Grammar/invalid.gram, which generates Parser/parser_invalid.c.
Fix `ZipFile.mkdir()` so that it raises `ValueError` when another writable
member handle returned by `ZipFile.open(..., mode="w")` is still open.
Co-authored-by: Stan Ulbrych <stan@python.org>
A character data callback can disable buffering or remove the next event handler during a flush. Interning an attribute name can also change ordered_attributes while pyexpat is filling the attribute container. Using the freed buffer, cleared handler, or wrong container type can crash the interpreter. Clear the buffered length before dispatch, keep the active handler alive, recheck the buffer and handlers after callbacks, and use one attribute mode for the whole start event.
CPython copies the trampoline templates into executable memory. Keep the
ELF source in .rodata so BOLT preserves its bytes and boundaries.
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>