EXIT_PROCESS_DEBUG_EVENT silently dropped for emulated x64 debuggee on Windows ARM64 under load

2026-09-14

Stack Overflow: View Question

Tags: c++, debugging, winapi, arm64

Score: 3 | Views: 103

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:

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.

The challenge: A documented OS invariant appears to break only under the specific combination of ARM64 host, emulated x64 debuggee, and concurrent load — exactly the kind of bug that erodes trust in the platform's debugging contract.

All newsletters