Describe the bug
The Buzz desktop app on Windows x64 crashes with 0xc00000fd (STATUS_STACK_BUFFER_OVERRUN) about 0.4 s after the websocket connects, while the initial channel history is being loaded. The process dies on the main thread: the relay sees the connection and NIP-42 auth succeed, then the client is simply gone. Reproducible — two separate crash dumps show the identical fault.
Steps to reproduce
Install Buzz desktop 0.5.20 on Windows x64.
Connect to a relay with non-trivial channel history (ours: a burst of ~50 EOSE/EVENT history frames on connect).
~0.4 s after connect, during history load, the app crashes.
Windows Event Log (Application, ID 1000): Exception code: 0xc00000fd, faulting module buzz-desktop.exe, fault offset 0x0655b2a6.
Observed on a locally rebuilt desktop-v0.5.20 (mingw cross-build, TLS native-roots fix, 2 MiB main-thread reserve). The stock release ships with a 1 MiB main-thread reserve, so it should hit this at least as easily (the stock binary itself was not tested — its TLS stack can't complete the handshake on our private-CA relay, see #5197).
Expected behavior
History loads and the app stays open. Same relay, same history, 0.5.20 Linux .deb: no crash.
Version and platform
Buzz version: desktop-v0.5.20 (tag desktop-v0.5.20)
OS: Windows 11 x64 (build 10.0.26200), AMD64 (family 6, model 126), 8 CPUs
Control: 0.5.20 Linux .deb on the same relay — no crash (glibc main-thread default is 8 MiB)
Forensics (minidumps + the release binary)
minidump-stackwalk on both dumps (buzz-desktop.exe.33308.dmp, buzz-desktop.exe.22228.dmp):
Crash reason: EXCEPTION_STACK_OVERFLOW
Crash address: 0x00007ff7fb25b2a6
Crashing instruction: test qword [rcx], rcx
Crash address = RVA 0x655b2a6, inside ___chkstk_ms — the compiler's stack-probe helper. The fault is the probe's page-touch loop: the allocation of a large stack frame walked past the guard page.
The faulting frame is a static 522.9 KiB frame. The call site at RVA 0xa6cd85 executes mov $0x82bb8, %eax; call ___chkstk_ms (0x82bb8 = 535,480 bytes); its return address (0xa6cd8e) is exactly frame 1 in both dumps, so this is the function allocating the frame at crash time.
Per the build's COFF symbol table, the enclosing function is core::ptr::drop_in_placereqwest::async_impl::response::Response::do_bytes::{closure} (a ~218 KiB monomorphized drop; it contains no self-recursive calls — this is one giant frame, not deep recursion).
Independent cross-check from the register state in both dumps: at fault rax = 0x5ebb8 and the probe had touched 37 pages, so the initial frame was 0x5ebb8 + 36×0x1000 = 0x82bb8 — the same 522.9 KiB, from two separate dumps.
At the moment that frame was allocated, only ~148 KiB of stack remained below it: the main-thread call chain was already ~1.85 MiB deep.
PE header of the stock release buzz-desktop.exe (Buzz_0.5.20_x64-setup_alpha-unsigned.exe): SizeOfStackReserve = 0x100000 (1 MiB — the Windows default). The same code on Linux gets glibc's 8 MiB main-thread stack.
This is not a one-off in the codebase: a scan of the same binary found ~10 other functions with single-frame reserves of 1024–1094 KiB. With a 1 MiB main-thread reserve, any of them can overflow on a moderately deep call chain.
Why it never happens on Linux
Same code, same history: 8 MiB main-thread reserve, so the ~2.4 MiB of depth fits. Windows ships 1 MiB.
Proof the stack size is the trigger
Rebuilt 0.5.20 with the PE SizeOfStackReserve changed from 2 MiB to 8 MiB (matching the Linux default) — no code changes. The crash no longer reproduces: the app connects, authenticates, and renders the full history. Raising the reserve is therefore a verified workaround; shrinking the frame is the real fix.
Suggested directions
Real fix: find out why that monomorphized drop_in_place needs a ~511 KiB stack frame — likely a large inline buffer inside the dropped future/closure state that belongs on the heap — and shrink it. A drop requiring half a megabyte of stack is a strong smell, and it makes every call into it fragile.
Immediate mitigation: raise the Windows desktop build's main-thread stack reserve to 8 MiB to match Linux (linker flag for the desktop target — upstream CI builds with MSVC: /STACK:8388608; GNU/mingw equivalent: -Wl,--stack,8388608). Given the number of ~1 MiB single-frame allocations in the binary, 1 MiB is structurally insufficient for this codebase on Windows.
Happy to share the two minidumps and the relay-side logs (NIP-42 auth success immediately before the client died), and to test any candidate fix or a release candidate.
Describe the bug
The Buzz desktop app on Windows x64 crashes with 0xc00000fd (STATUS_STACK_BUFFER_OVERRUN) about 0.4 s after the websocket connects, while the initial channel history is being loaded. The process dies on the main thread: the relay sees the connection and NIP-42 auth succeed, then the client is simply gone. Reproducible — two separate crash dumps show the identical fault.
Steps to reproduce
Install Buzz desktop 0.5.20 on Windows x64.
Connect to a relay with non-trivial channel history (ours: a burst of ~50 EOSE/EVENT history frames on connect).
~0.4 s after connect, during history load, the app crashes.
Windows Event Log (Application, ID 1000): Exception code: 0xc00000fd, faulting module buzz-desktop.exe, fault offset 0x0655b2a6.
Observed on a locally rebuilt desktop-v0.5.20 (mingw cross-build, TLS native-roots fix, 2 MiB main-thread reserve). The stock release ships with a 1 MiB main-thread reserve, so it should hit this at least as easily (the stock binary itself was not tested — its TLS stack can't complete the handshake on our private-CA relay, see #5197).
Expected behavior
History loads and the app stays open. Same relay, same history, 0.5.20 Linux .deb: no crash.
Version and platform
Buzz version: desktop-v0.5.20 (tag desktop-v0.5.20)
OS: Windows 11 x64 (build 10.0.26200), AMD64 (family 6, model 126), 8 CPUs
Control: 0.5.20 Linux .deb on the same relay — no crash (glibc main-thread default is 8 MiB)
Forensics (minidumps + the release binary)
minidump-stackwalk on both dumps (buzz-desktop.exe.33308.dmp, buzz-desktop.exe.22228.dmp):
Crash reason: EXCEPTION_STACK_OVERFLOW
Crash address: 0x00007ff7fb25b2a6
Crashing instruction:
test qword [rcx], rcxCrash address = RVA 0x655b2a6, inside ___chkstk_ms — the compiler's stack-probe helper. The fault is the probe's page-touch loop: the allocation of a large stack frame walked past the guard page.
The faulting frame is a static 522.9 KiB frame. The call site at RVA 0xa6cd85 executes mov $0x82bb8, %eax; call ___chkstk_ms (0x82bb8 = 535,480 bytes); its return address (0xa6cd8e) is exactly frame 1 in both dumps, so this is the function allocating the frame at crash time.
Per the build's COFF symbol table, the enclosing function is core::ptr::drop_in_placereqwest::async_impl::response::Response::do_bytes::{closure} (a ~218 KiB monomorphized drop; it contains no self-recursive calls — this is one giant frame, not deep recursion).
Independent cross-check from the register state in both dumps: at fault rax = 0x5ebb8 and the probe had touched 37 pages, so the initial frame was 0x5ebb8 + 36×0x1000 = 0x82bb8 — the same 522.9 KiB, from two separate dumps.
At the moment that frame was allocated, only ~148 KiB of stack remained below it: the main-thread call chain was already ~1.85 MiB deep.
PE header of the stock release buzz-desktop.exe (Buzz_0.5.20_x64-setup_alpha-unsigned.exe): SizeOfStackReserve = 0x100000 (1 MiB — the Windows default). The same code on Linux gets glibc's 8 MiB main-thread stack.
This is not a one-off in the codebase: a scan of the same binary found ~10 other functions with single-frame reserves of 1024–1094 KiB. With a 1 MiB main-thread reserve, any of them can overflow on a moderately deep call chain.
Why it never happens on Linux
Same code, same history: 8 MiB main-thread reserve, so the ~2.4 MiB of depth fits. Windows ships 1 MiB.
Proof the stack size is the trigger
Rebuilt 0.5.20 with the PE SizeOfStackReserve changed from 2 MiB to 8 MiB (matching the Linux default) — no code changes. The crash no longer reproduces: the app connects, authenticates, and renders the full history. Raising the reserve is therefore a verified workaround; shrinking the frame is the real fix.
Suggested directions
Real fix: find out why that monomorphized drop_in_place needs a ~511 KiB stack frame — likely a large inline buffer inside the dropped future/closure state that belongs on the heap — and shrink it. A drop requiring half a megabyte of stack is a strong smell, and it makes every call into it fragile.
Immediate mitigation: raise the Windows desktop build's main-thread stack reserve to 8 MiB to match Linux (linker flag for the desktop target — upstream CI builds with MSVC: /STACK:8388608; GNU/mingw equivalent: -Wl,--stack,8388608). Given the number of ~1 MiB single-frame allocations in the binary, 1 MiB is structurally insufficient for this codebase on Windows.
Happy to share the two minidumps and the relay-side logs (NIP-42 auth success immediately before the client died), and to test any candidate fix or a release candidate.