From 5e493484f14e2740c3c1ace69e2100f40755e64e Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 21 May 2026 20:12:09 -0400 Subject: [PATCH] Run the Rust CLI on a large-stack worker thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clap derive-generated argument parser is deeply recursive; in debug builds (no inlining) parsing the Command enum exhausted the default 8 MiB main-thread stack once the alarm subcommands grew it, crashing mxgw.exe with STATUS_STACK_OVERFLOW at startup — which failed the Rust leg of the client e2e matrix. Move parse + dispatch onto a dedicated 32 MiB worker thread so the CLI is robust regardless of build profile. Co-Authored-By: Claude Opus 4.7 (1M context) --- clients/rust/crates/mxgw-cli/src/main.rs | 31 +++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/clients/rust/crates/mxgw-cli/src/main.rs b/clients/rust/crates/mxgw-cli/src/main.rs index f510851..957815e 100644 --- a/clients/rust/crates/mxgw-cli/src/main.rs +++ b/clients/rust/crates/mxgw-cli/src/main.rs @@ -465,13 +465,32 @@ enum CliValueType { String, } -#[tokio::main] -async fn main() -> ExitCode { +/// Entry point. The real work runs on a dedicated thread with a large stack: +/// clap's derive-generated argument parser is deeply recursive, and in debug +/// builds (no inlining) parsing the `Command` enum can exhaust the default +/// 8 MiB main-thread stack as the enum grows. A 32 MiB worker stack keeps the +/// CLI robust regardless of build profile or future subcommand growth. +fn main() -> ExitCode { + let worker = std::thread::Builder::new() + .name("mxgw-cli".to_owned()) + .stack_size(32 * 1024 * 1024) + .spawn(run) + .expect("failed to spawn the CLI worker thread"); + worker.join().expect("the CLI worker thread panicked") +} + +fn run() -> ExitCode { let cli = Cli::parse(); - let result = match cli.command { - Command::Batch => run_batch().await, - command => dispatch(command).await, - }; + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("failed to build the Tokio runtime"); + let result = runtime.block_on(async { + match cli.command { + Command::Batch => run_batch().await, + command => dispatch(command).await, + } + }); match result { Ok(()) => ExitCode::SUCCESS, Err(error) => {