In a free-threaded build, if allocating the thread-local bytecode cache fails after the code-object cache has been created, the initializer destroys the first cache and returns an error without clearing its pointer. Failed construction then invokes the unwinder's deallocator, which destroys the same cache again and can crash the profiling process instead of propagating `MemoryError`.
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).
* gh-158539: Fix exception mode missing handlers in generators/coroutines
The sampling profiler's exception mode decided whether a thread was
handling an exception by reading the embedded PyThreadState.exc_state.
Generators, coroutines and async generators repoint tstate->exc_info
at their own _PyErr_StackItem while they run, so an except block
running in one of them (or in a function they call) stored the
exception in that item instead, and was never sampled.
Follow tstate->exc_info and its previous_item chain, mirroring
_PyErr_GetTopmostException(), and export the two debug offsets needed
to walk the chain from remote memory. The common case where exc_info
points at the embedded exc_state keeps the existing zero-extra-read
fast path.
* gh-158539: Handle deep exception chains without changing debug offsets
* gh-158539: Use portable static assertion messages
* gh-158539: Keep layout assertions with debug-offset validation
* gh-158539: Use the platform guard for in-process inspection tests
---------
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
* gh-152721: Fix quadratic RLE replay time in the profiling binary reader
* gh-152721: Clarify the batch-list comment
Reword per review: the list is built with append per element, not
pre-sized; note the old alloc(count - i) + trim per batch was O(count^2).
* Cap RLE batch size to bound the per-batch timestamp list
* Move MAX_RLE_BATCH_SAMPLES comment to its own line (keep under 79 cols)
* Drop the now-redundant emit_batch trim and fix the review nits
The batch list is built to its exact size, so the PyList_SetSlice trim was a no-op; call emit_sample directly. Also point the cap comment at the issue (gh-151378) and drop the stale over-long comment.
* gh-152721: Test replay batches beyond the RLE limit
---------
Co-authored-by: Pablo Galindo Salgado <Pablogsal@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>
* the kolektor
* test
* better test
* news
* =Q, move const to the base, not self.running
* gh-151292: Track binary writer finalization state
---------
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
* let me declare single limit
* use our new limit in process_frame_chain()
* add it in parse_async_frame_chain()
* parse_coro_chain()
* NEWS
* async in the message?
* test
* no race
* process_task_awaited_by
* process_task_awaited_by limit test
* NEWS
* MAX_TASK_WAITER_CHAIN_DEPTH
* TASK_WAITER_CHAIN_DEPTH in test
* TASK_WAITER_CHAIN_DEPTH 256
* prevent the drift with the comment
* better naming, better style
* MAX_TASK_WAITER_CHAIN_DEPTH comment
* task-waiter iterative bfs walk
* iterative coro-walk
* nicer news
* 1 << 14
* comment
* unused read_Py_ssize_t
* fix tombstones
* simplify
* correct msg
* better test
* news for tombstones
* left-over from when testing buggy version
* redundant new line
* gh-157660: Fix stale TLBC caches in _remote_debugging
`profiling.sampling` reporting errors or incorrect line numbers in free-threaded
builds when a thread-local bytecode array grows or gains entries after being cached.
* gh-157660: Retry transient sampling races in TLBC tests
---------
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
Accept empty native-thread stacks when sampling instead of raising an error. Distinguish interpreter-owned C frames from cleared Python frames so frame cleanup cannot produce a false <native> marker.
The pid_t, Py_off_t, HANDLE, DWORD and BOOL converters were defined in
9 files. The Py_off_t type and its converter function are now shared too.
DWORD in _winapi is used with bitwise=True to keep accepting negative
values.
The pid_t converter is now used for the pid parameters in the
_remote_debugging module, which were declared as int.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The remote debugging frame cache previously used only the last_profiled_frame address as its cache anchor. If a frame returned and a later frame reused the same _PyInterpreterFrame address, the profiler could accept a stale cache entry and splice parent frames from a different call chain into the current stack.
This adds a last_profiled_frame_seq counter next to last_profiled_frame, increments it when the anchor advances, stores it in frame cache entries, and validates cache hits against both the frame address and the sequence. Cache miss walks now copy stack chunks before storing new cache entries so stored continuations come from a stable snapshot. The new regression test exercises alternating call chains and checks that cached stacks never contain frames from both branches.
Use exact remote reads for interpreter state, thread state, and
interpreter frame structs instead of pulling full remote pages into the
profiler page cache. This matches the core change from
python/cpython#149585.
The profiler clears the page cache between samples, so live entries are
always packed at the front. Track the live count and only clear/search
that prefix instead of scanning all 1024 slots on the hot path.
Use the frame cache to predict the next thread state and top frame
address, then batch interpreter/thread/frame reads with process_vm_readv
when profiling a Linux target. Reuse prefetched frame buffers in the
frame walker when the prediction is valid.
Cache the last FrameInfo tuple per code object/instruction offset, reuse
cached thread id objects, and append cached parent frames directly on
full frame-cache hits. This cuts Python allocation churn in the
steady-state profiler path.
Compute ``final_depth`` in ``decode_stack_pop_push()`` and
``decode_stack_suffix()`` using ``uint64_t`` before validating it.
On 32-bit builds, using ``size_t`` arithmetic for ``keep + push`` can wrap
for large input values, causing the later bounds check to validate the wrong
final depth. Using a widened type keeps the validation aligned with the
actual result.
Treat the debug offset tables read from a target process as untrusted input
and validate them before the unwinder uses any reported sizes or offsets.
Add a shared validator in debug_offsets_validation.h and run it once when
_Py_DebugOffsets is loaded and once when AsyncioDebug is loaded. The checks
cover section sizes used for fixed local buffers and every offset that is
later dereferenced against a local buffer or local object view. This keeps
the bounds checks out of the sampling hot path while rejecting malformed
tables up front.