_CALL_LIST_APPEND stole the arg stackref via PyStackRef_AsPyObjectSteal
and passed it to _PyList_AppendTakeRef. When the list's backing array
failed to grow, _PyList_AppendTakeRef decreffed the item, but the stale
stackref remained on the value stack. The exception unwinder then closed
it a second time, causing a double-free / use-after-free.
Fix by giving _PyList_AppendTakeRef a separate reference via Py_NewRef
and closing the stackref explicitly on success. On the error path the
stackref still holds a valid reference, so the exception unwinder can
safely close it.
* Update vendored mimalloc to v2.5.2
Upgrade mimalloc from v2.1.2 to v2.5.2 as-is from upstream.
v2.1.2: https://github.com/microsoft/mimalloc/releases/tag/v2.1.2
v2.5.2: https://github.com/microsoft/mimalloc/releases/tag/v2.5.2
* Re-apply CPython-specific changes to mimalloc v2.5.2
Most of the previous downstream changes were upstreamed in mimalloc
v2.1.3 - v2.1.7 (heap tags, _mi_heap_init/_mi_tld_init, MI_PRIM_THREAD_ID,
sub-processes, heap walk optimizations, platform fixes) and are dropped.
Remaining CPython-specific changes, all marked with a "CPython" comment:
- QSBR delayed page freeing for free-threaded builds (gh-115103,
gh-145615): mi_page_t/mi_heap_t fields and _PyMem_mi_* hooks in
page.c, heap.c and segment.c.
- debug_offset: preserve the first bytes of a PyObject (ob_tid, refcount
fields) when filling freed or uninitialized memory in debug builds
(gh-115491).
- Atomic mi_block_t.next loads/stores to avoid TSAN reports (gh-129748).
- Relax the owning thread assertion in _mi_free_delayed_block for
free-threaded builds, since the GC traverses heaps of other threads.
- Call _mi_heap_delayed_free_partial() in mi_heap_visit_blocks()
(gh-112532).
- Only count reclaimed pages up to MI_MEDIUM_OBJ_SIZE_MAX as a
"right page" in mi_segment_reclaim (gh-115103).
- Rename the weak _ZSt15get_new_handlerv symbol and disable the
mi_is_in_heap_region debug warning.
- Zero-initialize _mi_page_empty instead of a positional initializer.
* Update the free-threaded build to mimalloc v2.5.2 changes
mimalloc v2.1.4 replaced the list of abandoned segments with per-arena
bitmaps and introduced sub-processes (mi_subproc_t) to keep abandoned
segments of separate interpreters apart. Use them instead of the
CPython-specific mi_abandoned_pool_t:
- Each interpreter owns a mi_subproc_t created in init_interpreter().
- tstate_mimalloc_bind() sets tld->segments.subproc and uses the
upstream _mi_heap_init() signature.
- The GC and sys.getallocatedblocks() visit abandoned segments with
_PyMem_mi_visit_abandoned_blocks(), the upstream cursor API without
the mi_option_visit_abandoned requirement, while STW.
* Update NEWS.d
* fix MSAN
* fix TSAN
* fix test_cext
* Disable THP
* Address code review
* Address code review
* Address code review
* nit
* Address code review
* Address code review
binascii.a2b_qp() and quopri now leave an invalid "=" escape in place and
rescan the following character instead of consuming it, like email.quoprimime
and other decoders (b'==41' now decodes to b'=A').
Add an opt-in strip_ws parameter to binascii.a2b_qp(), quopri.decode(),
quopri.decodestring() and email.quoprimime.decode() to strip trailing
whitespace per RFC 2045. It is false by default everywhere except
email.quoprimime.decode(), preserving every existing default.
Also document that email's get_payload(decode=True) does not strip trailing
whitespace, contrary to RFC 2045.
Register the new "strip_ws" argument name in the global objects tables
(make regen-global-objects), needed by static builds where binascii is
compiled into the core, and replace an unresolved :func: reference to the
undocumented email.quoprimime.decode with a literal.
* gh-62222: Make strip_ws parameters keyword-only
---------
Co-authored-by: Gregory P. Smith <greg@krypto.org>
The C implementation considerably boosts the performance of the key UUID operations:
------------------------------------
Operation Speedup
------------------------------------
uuid4() generation 15.01x
uuid7() generation 29.64x
UUID from string 6.76x
UUID from bytes 5.16x
str(uuid) conversion 6.66x
------------------------------------
Summary of changes:
* The UUID type is reimplemented in C in its entirety.
* The pure-Python is kept around and is used of the C implementation
isn't available for some reason.
* Both implementations are tested extensively; additional tests are
added to ensure that the C implementation of the type follows the pure
Python implementation fully.
* The Python implementation stores UUID values as int objects. The C
implementation stores them as `uint8_t[16]` array.
* The C implementation has faster hash() implementation but also caches
the computed hash value to speedup cases when UUIDs are used as
set/dict keys.
* The C implementation has a freelist to make new UUID object
instantiation as fast as possible.
* uuid4() and uuid7() are now implmented in C. The most performance
boost (10x) comes from overfetching entropy to decrease the number of
_PyOS_URandom() calls. On its own it's a safe optimization with the
edge case that Unix fork needs to be explicitly handled. We do that by
comparing the current PID to the PID of when the random buffer was
populated.
* Portions of code are coming from my implementation of faster UUID
in gel-python [1]. I did use AI during the development, but basically
had to rewrite the code it generated to be more idiomatic and
efficient.
* The benchmark can be found here [2].
* This PR makes Python UUID operations as fast as they are in NodeJS and
Bun runtimes.
[1] https://github.com/MagicStack/py-pgproto/blob/b8109fb311a59f30f9947567a13508da9a776564/uuid.pyx
[2] https://gist.github.com/1st1/f03e816f34a61e4d46c78ff98baf4818
Read insertion order from the iterator's captured values snapshot instead
of re-reading ma_values and asserting against a concurrently changing
size. Retry under the dictionary lock when a value slot has been cleared.
Make insertion-order writes atomic and publish size changes with release
stores, pairing with the iterator's size load. Keep order-byte accesses
relaxed. Add _Py_atomic_store_uint8_release() and
FT_ATOMIC_STORE_UINT8_RELEASE() for this.
gh-157361: Implement aiter() in Python instead of C
Move both forms of aiter() into the frozen _pybuiltins module and remove
the C async_callable_iterator types. The callable form now returns an
iterator whose __anext__() is a plain coroutine, so call-graph tools can
see through it into the awaited result of the callable.
Setting __name__, __qualname__, __doc__ or __module__ on a function
stopped the world in the free-threaded build since gh-154826 and
gh-154851, making functools.wraps() orders of magnitude slower with
multiple threads.
Use the per-object critical section and _PyObject_XSetRefDelayed()
instead, as gen_set_name() already does. Use acquire loads in the
readers and hold strong references across error reporting, tracing, and
eval-frame recording that may execute Python or detach the thread. The
__code__, __defaults__, __kwdefaults__ and __closure__ setters still
stop the world to clear func_version.
Document synchronization requirements for direct field access and the
lifetime of borrowed function attributes.
Starting off with WASI version, WASI SDK version, and whether cooperative multithreading is available. All values are required as WASI SDK is the officially supported compiler according to PEP 11.
Move source access and logical spans into the tokenizer source API, and keep input and encoding ownership in the reader. Export the incremental decoder helper for parser generator extensions.
The compiler merges equal constants of a module through its constant
cache. intern_constants() then ran on each code object and rebuilt a
frozenset (or, in the free-threaded build, a slice) when one of its
strings was replaced by an already interned one, so a constant shared by
several functions was copied for some of them depending on which strings
happened to be interned in the process. The class body's __qualname__
constant and co_qualname had the same problem. marshal then wrote
different bytes for the same source.
Intern the eligible strings of the final constants of each code unit
after optimization and before the code object is created. Tuples are
updated in place; a frozenset or slice is rebuilt once and stored in the
constant cache so that later units get the same object. The same code
is used in both builds.
Which strings are interned does not change, except that identifier-like
strings in slice constants are now interned in the default build too.
TestConstantsIdentity compares the identity graph and the marshal
output of code compiled in differently prepared processes, including
names tuples shared with constants.
This makes it so that in wasi builds if `-DPY_CALL_TRAMPOLINE` is passed, a call trampoline adaptor is used to prevent traps when there is a call signature mismatch between a C slot handler and the signature that the interpreter uses to call it.
This requires Clang >= 22. PEP 11 specifies that builds of Python 3.15 use WASI SDK version 33 which includes clang 23.1.0, so this could be used with Python 3.15 WASI builds but not earlier ones.
It requires a WebAssembly runtime that supports wasm-gc. Wasmtime has supported wasm-gc since version 27.0 released November 25, 2024. Some other runtimes still don't support it, but for those runtimes people can use builds with the trampoline disabled.
This also removed the Emscripten trampoline support for JS runtimes with no wasm-gc support. This removes a lot of implementation complexity and allows WASI and Emscripten to share code. The main concern is that it drops support for some very old iPhones, but every iPhone model released since 2018 is compatible with versions of Safari that support wasm-gc.
Tests were added that define handlers with various wrong numbers of arguments. The tests also run on non-webassembly platforms since they should work there as well.
Adds an `external` flag to a bit-packed byte on the
_PyInterpreterFrame struct in order to provide external frame
evaluators a way to distinguish VM-pushed frames vs externally-
pushed frames.
If Py_MIN/MAX/ABS() macros are called on an existing "_x" or "_y"
variable name, the external variable is used instead of macro local
variable. So use more unique names in the macros to avoid
the issue.
Add test_min_max_abs_macros() to _testlimitedcapi.
Add a new internal _Py_strerror() function to Python/fileutils.c. It
uses strerror_r() if available, or use strerror() otherwise.
Replace all strerror(code) calls with _Py_strerror(code).
--with-*address-sanitizer and --with-memory-sanitizer unconditionally
disabled pymalloc (even when --with-pymalloc was given explicitly).
Enable it, so that it's available with `PYTHONMALLOC=pymalloc`.
Disable it by default on the affected sanitizer builds.
Initialize all fields in the macro. Otherwise, g++ -Wall -Wextra
complains that some fields are not initialized
[-Werror=missing-field-initializers]:
error: missing initializer for member ‘PySlot::sl_flags’
error: missing initializer for member ‘PySlot::<anonymous>’
error: missing initializer for member ‘PySlot::<anonymous>’
Fix the compiler warning "extension used" when building test_cext
with clang.
* test_cext no longer overrides the CC environment variable if it's
already defined.
* test_cext now also logs __STRICT_ANSI__ macro.
* Speed up PyObject_CallMethod via _PyObject_GetMethod
PyObject_CallMethod (and _PyObject_CallMethod, PyEval_CallMethod,
_PyObject_CallMethodId and the _SizeT variant) resolved the method with
PyObject_GetAttr, which builds a temporary bound-method object on every call,
then called it.
Resolve the method with _PyObject_GetMethod instead (the same lookup the
interpreter uses for obj.name(...)) and call it directly via
_PyObject_VectorcallPrepend, skipping the bound-method allocation. Behaviour
is unchanged: same attribute semantics, same "attribute of type ... is not
callable" error, and the historical
PyObject_CallMethod(o, m, "O", tuple) -> o.m(*tuple) unpacking.
The shared helper callmethod() and _PyObject_CallMethodFormat() are no longer
needed: their only caller (traceback.c) now uses PyObject_CallFunction, so both
are removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Use _PyObject_GetMethodStackRef so method calls scale in free-threading
Resolve the method in callmethod_va() via _PyObject_GetMethodStackRef()
instead of _PyObject_GetMethod(). The StackRef variant returns the method
as a deferred reference, avoiding the per-call atomic refcount on the
shared method object that otherwise serializes threads in the
free-threaded build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* rename to callmethod
* review comments
* review comments
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Co-authored-by: Inada Naoki <songofacandy@gmail.com>
* gh-157407: Use _PyUnicode_AsUTF8NoNUL for AC 's' and 'z' converters
The code was doing the same as the helper added in GH-111957 but inline.
That resulted in significantly more `.text` for most functions. Refactor
the Arguemnt Clinic converters code to deduplicate a bit while keeping
generated code close to original.
On my Linux x64 box this reduces `.text` by ~6200 bytes in a clang
release build (no PGO or LTO). Performance is flat.
The helper was already exported for `_sqlite3`, update the comment that
it is used in AC generated code as well.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Update Include/internal/pycore_unicodeobject.h
Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
* Remove NEWS, add period
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
* update_seq
* no need for XCHGL, MOVL is enough?
* gh-155811: Retry an inconsistent GC snapshot once
---------
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
* Run the test suite with MSan in CI
* Additional fixes
* Add `_Py_MSAN_UNPOISON_STRING`
* Apply Victor's suggestions
Co-authored-by: Victor Stinner <victor.stinner@gmail.com>
* Apply Victor's suggestions
Co-authored-by: Victor Stinner <victor.stinner@gmail.com>
---------
Co-authored-by: Victor Stinner <victor.stinner@gmail.com>
Add output_length to _Py_EncodeLocale(), _Py_EncodeUTF8(),
encode_current_locale() and encode_ascii(). So unicode_encode_locale() and
wstr_to_utf8() can now use the output_length, instead of having to compute
strlen().
* Rename functions:
* _Py_DecodeUTF8Ex() => _Py_DecodeUTF8()
* _Py_EncodeUTF8Ex() => _Py_EncodeUTF8()
* _Py_EncodeLocaleEx() => _Py_EncodeLocale()
* _Py_DecodeLocaleEx() => _Py_DecodeLocale()
* Add tests on Py_DecodeLocale() and Py_EncodeLocale() in test_codecs.
Clarify also their documentation.
* _Py_EncodeLocale() and _Py_DecodeLocale() now sets all output parameters on
error. Add more tests on these output parameters.
* Add encode_current_locale_impl() to simplify encode_current_locale().
* Remove reason parameter of _Py_EncodeLocale() and _Py_DecodeLocale() to
simplify the code. Only the UTF-8 decoder used specific reasons.
* _Py_EncodeUTF8() now uses size_t instead of Py_ssize_t to iterate
on the input string.
* On error, encode_current_locale_impl() now returns ENCODE_ERROR (new
constant) instead of DECODE_ERROR.
* Mark _Py_EncodeLocaleRaw() as static (it's not used outside fileutils.c).
Py_GetVersion() now allocates memory on the heap, instead of using a
static buffer, to no longer truncate the version if it's longer than
299 bytes.
Update Py_GetCompiler() and Py_GetBuildInfo() tests: they are now
always a part of sys.version.
* gh-158140: Resolve lazy siblings through the pending-child registry
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: T. Wouters <thomas@python.org>
Replace global variables with a new _PyOS_GetOpt structure:
* _PyOS_opterr => getopt->error
* _PyOS_optind => getopt->index
* _PyOS_optarg => getopt->arg
Changes:
* Add tests to test_cmd_line.
* Rename _PyOS_ResetGetOpt() to _PyOS_GetOpt_Init(). Add argc and
argv parameters.
* Don't expose longindex in the structure, it's only used internally.
* Move _PyOS_LongOption structure from the internal C API to
getopt.c.
* Expose two possible builtin JIT gaps
* Add trace and runtime guard for builtin dict
* Check _GUARD_BUILTINS_IS_CANONICAL once per frame
* Add check and fix for globals being folded
Add assertion to _PyUnicodeWriter_Prepare() to check that length is
not negative.
Add some assertions to check that _PyUnicodeWriter_Prepare() is
called with len >= 1.