Skip to content

Debug Session not respecting Added or removed Breakpoints & Integrated Shell Crash #1494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
GABeech opened this issue Aug 22, 2018 · 18 comments
Labels
Area-Debugging Issue-Enhancement A feature request (enhancement).

Comments

@GABeech
Copy link

GABeech commented Aug 22, 2018

Issue Description

When I run a debug session two things happen:

  1. Any addition or removal of breakpoints is not respected
  2. The Integrated shell Crashes after not exiting correctly

You can replicate this by running a small script like:

while ($true)
{
  Write-Output "I'm In a loop"
  Start-Sleep 10
  Write-Output "I just woke up"
}

Removing Breakpoint

  • Set a breakpoint on the first Write-Output
  • Debug The script
  • Remove Breakpoint on First Write-Output
  • Continue running

What will happen is the debugger will break again on the first Write-Output and you won't be able to continue. If you stop execution and type exit in the debug terminal the integrated terminal will crash

Adding Breakpoint

  • Debug the script
  • Set a breakpoint anywhere in the while loop
  • It will never be hit.

Attached Logs

EditorServices.log
vscode-powershell.log

) about
capturing and sending logs.

Environment Information

Visual Studio Code

Name Version
Operating System Windows_NT x64 10.0.16299
VSCode 1.26.1
PowerShell Extension Version 1.8.3

PowerShell Information

Name Value
PSVersion 5.1.16299.492
PSEdition Desktop
PSCompatibleVersions 1.0 2.0 3.0 4.0 5.0 5.1.16299.492
BuildVersion 10.0.16299.492
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

Visual Studio Code Extensions

Visual Studio Code Extensions(Click to Expand)
Extension Author Version
aspnet-helper schneiderpat 0.6.4
ecdc mitchdenny 0.12.0
EditorConfig EditorConfig 0.12.4
github-issues-prs ms-vscode 0.9.0
gitlens eamodio 8.5.6
jenkins-declarative-support jmMeessen 0.1.0
markdown-all-in-one yzhang 1.6.0
PowerShell ms-vscode 1.8.3
python ms-python 2018.7.1
rainbow-csv mechatroner 0.4.2
vscode-github KnisterPeter 0.30.0
vscode-icons robertohuertasm 7.25.0
vscode-markdownlint DavidAnson 0.20.0
vscode-mermaid-preview vstirbu 0.10.1
xml DotJoshJohnson 2.3.2
@GABeech GABeech changed the title Debug Session no respecting Added or removed Breakpoints & Integrated Shell Crash Debug Session not respecting Added or removed Breakpoints & Integrated Shell Crash Aug 22, 2018
@rjmholt rjmholt added Issue-Bug A bug to squash. Area-Debugging labels Aug 23, 2018
@rjmholt
Copy link
Contributor

rjmholt commented Aug 23, 2018

Thanks for opening an issue @GABeech. I can reproduce this on my machine. I've been looking into it but haven't found the cause yet. Will continue investigating.

@rjmholt
Copy link
Contributor

rjmholt commented Aug 23, 2018

@SeeminglyScience
Copy link
Collaborator

@rjmholt If you have the PSRL build still, see if you can reproduce it there. I made a lot of changes around the runspace handle queues.

@rjmholt
Copy link
Contributor

rjmholt commented Oct 8, 2018

So I did some more investigating on this today.

The breakpoint is set correctly and unset correctly, but trying to set it again does nothing at all. This is almost certainly because PSES is being blocked by the current execution.

I was curious as to where PSES thought it was, so I paused the PSES .NET debugger and on my Windows machine in 1.9.1, it reports itself as being here:
https://github.com/PowerShell/PowerShellEditorServices/blob/f1ab46289904b77fe5f5bd97cc89e2f5286444db/src/PowerShellEditorServices/Console/WindowsConsoleOperations.cs#L22

In v2, I think it reports itself as being here:
https://github.com/PowerShell/PowerShellEditorServices/blob/67af23203c0d7aac52a6c5655d7d7f1202e80dd0/src/PowerShellEditorServices/Session/PowerShellContext.cs#L651

I think it basically comes down to the debug adapter not being able to interrupt the script to add a new breakpoint -- which is obviously a problem.

