Frequent standby-park churn (duplicate logins sharing one clientID) was crashing the server with 0xC0000409 (STACK_BUFFER_OVERRUN). The heartbeat handler posts the raw CONTEXT_OBJECT pointer via PostMessageA (WM_UPDATE_ACTIVEWND) without holding a reference, so RemoveStaleContext could recycle the context back to the pool and reuse it before the UI thread consumed the queued message. UpdateActiveWindow then read a stale/recycled object, and the unguarded Authorization memcpy overflowed the 200-byte HeartbeatACK field and clobbered the stack cookie. Hold the object's IoRefCount across the deferred message: fetch_add before PostMessageA (with rollback on failure) and a paired fetch_sub in UpdateUserEvent after UpdateActiveWindow returns. RemoveStaleContext already waits for IoRefCount == 0 before MoveContextToFreePoolList, so the object is now guaranteed to stay alive for the whole deferred call. Also bound the three memcpy sites (two Signature[64], one Authorization[200]) with explicit truncation so an unexpectedly long signature or license can no longer overflow its fixed buffer in Release builds, where ASSERT is a no-op. Co-Authored-By: deepseek-v4-pro
496 KiB
496 KiB