Skip to content

fix: raise RUST_MIN_STACK repo-wide to fix e2e test stack overflows#3455

Open
wbbradley wants to merge 1 commit into
mainfrom
fix/e2e-stack-overflow-rust-min-stack
Open

fix: raise RUST_MIN_STACK repo-wide to fix e2e test stack overflows#3455
wbbradley wants to merge 1 commit into
mainfrom
fix/e2e-stack-overflow-rust-min-stack

Conversation

@wbbradley

@wbbradley wbbradley commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Problem

E2e tests (test_blob_attribute_add_and_remove, test_byte_range_read_client, test_aggregator_blob_endpoints_corner_cases, and others run via --run-ignored) abort with fatal runtime error: stack overflow when built with the default debug profile (opt-level = 0), for example a plain local cargo nextest run --run-ignored ....

The root cause is deep async call chains through the Sui SDK futures (Wallet::execute_transaction_may_fail ≈ 10 KB, WalletContext::execute_transaction_may_fail ≈ 9.7 KB, and friends). In debug builds these frames are large and un-inlined, so they compose past the default thread stack.

This is a local-only issue, not a CI failure

CI is not affected and is green on main. The test job runs with --cargo-profile test-opt (Cargo.toml:202, opt-level = 1), which shrinks those stack frames enough to stay under the default stack even though it runs the same --run-ignored all e2e tests. The real axis is debug-vs-optimized builds, not macOS-vs-Linux.

Fix

Add a workspace-root .cargo/config.toml with a Cargo [env] table setting RUST_MIN_STACK to 32 MiB. This lets developers run the e2e suite with a default debug build without manually exporting RUST_MIN_STACK per invocation. Cargo applies [env] to all processes it launches (test binaries under both cargo test and cargo nextest run, build scripts, cargo run), so it is honored uniformly. The value is non-force, so a developer who already exports RUST_MIN_STACK keeps their own value.

The libtest harness runs each test on its own spawned thread (the overflow message names the thread after the test, for example thread 'deep_stack' has overflowed its stack), and that thread honors RUST_MIN_STACK at creation time. cargo-nextest 0.9.108 propagates the Cargo [env] table into the test process.

Why this over alternatives

  • build.rs linker flags (-Wl,-stack_size / -Wl,-z,stacksize): only reliably resize the main thread stack on macOS, and tests don't run on the main thread anyway — so they wouldn't help the per-test spawned threads where the overflow actually occurs.
  • multi_thread, worker_threads = 1: changes async test semantics workspace-wide — risky and broad for no benefit.
  • Box more futures: diminishing returns; the largest frames live in the Sui SDK.
  • Per-invocation RUST_MIN_STACK export: easy to forget and undocumented; .cargo/config.toml makes it automatic and discoverable.

Notes

  • 32 MiB is a minimum reserve per spawned thread and is virtual address space only; RSS grows solely for touched pages. No measurable runtime cost.
  • Harmless in CI: CI already builds optimized and never overflowed, so this is a no-op there. It applies regardless, which is fine.
  • Does not affect deployed node binaries (executed directly, not via cargo run).

Verification

  • chk — clean (config-only change; no compiler impact).
  • cargo nextest run — 1106 tests passed, no regressions.

🤖 Generated with Claude Code

E2e tests build deep async call chains through the Sui SDK futures
(Wallet::execute_transaction_may_fail and friends are ~10 KB stack frames
each), which compose past the default thread stack and abort with
`fatal runtime error: stack overflow` when run via --run-ignored.

Set RUST_MIN_STACK to 32 MiB via a workspace-root .cargo/config.toml [env]
table. Cargo applies this to all launched processes (test binaries under
cargo test and cargo nextest run, build scripts, cargo run), so it is honored
locally and in CI uniformly with no per-invocation env var. The libtest
harness runs each test on its own spawned thread, which honors RUST_MIN_STACK
at creation time. Non-force, so a developer who already exports RUST_MIN_STACK
keeps their own value.
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.

1 participant