Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e71a5fd
Correct what the non-unix frame stack is for
youknowone Aug 17, 2026
e981e03
Seek by the whole file position on Windows
youknowone Aug 17, 2026
9b40373
memoryview: tell a value of the wrong kind from one that does not fit
youknowone Aug 17, 2026
562dd86
Raise MemoryError for allocations sized by Python input
youknowone Aug 17, 2026
6b9b80d
Collect with the count in the object header
youknowone Aug 18, 2026
4573909
Take an explicit thread stack size as a floor in debug builds
youknowone Aug 18, 2026
b077f20
Check the native stack on every frame entry
youknowone Aug 18, 2026
45ce8f4
Take an iterable's length hint when a list is filled from it
youknowone Aug 18, 2026
c7e2658
Drop map.__length_hint__
youknowone Aug 18, 2026
94dc4db
Ask for a length hint where each caller asks for it
youknowone Aug 18, 2026
5a9c726
Settle product's pool count before it reads its arguments
youknowone Aug 18, 2026
4df44e8
Let the bool format answer with the error its value raised
youknowone Aug 18, 2026
aff3fca
Release a cell's old value after the lock
youknowone Aug 18, 2026
8f8382c
Have a set iterator hold the set it iterates
youknowone Aug 18, 2026
1c7899d
Release an exhausted iterator's container after the lock
youknowone Aug 18, 2026
800c2d8
Unskip test_free_after_iterating
youknowone Aug 18, 2026
da37fb8
Stop listing test_set as an environment polluter
youknowone Aug 18, 2026
c0faf2d
Drop winsound imports left unused
youknowone Aug 18, 2026
b2ad9b1
Ask nothing where the caller takes no room
youknowone Aug 18, 2026
3613b89
Stop asking an iterator how long it is to walk it
youknowone Aug 19, 2026
9f3580b
Name the matrix jobs rather than let the matrix name them
youknowone Aug 19, 2026
e07987d
Keep a sequence iterator active when an element raises
youknowone Aug 19, 2026
357ed5e
Name the caller in the bytes conversion TypeError
youknowone Aug 19, 2026
468f9dd
Take a strong count too large to hold as reachable
youknowone Aug 19, 2026
09dca1e
Raise AssertionError where a snippet asserts False
youknowone Aug 19, 2026
0f38af2
Keep raising for a collection that moved under its iterator
youknowone Aug 19, 2026
7392a20
Give apt-get update a deadline to fail on
youknowone Aug 19, 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
Check the native stack on every frame entry
The C-stack guard ran on one frame entry in eight. That asks the margin to
cover eight frames rather than one, and it does not: an unoptimized frame
entered through native code takes 88,672 bytes against a debug margin of
262,144. A recursion whose steps re-enter that way -- `__add__` calling
itself, a sort key that sorts -- ran off the end of the stack instead of
raising RecursionError. On a debug build `class Add: __add__ = lambda s, o:
s + o; Add() + 1` segfaulted on the main thread; it now raises, as it does
under CPython and in release builds.

enter_iframe checked and then called enter_iframe_unchecked, which checked
again; it now leaves the check to the one call.

Measured on a call-dominated benchmark, five interleaved pairs: instructions
retired go up 0.17%, about four per call, which is the stack pointer read
and the compare.

Assisted-by: Claude
  • Loading branch information
youknowone committed Aug 18, 2026
commit b077f203115aa24acfac63c9302d38dcf21f08d5
22 changes: 8 additions & 14 deletions crates/vm/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2161,13 +2161,12 @@ impl VirtualMachine {
) -> PyResult<R> {
self.check_recursive_call("")?;

// Check the native C stack periodically. The sampling interval
// (every 8th call) balances overhead against the risk of missing
// an overflow between checks, especially when light and heavy
// frames alternate (each recursion step uses different native
// stack amounts).
let depth = self.recursion_depth.get();
if depth & 7 == 0 && self.check_c_stack_overflow() {
// Every entry, not every eighth. The margin only has to cover what a
// single frame takes if the check runs each time; sampling asks it to
// cover eight, and a recursion whose steps re-enter through native
// code -- an `__add__` chain, a sort key that sorts -- takes more than
// the margin in that many.
if self.check_c_stack_overflow() {
return Err(self.new_recursion_error(String::new()));
}

Expand Down Expand Up @@ -2261,11 +2260,7 @@ impl VirtualMachine {
) -> PyResult<IframeEntryState> {
self.check_recursive_call("")?;

let depth = self.recursion_depth.get();
if depth & 7 == 0 && self.check_c_stack_overflow() {
return Err(self.new_recursion_error(String::new()));
}

// The C stack is checked by `enter_iframe_unchecked` below.
self.enter_iframe_unchecked(iframe)
}

Expand All @@ -2278,8 +2273,7 @@ impl VirtualMachine {
&self,
iframe: &mut crate::frame::InterpreterFrame,
) -> PyResult<IframeEntryState> {
let depth = self.recursion_depth.get();
if depth & 7 == 0 && self.check_c_stack_overflow() {
if self.check_c_stack_overflow() {
return Err(self.new_recursion_error(String::new()));
}

Expand Down