Skip to content

WebSocket listener startup is not exception-safe after global state initialization

Summary

StartSockets initializes global WebSocket termination and SSL state before allocating and starting the listener CWinThread. Allocation or thread-start failure after those globals are initialized can skip cleanup and leave the subsystem half-started.

This is an Beta 0.7.3 blocker because WebSocket accepted-client tracking was hardened, but listener startup still has a low-probability memory-pressure path that can poison later start/stop behavior.

Evidence

  • srchybrid/WebSocket.cpp:849 enters WebSocket listener startup.
  • srchybrid/WebSocket.cpp:849 through srchybrid/WebSocket.cpp:858 initialize termination/SSL state before listener thread allocation and start.
  • srchybrid/WebSocket.cpp:856 allocates the listener CWinThread.
  • The listener allocation/start path is not wrapped in cleanup that unwinds SSL and termination-handle state on allocation failure.

Execution Plan

  1. Revalidate the current StartSockets startup sequence and every global state mutation before listener thread creation.
  2. Introduce narrow local RAII or structured cleanup for the termination event, SSL state, listener object, and any startup flags mutated before the listener is fully running.
  3. Wrap listener CWinThread allocation and CreateThread startup so every failure path unwinds initialized state exactly once.
  4. Preserve successful HTTP and HTTPS listener startup behavior.
  5. Preserve the existing failed-shutdown restart guard semantics from prior Beta 0.7.3 WebSocket fixes.
  6. Add an allocation/start-failure seam if practical; otherwise add code-review evidence and manual failure-path reasoning to the item validation.
  7. Validate Web UI disabled, HTTP enabled, HTTPS enabled, stop/start cycle, and Debug/Release x64 app builds through supported workspace entrypoints.

Acceptance Criteria

  • Allocation failure during listener startup cannot leave SSL or termination global state initialized behind the caller's back.
  • Listener CreateThread failure cannot leak the listener object or leave the subsystem in a partially running state.
  • Later StartSockets and StopSockets calls behave deterministically after a failed startup.
  • Existing successful WebServer/WebSocket startup behavior remains unchanged.
  • The item has commit evidence and targeted validation in this file before Beta 0.7.3.

Validation

  • 2026-05-08: Done in app commit a4c4dc3.
  • python -m emule_workspace validate --workspace-root . passed.
  • python -m emule_workspace build app --workspace-root . --config Debug --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-105659.
  • python -m emule_workspace build app --workspace-root . --config Release --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-105714.
  • Code validation: StartSockets now wraps listener allocation/start in cleanup that unwinds the termination event, SSL state, and listener object on allocation, exception, or CreateThread failure while preserving the normal StopSockets path after the listener object reaches global state.