fix(dap): keep evaluator registry when continuing all processes - #1274
Merged
Conversation
`init/1` seeds `paused_processes` with a synthetic `:evaluator` entry that
holds variable references produced by `evaluate` requests, but
`maybe_continue_other_processes/2` wiped the entire map when resuming all
threads. Any subsequent `evaluate` request then raised
`** (KeyError) key :evaluator not found in: %{#PID<...> => %PausedProcess{}}`.
The same loop also called `:int.continue(:evaluator)` on that atom key,
logging a spurious `:int` failure on every continue.
Preserve the `:evaluator` entry across continue, skip non-pid keys when
calling `:int.continue/1`, and fall back to a fresh registry in the
evaluate handler instead of raising.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The debug adapter crashes
evaluaterequests with:init/1seedspaused_processeswith a synthetic:evaluatorentry that holds the variable references produced byevaluaterequests.maybe_continue_other_processes/2then wiped the whole map with%{state | paused_processes: %{}}when resuming all threads, so any laterevaluaterequest hitMap.fetch!(state.paused_processes, :evaluator)and raised. That matches the crash dumps, which show a map containing only a real pid — one that was added after the wipe.The same loop also called
:int.continue(:evaluator)on that atom key, logging a spurious:intfailure on every continue.Changes
maybe_continue_other_processes/2preserves the:evaluatorentry (Map.take(..., [:evaluator])) and only calls:int.continue/1for real pids (is_pid/1guard).:evaluatorentry falls back to a fresh registry instead of raising.Testing
Added
test "evaluate expression after continuing all processes"— pause on adbgbreakpoint, continue all threads, then evaluate. Without the server fix it reproduces exactly the reported error (internalServerError/** (KeyError) key :evaluator not found in: %{#PID<...> => %PausedProcess{...}}); with the fix it passes.Full
apps/debug_adaptersuite (--include fixture): 134/138 passed, 1 skipped. The 4 failures (basic debugging,multiple paused processes,continue without singleThread resumes all paused processes,breakpoints breakpoint in protocol) also fail on an unmodified tree in my environment — they all depend on:intline breakpoints, which don't trigger on Elixir 1.21.0-dev / OTP 28 locally. Pre-existing and unrelated, but it does mean the:int-breakpoint continue path wasn't exercised locally; only thedbgcontinue path was. CI should cover the rest.🤖 Generated with Claude Code