Skip to content

Fix stack overflow segfault on debug builds for Python threads#7986

Open
JamesClarke7283 wants to merge 2 commits into
RustPython:mainfrom
JamesClarke7283:fix-7941-thread-stack-overflow
Open

Fix stack overflow segfault on debug builds for Python threads#7986
JamesClarke7283 wants to merge 2 commits into
RustPython:mainfrom
JamesClarke7283:fix-7941-thread-stack-overflow

Conversation

@JamesClarke7283
Copy link
Copy Markdown
Contributor

@JamesClarke7283 JamesClarke7283 commented May 27, 2026

Summary

  • Spawned Python threads were getting Rust's std::thread::Builder default stack of 2 MB, which is too small for the call chains the Python stdlib runs on helper threads in debug builds (where Rust stack frames are substantially larger). CPython on glibc Linux relies on pthread's ~8 MB default instead — a 4× difference that explains why this hits us but not CPython.
  • Apply 8 MB in apply_thread_stack_size whenever the user hasn't explicitly set a value via threading.stack_size(N). This matches CPython's effective default while keeping the Python API contract exact: threading.stack_size() still returns 0 ("platform default"), and explicit overrides still take precedence.
  • Single-file change in crates/vm/src/stdlib/_thread.rs.

Closes #7941

Test plan

  • cargo build succeeds.
  • Original reproducer passes on a debug build: cargo run -- -m test.test_ssl ThreadedTests.test_socketserverRan 1 test in 21.59s, OK (was segfaulting on main).
  • Python API contract preserved: threading.stack_size() returns 0 by default; setting to 1 MiB then reading back returns 1048576; previous value reported correctly.
  • Basic threaded workload (5 threads doing work + join) still completes normally.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved thread stack sizing consistency and reliability. Fixed an issue where an unset or zero stack size could fall back to platform defaults, causing inconsistent behavior. Threads now apply a consistent explicit default stack size in all configurations, ensuring more predictable and reliable thread creation.

Review Change Stack

Rust's std::thread::Builder defaults to a 2 MB stack when no size is
set, which is too small for the call chains the Python stdlib runs on
helper threads in debug builds (e.g. test.test_ssl's threaded server).
CPython on glibc Linux relies on pthread's ~8 MB default instead.

Apply 8 MB as the default in apply_thread_stack_size when the user has
not explicitly called threading.stack_size(N). This matches CPython's
effective default across builds while preserving the existing API:
threading.stack_size() still returns 0 by default ("platform default"),
and explicit user values still take precedence.

Fixes RustPython#7941

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 51052005-feb1-4d12-9e27-47b74e836270

📥 Commits

Reviewing files that changed from the base of the PR and between b953363 and e4011c1.

📒 Files selected for processing (1)
  • crates/vm/src/stdlib/_thread.rs

📝 Walkthrough

Walkthrough

apply_thread_stack_size now always sets the thread builder's stack size: it uses vm.state.stacksize when non-zero, otherwise a new DEFAULT_THREAD_STACK_SIZE (8 MiB) is applied.

Changes

Thread Stack Sizing

Layer / File(s) Summary
Default thread stack size implementation
crates/vm/src/stdlib/_thread.rs
DEFAULT_THREAD_STACK_SIZE (8 MiB) constant added. apply_thread_stack_size now always calls thread_builder.stack_size(size), using configured vm.state.stacksize when non-zero or otherwise the new default.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested reviewers

  • ShaharNaveh
  • youknowone

Poem

🐰 I nudged the stack to eight meg bright,
No silent crashes in the night,
A builder set, no defaults hid,
Threads hop steady — proudly rid,
Hooray for sizes small and right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix stack overflow segfault on debug builds for Python threads' is concise, clear, and directly describes the primary change—addressing a stack overflow issue in Python thread handling.
Linked Issues check ✅ Passed The PR implements the core requirement from issue #7941: applies an explicit 8 MiB default stack size to Python threads when stack size is unset, addressing the segfault on debug builds.
Out of Scope Changes check ✅ Passed The PR modifies only crates/vm/src/stdlib/_thread.rs to set thread stack sizes, which is directly scoped to the thread stack overflow issue and does not introduce unrelated changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Satisfy docstring coverage check on the PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some python tests are crashing with segmentation fault when running on debug build

1 participant