@@ -655,6 +655,11 @@ void DbgEngAdapter::EngineLoop()
655655 bool outputStateOnStop = settings->Get <bool >(" debugger.dbgEngOutputStateOnStop" );
656656
657657 m_lastExecutionStatus = DEBUG_STATUS_NO_DEBUGGEE ;
658+ // The controller reuses one adapter object across launches, so a terminate request that the previous
659+ // session left unserviced (it exited on its own before we picked the request up) would otherwise be
660+ // latched here and kill this target. The worker queue cannot deliver a Quit() until the launch
661+ // operation completes, which needs the stop event posted below, so no live request can be lost here.
662+ m_terminateRequested = false ;
658663 bool finished = false ;
659664 while (true )
660665 {
@@ -708,6 +713,16 @@ void DbgEngAdapter::EngineLoop()
708713 // WaitForEvent(). The real purpose of this call is to wait until the UI/API initiates another control
709714 // operation, which then calls ExitDispatch(), which causes the DispatchCallbacks() to return.
710715 m_debugClient->DispatchCallbacks (INFINITE );
716+
717+ // A DbgEng client belongs to the thread that created it, and ExitDispatch() is the only call
718+ // documented as safe to make from another thread. So Quit() only raises this flag and wakes us
719+ // up; the terminate itself has to happen here. Doing it from the requesting thread while this
720+ // one sits in DispatchCallbacks() faults inside WinDbg's data model JS provider on 1.2606
721+ // (#1129).
722+ if (m_terminateRequested.exchange (false ) && !TerminateTargetOnEngineThread ())
723+ // Quit() has already reported success to its caller, so this is the only place the
724+ // failure can be surfaced.
725+ LogWarn (" Failed to terminate the target" );
711726 }
712727 // TODO: add step branch and step backs
713728 else if ((execution_status == DEBUG_STATUS_GO ) || (execution_status == DEBUG_STATUS_STEP_INTO )
@@ -908,6 +923,15 @@ bool DbgEngAdapter::Detach()
908923 return true ;
909924}
910925
926+ bool DbgEngAdapter::TerminateTargetOnEngineThread ()
927+ {
928+ if (!this ->m_debugClient )
929+ return false ;
930+
931+ return this ->m_debugClient ->TerminateProcesses () == S_OK ;
932+ }
933+
934+
911935bool DbgEngAdapter::Quit ()
912936{
913937 m_aboutToBeKilled = true ;
0 commit comments