In 1.9.1 I get no crash (or at least I didn't this time). But with v2 I got a pipe broken error, which I think we've seen can also occur in 1.9.1.

@rjmholt
Copy link
Contributor

rjmholt commented Oct 10, 2018

After looking into this and thinking about it a bit, this looks like a deeper issue -- I'll see what we can do to fix it, but I think we will need to do some cleverness with interrupting the execution of the PowerShell pipeline.

@SeeminglyScience
Copy link
Collaborator

We could implement this in 2.0. Taking over script execution between sequence points can be done with events, but that requires all the nested context work done for PSReadLine.

@rjmholt
Copy link
Contributor

rjmholt commented Oct 10, 2018

If we can engineer that, it would be useful in a whole bunch of cases for cancellation of the PowerShell executions powering most requests -- so we could finally implement $/cancelRequest properly.

@SeeminglyScience
Copy link
Collaborator

We can already trigger a pipeline stop from any thread, the engine supports that. Just gotta tie a request to a powershell instance

@rjmholt rjmholt added Issue-Enhancement A feature request (enhancement). and removed Area-Threading Issue-Bug A bug to squash. labels Oct 16, 2018
@rjmholt
Copy link
Contributor

rjmholt commented Oct 16, 2018

Ok @GABeech I've done some research on this one and talked to @PaulHigin as well, who is our debugger expert.

Because the PowerShell debugger is just PowerShell, setting a breakpoint while the pipeline is running is a bit trickier than for other languages. As far as I know, it's something that neither PowerShell nor the ISE has directly supported.

But, experimenting with your scenario, using the pause (⏸ or F6) button will stop pipeline execution. It hooks into the same API that the ISE uses with Ctrl+Break and PowerShell itself (the ConHost) uses with Ctrl+B.

So the current way to set a breakpoint while a script is running like in the scenario above it:

  • F6 (Pause)
  • Set the breakpoint
  • F5 (Continue)

Bear in mind that if you have a single long running command or .NET call, this can't pause that. There's no mechanism for that anywhere, because the PowerShell debugger is PowerShell -- it can't stop in the middle of a native or .NET call.

I'm looking into how we might make this automatic -- so that when you set a breakpoint, it will stop the pipeline, insert the breakpoint and then continue on its way. But it's complicated by needing to sync up VSCode's client state.

@SeeminglyScience
Copy link
Collaborator

@rjmholt We could use events. I think this should be safe from issues like the completion deadlock.

Here's a little sample:

$timer = [System.Timers.Timer]::new(60000)
Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
    $Event | Unregister-Event
    Set-PSBreakpoint -Variable someSpecificVar -Mode Write
}

$timer.Enabled = $true

# After a minute, the debugger will break on the someSpecificVar assignment.
while ($true) {
    $someSpecificVar = $true
    Start-Sleep 5
}

We would probably want register it on an event on PowerShellContext instead of Timer, that's just for the PoC. The idea is that PowerShell events like those register via Register-ObjectEvent will be processed between sequence points if a script is running. This still won't help in situations where a single sequence point is taking a long time, but we can't really do anything about that.

@rkeithhill
Copy link
Contributor

Does OnIdle execute between pipeline invocations? If so, we could queue up breakpoint requests and execute them then.

@SeeminglyScience
Copy link
Collaborator

SeeminglyScience commented Oct 16, 2018

@rkeithhill Not sure what the usual timeout is for OnIdle, with PSReadLine it's 200ms (or immediately when we ask it to check for events). I know for sure it won't execute between sequence points of a long running script though.

Same idea though, we would queue up breakpoints by raising an event on an object we control and the subscriber would get to it at the next sequence point.

@rjmholt
Copy link
Contributor

rjmholt commented Oct 16, 2018

@rkeithhill I don't think OnIdle events are raised between pipeline invocations, but could be wrong.

The reason I mention our debugService.Break() method, is because I think it actually uses the right API:

It's what the ISE uses for interrupting a currently running script to break into it.

Is there a reason using that is a bad idea for us?

@SeeminglyScience
Copy link
Collaborator

@rjmholt I could be wrong but I believe that just tells the debugger that it should pause at the next sequence point. I don't think it synchronously stops the debugger.

@rjmholt
Copy link
Contributor

rjmholt commented Oct 16, 2018

Right, it just says "please pause the debugger at the next opportunity". Is there a way we think we can/should be doing better than that?

@SeeminglyScience
Copy link
Collaborator

We're not specifically trying to stop the debugger right? If we're just trying to set a breakpoint then I think the event route is cleaner. We could stop the debugger, then in the PowerShellContext.OnDebuggerStop method we could set queued breakpoints and possibly exit early, that seems like a lot of extra state to manage though.

@rjmholt
Copy link
Contributor

rjmholt commented Oct 16, 2018

Ah, yes agreed!

It seems like an API we ought to have on PowerShellContext -- like QueueSequencePointCommand or something

@PaulHigin
Copy link

Sorry for the late contribution. If I understand the issue correctly, engine events are not needed to manage script breakpoints. But the only way to update script breakpoints on running script is to, as discussed above:
a. Break into the debugger (set to step mode)
b. Add/remove/enable/disable breakpoints
c. Resume script execution

Note that the first step (a.) can be problematic if the script is not running but is stalled during a dotNet API call or while running a native command. The debugger stop event will not occur until the next sequence point is executed.

Breaking into the debugger can be done via the ScriptDebugger.SetDebuggerStepMode() method, and engine events are not needed. The method can be called from any thread. Then as @SeeminglyScience mentions, breakpoints can be managed during the DebuggerStop event callback via the ScriptDebugger.ProcessCommand() method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Debugging Issue-Enhancement A feature request (enhancement).
Projects
None yet
Development

No branches or pull requests

5 participants