From a4957f6d207f8a849a2784de47677aa8bbc4cb55 Mon Sep 17 00:00:00 2001 From: Sion Smith Date: Sun, 6 Sep 2026 06:56:52 +0100 Subject: [PATCH] Reserve an 8 MiB main-thread stack on Windows Windows gives the main thread 1 MiB; Linux and macOS give it 8 MiB. Building clap's command tree for this many subcommands needs just under 1 MiB in an unoptimized build (measured with `ulimit -s` on 2026-09-06: main fails below 1024 KiB on macOS too), so adding a single flag to `message` (#90, #91) made every debug and test invocation on Windows, `--help` included, die with `thread 'main' has overflowed its stack`, and `cargo test --all-targets` failed on windows-latest only. A build script now passes `/STACK:8388608` to the MSVC linker (and `--stack` to the GNU one). This is the approach rustup takes for the same clap behaviour (clap-rs/clap#5134), and unlike a `.cargo/config` rustflags entry it survives CI setting `RUSTFLAGS`. The reservation is address space, not committed memory. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01WG7vFLjFZHqAUMRS1zkWRE --- CHANGELOG.md | 4 ++++ build.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 build.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e5fe88..3dd641e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Fixed + +- Windows builds reserve an 8 MiB main-thread stack, matching Linux and macOS. Windows gives the main thread 1 MiB by default, and building clap's command tree for this many subcommands needs almost all of it in an unoptimized build, so any addition to the `message` command made every debug and test invocation of `teams` on Windows — `--help` included — fail with `thread 'main' has overflowed its stack`, and `cargo test` failed on `windows-latest` while passing on Linux and macOS. A build script now passes `/STACK:8388608` to the MSVC linker (`--stack` on the GNU toolchain). The reservation is address space rather than committed memory, so an idle process costs nothing extra. + ## v0.6.0 - 2026-08-30 ### Added diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..3fa1f50 --- /dev/null +++ b/build.rs @@ -0,0 +1,29 @@ +//! Windows reserves 1 MiB of stack for the main thread; Linux and macOS give +//! it 8 MiB. Building clap's command tree for this many subcommands uses +//! almost all of that 1 MiB in an unoptimized build (measured at just under +//! it on 2026-09-06), so on Windows every debug or test invocation of `teams` +//! — `--help` included — overflowed the stack as soon as one more flag was +//! added to `message`, and `cargo test` failed there while passing elsewhere. +//! +//! Reserving the same 8 MiB the Unix targets get removes the cliff. It is +//! address space, not committed memory, so an idle process costs nothing +//! extra. rustup does the same for the same reason (clap's debug-mode stack +//! use, clap-rs/clap#5134). A build script survives CI overriding `RUSTFLAGS`, which a +//! `.cargo/config.toml` `rustflags` entry would not. + +use std::env; + +const MAIN_THREAD_STACK_BYTES: u32 = 8 * 1024 * 1024; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") { + return; + } + match env::var("CARGO_CFG_TARGET_ENV").as_deref() { + Ok("msvc") => println!("cargo:rustc-link-arg=/STACK:{MAIN_THREAD_STACK_BYTES}"), + Ok("gnu") => println!("cargo:rustc-link-arg=-Wl,--stack,{MAIN_THREAD_STACK_BYTES}"), + _ => {} + } +}