* fix(wallet): prevent exit-hang on Windows from detached Tor/I2P threads
Embedded Tor and embedded I2P each ran on a background std::thread that was
.detach()'d at startup. The teardown paths (CTorEmbedded::Stop,
CI2PEmbedded::Stop) only flipped a running-flag — they did not signal the
thread to exit, and on Windows there is no signal mechanism in tor_api 0.4.x.
Result on Windows: when the user closed the wallet, Shutdown() completed its
bookkeeping and main() returned 0, but the process could not exit because the
detached thread was still in the Tor event loop / i2pd io_context. End Task
(TerminateProcess) was the only escape; the GUI appeared completely stuck.
Fixes:
- tor_embedded.h/.cpp: keep the Tor thread handle; Stop() now raise(SIGTERM)
on Linux, then joins the thread with a 5s timeout, then TerminateThread
(Win) / pthread_cancel + pthread_join (Linux) as a last resort.
- i2p_embedded.h/.cpp: same pattern — capture the bootstrap thread and join
it in Stop() with a 5s timeout fallback.
- init.cpp Shutdown(): spawn a 30s watchdog thread that calls ExitProcess(1)
if the graceful teardown takes too long. Belt-and-suspenders against any
future deadlock in the exit path.
- trianglesgui.cpp closeEvent(): second close attempt while the first
exit is still running immediately calls ExitProcess(2) / _exit(2).
User escape hatch when the graceful exit hangs.
All non-consensus (threading/process lifecycle only). Build via CI; not local.
Notes: notes/wallet-close-hang-fix-2026-07-07.md
* fix(i2p): drop leftover .detach() that broke build (lambda now joinable)
* fix(i2p): clean up after .detach() removal (trailing comment, blank line)
* fix(tor): MINGW std::thread is pthread-based, use pthread_cancel/join on MINGW
MINGW std::thread::native_handle_type is unsigned long long (pthread_t
emulation), not HANDLE. Mixing pthread handles with Win32
WaitForSingleObject/TerminateThread fails to compile on MINGW with
'invalid conversion' errors.
Use the same pthread_cancel/pthread_join path on Linux and MINGW; keep
TerminateThread only for MSVC builds where native_handle() returns a
real Win32 HANDLE.
---------
Co-authored-by: krystie <krystie>
Replace undefined signed shifts in SPHlib SIMD FFT arithmetic with bounded multiplications, handle empty vectors in base64/base32/base58/hash/script paths, and skip the DoS_checkSig microbenchmark threshold under sanitizer instrumentation.
Sanitizer ctest is now green locally, so make the GitHub sanitizer job blocking again.
Documents:
- V5 soft-cap test coverage shipped on audit/kernel-coverage (ab0f4b4)
- PR #14 CI status: test-linux-unit PASS, sanitizer FAIL pre-existing
(simd.c:265 UBSan, separate workstream)
- Outstanding work prioritized for future sessions
- PR #14 is ready to merge
Documents:
- Hermes's 2026-07-04 handoff letter had a stale 'blocked on W2' framing;
W2/H4/W1 were already committed as 6cadf7f on 2026-07-02.
- This session's DoS_checkSig timing fix (commit b79e2b8): replaced the
nonsensical nManyValidate < nOneValidate comparison with a stable
per-verify bound (min of 3 trials after warmup, threshold 600ms
calibrated to ~1.6x observed p100 on DNS2).
- PR #14 CI status: 9 jobs in progress as of session end.