Skip to content

Commit e4baf74

Browse files
committed
Fix crash when breakpoint gets hit outside of debug mode
This change fixes a crash that occurs when a breakpoint is hit at a time when the debugger is not active. This is caused by some event handlers being registered prematurely in the DebugAdapter before it gets activated by VS Code. Fixes PowerShell/vscode-powershell#620.
1 parent 22a8272 commit e4baf74

File tree

1 file changed

+46
-11
lines changed

1 file changed

+46
-11
lines changed

src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

+46-11
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class DebugAdapter : DebugAdapterBase
3030
private bool isAttachSession;
3131
private bool waitingForAttach;
3232
private string scriptToLaunch;
33+
private bool enableConsoleRepl;
3334
private bool ownsEditorSession;
3435
private bool executionCompleted;
3536
private string arguments;
@@ -44,29 +45,29 @@ public DebugAdapter(EditorSession editorSession, ChannelBase serverChannel)
4445
: base(serverChannel)
4546
{
4647
this.editorSession = editorSession;
47-
this.editorSession.PowerShellContext.RunspaceChanged += this.powerShellContext_RunspaceChanged;
48-
this.editorSession.DebugService.DebuggerStopped += this.DebugService_DebuggerStopped;
49-
this.editorSession.PowerShellContext.DebuggerResumed += this.powerShellContext_DebuggerResumed;
5048
}
5149

5250
public DebugAdapter(
5351
HostDetails hostDetails,
5452
ProfilePaths profilePaths,
5553
ChannelBase serverChannel,
5654
IEditorOperations editorOperations)
55+
: this(hostDetails, profilePaths, serverChannel, editorOperations, false)
56+
{
57+
}
58+
59+
public DebugAdapter(
60+
HostDetails hostDetails,
61+
ProfilePaths profilePaths,
62+
ChannelBase serverChannel,
63+
IEditorOperations editorOperations,
64+
bool enableConsoleRepl)
5765
: base(serverChannel)
5866
{
5967
this.ownsEditorSession = true;
6068
this.editorSession = new EditorSession();
6169
this.editorSession.StartDebugSession(hostDetails, profilePaths, editorOperations);
62-
this.editorSession.PowerShellContext.RunspaceChanged += this.powerShellContext_RunspaceChanged;
63-
this.editorSession.DebugService.DebuggerStopped += this.DebugService_DebuggerStopped;
64-
this.editorSession.PowerShellContext.DebuggerResumed += this.powerShellContext_DebuggerResumed;
65-
66-
// The assumption in this overload is that the debugger
67-
// is running in UI-hosted mode, no terminal interface
68-
this.editorSession.ConsoleService.OutputWritten += this.powerShellContext_OutputWritten;
69-
this.outputDebouncer = new OutputDebouncer(this);
70+
this.enableConsoleRepl = enableConsoleRepl;
7071
}
7172

7273
protected override void Initialize()
@@ -139,6 +140,8 @@ private async Task OnExecutionCompleted(Task executeTask)
139140
await this.outputDebouncer.Flush();
140141
}
141142

143+
this.UnregisterEventHandlers();
144+
142145
if (this.isAttachSession)
143146
{
144147
// Ensure the read loop is stopped
@@ -198,6 +201,7 @@ protected override void Shutdown()
198201
{
199202
this.editorSession.PowerShellContext.RunspaceChanged -= this.powerShellContext_RunspaceChanged;
200203
this.editorSession.DebugService.DebuggerStopped -= this.DebugService_DebuggerStopped;
204+
this.editorSession.PowerShellContext.DebuggerResumed -= this.powerShellContext_DebuggerResumed;
201205

202206
if (this.ownsEditorSession)
203207
{
@@ -238,6 +242,8 @@ protected async Task HandleLaunchRequest(
238242
LaunchRequestArguments launchParams,
239243
RequestContext<object> requestContext)
240244
{
245+
this.RegisterEventHandlers();
246+
241247
// Set the working directory for the PowerShell runspace to the cwd passed in via launch.json.
242248
// In case that is null, use the the folder of the script to be executed. If the resulting
243249
// working dir path is a file path then extract the directory and use that.
@@ -335,6 +341,8 @@ protected async Task HandleAttachRequest(
335341
{
336342
this.isAttachSession = true;
337343

344+
this.RegisterEventHandlers();
345+
338346
// If there are no host processes to attach to or the user cancels selection, we get a null for the process id.
339347
// This is not an error, just a request to stop the original "attach to" request.
340348
// Testing against "undefined" is a HACK because I don't know how to make "Cancel" on quick pick loading
@@ -454,6 +462,8 @@ protected async Task HandleDisconnectRequest(
454462
}
455463
else
456464
{
465+
this.UnregisterEventHandlers();
466+
457467
await requestContext.SendResult(null);
458468
await this.Stop();
459469
}
@@ -839,6 +849,31 @@ await this.SendEvent(
839849
});
840850
}
841851

852+
private void RegisterEventHandlers()
853+
{
854+
this.editorSession.PowerShellContext.RunspaceChanged += this.powerShellContext_RunspaceChanged;
855+
this.editorSession.DebugService.DebuggerStopped += this.DebugService_DebuggerStopped;
856+
this.editorSession.PowerShellContext.DebuggerResumed += this.powerShellContext_DebuggerResumed;
857+
858+
if (!this.enableConsoleRepl)
859+
{
860+
this.editorSession.ConsoleService.OutputWritten += this.powerShellContext_OutputWritten;
861+
this.outputDebouncer = new OutputDebouncer(this);
862+
}
863+
}
864+
865+
private void UnregisterEventHandlers()
866+
{
867+
this.editorSession.PowerShellContext.RunspaceChanged -= this.powerShellContext_RunspaceChanged;
868+
this.editorSession.DebugService.DebuggerStopped -= this.DebugService_DebuggerStopped;
869+
this.editorSession.PowerShellContext.DebuggerResumed -= this.powerShellContext_DebuggerResumed;
870+
871+
if (!this.enableConsoleRepl)
872+
{
873+
this.editorSession.ConsoleService.OutputWritten -= this.powerShellContext_OutputWritten;
874+
}
875+
}
876+
842877
#endregion
843878

844879
#region Event Handlers

0 commit comments

Comments
 (0)