microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
162.49k stars 28.65k forks source link

Thread state in debugger UI does not match what has been sent from the debug adapter #224832

Open DanTup opened 1 month ago

DanTup commented 1 month ago

Edit: See repro in the comment below which may be easier to digest :-)

I'm investigating https://github.com/dart-lang/sdk/issues/56367 which shows the debugger pausing on a breakpoint and then apparently resuming and showing as "Running" in the threads/call stack window unexpectedly. A second thread also shows as "Paused on entry" even though it was continued afterwards.

I don't currently have a repro for this, but I have a log of the DAP traffic that was captured alongside the video in that thread, which I have been through and annotated the important lines:

dap.txt

The video in https://github.com/dart-lang/sdk/issues/56367 starts the debug session at approximately 0:10 in, which corresponds with approximately [3:14:12 AM] in the log file.

The video/log shows:

There is nothing in the DAP traffic to ever show Thread 1 unpausing after hitting the breakpoint, nor Thread 2 becoming paused-at-entry again. I feel like VS Code may somehow be applying a stale state of the call stack view from the past. There are lots of threads/call-stack requests for different threads ongoing - is it possible that one of them completes and then updates the state using information from before the request was sent?

I will post back if I can repro this, but I'm hopeful that with the video/log and info above, someone with knowledge of this code might understand what could be happening.

DanTup commented 1 month ago

I have created what I think is a repro for this here:

https://github.com/DanTup/vscode-mock-debug/tree/repro-vscode-224832

The mock debug adapter does this:

// Start thread 1
await this.delay(1000);
this._threads.push(new Thread(1, 'Thread 1'));
this.sendEvent(new ThreadEvent('started', 1));
this.sendEvent(new OutputEvent('Thread 1 started\n'));
await this.delay(10);
this.sendEvent(new StoppedEvent('entry', 1));
this.sendEvent(new OutputEvent('Thread 1 stopped on entry\n'));
await this.delay(10);
this.sendEvent(new ContinuedEvent(1));
this.sendEvent(new OutputEvent('Thread 1 continued\n'));

// Start thread 2
await this.delay(10);
this._threads.push(new Thread(2, 'Thread 2'));
this.sendEvent(new ThreadEvent('started', 2));
this.sendEvent(new OutputEvent('Thread 2 started\n'));

// Thread 1 hit breakpoint
await this.delay(10);
this.sendEvent(new StoppedEvent('breakpoint', 1));
this.sendEvent(new OutputEvent('Thread 1 stopped on breakpoint\n'));

// Thread 2 stops on entry and resumes
this.sendEvent(new StoppedEvent('entry', 2));
this.sendEvent(new OutputEvent('Thread 2 stopped on entry\n'));
await this.delay(10);
this.sendEvent(new ContinuedEvent(2));
this.sendEvent(new OutputEvent('Thread 2 continued\n'));

Thread 1 is stopped at a breakpoint and never resumed. However, in VS Code I see this:

image

Edit: Fixed typos

roblourens commented 1 month ago

@connor4312 I think you are doing something with threads this month anyway if you want to look at this, if not I can debug it.

Thanks for the repro @DanTup!

DanTup commented 1 week ago

I've had a few more reports of this between GH and Discord. It makes it very difficult to work with apps using multiple threads because you frequently end up in a paused state and no ability to unpause, because VS Code isn't showing the threads.

I noticed that this issue isn't' assigned to any milestone, so not if it shows up where it needs to to be fixed or might be overlooked?

There might also be a related issue where a thread that runs/exits quickly might leave the remaining thread that is paused as not selected, which makes it seem like the app is not paused when it is - although clicking on the thread in the call stack allows resuming from that.. I don't know if this is just a result of the same state corruption, or a separate issue, but it's hard to repro because of this first issue, so I can do some more testing of that once this is fixed.