2026-09-14
The asker is building a profiler that attaches as a debugger to child processes on Windows 11 ARM64. When the debuggee is an x64 binary (running under Microsoft's x64-on-ARM64 emulation layer), the final EXIT_PROCESS_DEBUG_EVENT is sometimes never delivered to WaitForDebugEvent. The child's process handle transitions to the signaled state (so it truly has exited), yet the debug loop sits forever waiting on an event that never arrives. The problem is load-dependent: it reproduces reliably only when many test processes are spawned simultaneously.
This is a genuinely nasty class of bug. The Windows debug subsystem guarantees a terminating event for every attached debuggee — that contract is what makes standard WaitForDebugEvent loops safe. If the guarantee silently breaks under emulation, any debugger, profiler, or sandbox built on the documented API can hang. Compounding this: emulated x64 on ARM64 uses xtajit64.dll plus a hybrid CHPE binary translation cache, so debug events must be marshaled across an extra translation boundary. That's a plausible place for events to be coalesced, reordered, or lost under pressure.
A useful investigative path:
WaitForDebugEventEx with a small timeout in a loop for several seconds. If nothing ever arrives, the event is truly lost, not merely delayed.MsgWaitForMultipleObjects or a second thread). When the handle signals but no exit event follows within a bounded window, synthesize the cleanup yourself and call DebugActiveProcessStop. This is pragmatic even if the root cause is never fixed.xtajit64/wow-layer issue and worth a Feedback Hub report with an ETW trace (Microsoft-Windows-Kernel-Process + Microsoft-Windows-Wow64 providers).Gotchas: don't confuse this with the well-known "last thread exit vs. process exit" ordering quirk — that one still delivers the event, just later than expected. And beware that ContinueDebugEvent on a stale event id can itself hang the loop, so the fallback path must be idempotent.
