You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
production: a generated rust-std package can need more rustc stack than a default Windows thread gives (found by #160) #164
Found on the first CI run of #160 (the axiom-output parser pilot, BS-01).
What happened
On the x86_64-pc-windows-msvc host leg, conformance_bs_01 failed to build the generated packages of its two roots:
thread 'optimize module run_boot_parse_audit_output_std.…-cgu.0' has overflowed its stack
error: could not compile `run_boot_parse_audit_output_std` (bin "run_boot_parse_audit_output_std")
The same for run_boot_is_closed_lean_name_std. Linux and macOS built the same bytes. The contributor reproduced it on Linux by giving rustc a 1 MiB thread (RUST_MIN_STACK): both generated library crates (boot_is_closed_lean_name_std, boot_parse_audit_output_std) are killed by SIGSEGV at 1 MiB and pass at 2 MiB. Candidates for the deepest nesting in the emitted Rust: a 20-term append chain (decimal) and nested conditionals (whiteLength).
Left open here: a consumer who builds a certified package on a host whose default rustc thread stack is 1 MiB (Windows) gets the overflow. Every certified package so far builds with the default; this is the first that does not.
To decide
Whether the Rust backend should bound the nesting depth of what it emits (flatten a let-chain or an append chain into sequential statements, which the calculus already allows), or whether the package's manifest should say what stack its build needs. The answer belongs to #91 (the Rust AST and its printer) and the RustSemantics model must keep covering whatever shape is emitted. A measurement first: the maximum expression depth of every committed package under tests/production-export/ against the smallest rustc stack that builds it.
Not a blocker for #160; no milestone until the measurement is done.
Measurement of expression/delimiter nesting depth and minimum rustc 1.85.0 thread stack across all committed packages under tests/production-export/ (68 packages on main + lex and audit_tokens on #171):
1. Maximum expression / delimiter nesting depth and minimum RUST_MIN_STACK (tests/production-export/**/src/lib.rs)
Separating the runtime preamble (rust-core lines 1–81, max delimiter depth 4; rust-std lines 1–293, max delimiter depth 11 at List::cons) from the generated root functions (Fn*, f*, run), and binary-searching RUST_MIN_STACK in 16 KiB steps for rustc --crate-type lib --edition 2021 (both dev and -C opt-level=2 on x86_64-unknown-linux-gnu):
Empty baseline crate (pub fn empty() {} or #![no_std])
1
1
1
18
1,168 KiB / 1,168 KiB
baseline rustc 1.85.0'rustc' thread frame
All 70 packages build at the exact same 1,168 KiB RUST_MIN_STACK threshold as a 1-line pub fn empty() {} crate.
2. Why RUST_MIN_STACK=1 MiB segfaulted on Linux and why Windows failed in #160
rustc uses two distinct kinds of worker threads with different default stack sizes when RUST_MIN_STACK is unset:
The 'rustc' frontend/typecheck/MIR thread (rustc_interface::util::run_in_thread_with_globals): spawned with an explicit .stack_size(8 * 1024 * 1024) (8 MiB on Linux, macOS, and Windows) unlessRUST_MIN_STACK is set in the environment, in which case RUST_MIN_STACK overrides the 8 MiB default.
As the table above shows, rustc 1.85.0's 'rustc' thread requires 1,168 KiB even on an empty 1-line pub fn empty() {} crate, and 1,168 KiB across every one of the 70 packages under tests/production-export/.
Setting RUST_MIN_STACK=1048576 (1 MiB) on Linux reproduced a SIGSEGV on boot_is_closed_lean_name_std and boot_parse_audit_output_std only because RUST_MIN_STACK=1048576 overrides rustc's 8 MiB default for the 'rustc' frontend thread down to 1,024 KiB — below the 1,168 KiB baseline that rustc 1.85.0 needs for an empty crate.
The 'optimize module …' LLVM codegen threads (rustc_codegen_ssa::back::write::start_executing_work): spawned via std::thread::Builder::new()without.stack_size(…), so when RUST_MIN_STACK is unset they inherit the platform default (2 MiB on Linux/macOS, 1 MiB on Windows).
Measured separately via a pthread_attr_setstacksize preload probe that overrides only the unconfigured 2 MiB codegen threads while keeping 'rustc' at its normal 8 MiB, the 'optimize module' thread builds every committed library package (parse_audit_output, is_closed_lean_name, lex, audit_tokens, graphs, etc.) at 64 KiB (dev) and 128 KiB (-O2 / -O3) — 1/8th of Windows's 1 MiB default thread stack.
Therefore, every committed rust-std and rust-core library package under tests/production-export/ builds on Windows with default rustc settings (no RUST_MIN_STACK needed by consumers).
The Windows crash in feat(bootstrap): the axiom-output parser as language-1.2 source (BS-01) #160 (thread 'optimize module run_boot_parse_audit_output_std.…-cgu.0' has overflowed its stack, could not compile run_boot_parse_audit_output_std (bin)) occurred in the conformance test harness binariesrun_boot_parse_audit_output_std and run_boot_is_closed_lean_name_std (after the library crates boot_* had already compiled), where rust_harness::render_calls emits all 12,487 audit calls (or 40,127 name calls) as one inline array literal for (a0, a1) in [ … ] inside fn harness_group0().
Activity
afflom commentedon Oct 18, 2026
Measurement of expression/delimiter nesting depth and minimum
rustc 1.85.0thread stack across all committed packages undertests/production-export/(68 packages onmain+lexandaudit_tokenson #171):1. Maximum expression / delimiter nesting depth and minimum
RUST_MIN_STACK(tests/production-export/**/src/lib.rs)Separating the runtime preamble (
rust-corelines 1–81, max delimiter depth4;rust-stdlines 1–293, max delimiter depth11atList::cons) from the generated root functions (Fn*,f*,run), and binary-searchingRUST_MIN_STACKin 16 KiB steps forrustc --crate-type lib --edition 2021(both dev and-C opt-level=2onx86_64-unknown-linux-gnu):tests/production-export/…)RUST_MIN_STACK(dev /-O2, 16 KiB steps)bootstrap/packages/rust-std/audit_tokens(#171)let/matchblocks inf0bootstrap/packages/rust-std/parse_audit_outputappend_byteschain indecimal(lib.rs:588)bootstrap/packages/rust-std/lex(#171)stdlib/packages/rust-std/linesmatch/letblocks inf4(lib.rs:441)production-coverage/packages/rust-std/sequenceslet/ tuple destructuring (lib.rs:333)stdlib/packages/rust-std/split_onmatch/letblocks (lib.rs:434)production-coverage/packages/rust-std/textletblocks (lib.rs:328)bootstrap/packages/rust-std/is_closed_lean_nameif/elsechain (f5)rust-stdpackagesList::cons) dominatesrust-corepackages (#![no_std])let/matchblockspub fn empty() {}or#![no_std])rustc 1.85.0'rustc'thread frameAll 70 packages build at the exact same 1,168 KiB
RUST_MIN_STACKthreshold as a 1-linepub fn empty() {}crate.2. Why
RUST_MIN_STACK=1 MiBsegfaulted on Linux and why Windows failed in #160rustcuses two distinct kinds of worker threads with different default stack sizes whenRUST_MIN_STACKis unset:'rustc'frontend/typecheck/MIR thread (rustc_interface::util::run_in_thread_with_globals): spawned with an explicit.stack_size(8 * 1024 * 1024)(8 MiB on Linux, macOS, and Windows) unlessRUST_MIN_STACKis set in the environment, in which caseRUST_MIN_STACKoverrides the 8 MiB default.rustc 1.85.0's'rustc'thread requires 1,168 KiB even on an empty 1-linepub fn empty() {}crate, and 1,168 KiB across every one of the 70 packages undertests/production-export/.RUST_MIN_STACK=1048576(1 MiB) on Linux reproduced a SIGSEGV onboot_is_closed_lean_name_stdandboot_parse_audit_output_stdonly becauseRUST_MIN_STACK=1048576overridesrustc's 8 MiB default for the'rustc'frontend thread down to 1,024 KiB — below the 1,168 KiB baseline thatrustc 1.85.0needs for an empty crate.'optimize module …'LLVM codegen threads (rustc_codegen_ssa::back::write::start_executing_work): spawned viastd::thread::Builder::new()without.stack_size(…), so whenRUST_MIN_STACKis unset they inherit the platform default (2 MiB on Linux/macOS, 1 MiB on Windows).pthread_attr_setstacksizepreload probe that overrides only the unconfigured 2 MiB codegen threads while keeping'rustc'at its normal 8 MiB, the'optimize module'thread builds every committed library package (parse_audit_output,is_closed_lean_name,lex,audit_tokens,graphs, etc.) at 64 KiB (dev) and 128 KiB (-O2/-O3) — 1/8th of Windows's 1 MiB default thread stack.rust-stdandrust-corelibrary package undertests/production-export/builds on Windows with defaultrustcsettings (noRUST_MIN_STACKneeded by consumers).thread 'optimize module run_boot_parse_audit_output_std.…-cgu.0' has overflowed its stack,could not compile run_boot_parse_audit_output_std (bin)) occurred in the conformance test harness binariesrun_boot_parse_audit_output_stdandrun_boot_is_closed_lean_name_std(after the library cratesboot_*had already compiled), whererust_harness::render_callsemits all12,487audit calls (or40,127name calls) as one inline array literalfor (a0, a1) in [ … ]insidefn harness_group0().