Skip to content

Commit 385b90a

Browse files
MICore: Runtime-impactful changes for nullable enablement
- Refactor MICommandFactory to use constructor injection (readonly _debugger field) - Move MICommandFactory.GetInstance() from DebuggedProcess to Debugger constructor - Fix bug: firstException should only be set when null (was checking != null) - Add null safety: _transport?.Close(), ThreadCreatedEvent?.Invoke, ThreadExitedEvent?.Invoke - Add null throw in SendToTransport for null transport - Use GetTargetProcessExitedReason() instead of raw _closeMessage - Null-safe access to _initialErrors/_initializationLog in OnDebuggerProcessExit - Pass EventArgs.Empty instead of null for DebuggerExitEvent - Use pattern matching for IsModuleLoad check - Make _commandLock readonly, initialize _lastCommandText Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1d87c2a commit 385b90a

5 files changed

Lines changed: 35 additions & 21 deletions

File tree

src/MICore/CommandFactories/MICommandFactory.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,34 @@ public enum AsyncBreakSignal
4848

4949
public abstract class MICommandFactory
5050
{
51-
protected Debugger _debugger;
51+
protected readonly Debugger _debugger;
5252

5353
public MIMode Mode { get; private set; }
5454

5555
public abstract string Name { get; }
5656

5757
internal int MajorVersion { get; set; }
5858

59+
protected MICommandFactory(Debugger debugger)
60+
{
61+
_debugger = debugger;
62+
}
63+
5964
public static MICommandFactory GetInstance(MIMode mode, Debugger debugger)
6065
{
6166
MICommandFactory commandFactory;
6267

6368
switch (mode)
6469
{
6570
case MIMode.Gdb:
66-
commandFactory = new GdbMICommandFactory();
71+
commandFactory = new GdbMICommandFactory(debugger);
6772
break;
6873
case MIMode.Lldb:
69-
commandFactory = new LlldbMICommandFactory();
74+
commandFactory = new LlldbMICommandFactory(debugger);
7075
break;
7176
default:
7277
throw new ArgumentException(null, nameof(mode));
7378
}
74-
commandFactory._debugger = debugger;
7579
commandFactory.Mode = mode;
7680
commandFactory.Radix = 10;
7781
return commandFactory;

src/MICore/CommandFactories/gdb.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ internal class GdbMICommandFactory : MICommandFactory
1919
private int _currentThreadId = 0;
2020
private uint _currentFrameLevel = 0;
2121

22+
public GdbMICommandFactory(Debugger debugger)
23+
: base(debugger)
24+
{
25+
}
26+
2227
public override string Name
2328
{
2429
get { return "GDB"; }

src/MICore/CommandFactories/lldb.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ namespace MICore
1616
{
1717
internal class LlldbMICommandFactory : MICommandFactory
1818
{
19+
public LlldbMICommandFactory(Debugger debugger)
20+
: base(debugger)
21+
{
22+
}
23+
1924
public override string Name
2025
{
2126
get { return "LLDB"; }

src/MICore/Debugger.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public bool IsClosed
7272
public uint MaxInstructionSize { get; private set; }
7373
public bool Is64BitArch { get; private set; }
7474
public CommandLock CommandLock { get { return _commandLock; } }
75-
public MICommandFactory MICommandFactory { get; protected set; }
75+
public MICommandFactory MICommandFactory { get; }
7676
public Logger Logger { private set; get; }
7777

7878
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
@@ -124,12 +124,12 @@ public StoppingEventArgs(Results results, BreakRequest asyncRequest = BreakReque
124124
}
125125

126126
private ITransport _transport;
127-
private CommandLock _commandLock = new CommandLock();
127+
private readonly CommandLock _commandLock = new CommandLock();
128128

129129
/// <summary>
130130
/// The last command we sent over the transport. This includes both the command name and arguments.
131131
/// </summary>
132-
private string _lastCommandText;
132+
private string _lastCommandText = string.Empty;
133133
private uint _lastCommandId;
134134

135135
/// <summary>
@@ -169,6 +169,7 @@ public Debugger(LaunchOptions launchOptions, Logger logger)
169169
_debuggeePids = new Dictionary<string, int>();
170170
Logger = logger;
171171
_miResults = new MIResults(logger);
172+
MICommandFactory = MICommandFactory.GetInstance(launchOptions.DebuggerMIMode, this);
172173
}
173174

174175
protected void SetDebuggerPid(int debuggerPid)
@@ -392,7 +393,7 @@ private async Task<bool> DoInternalBreakActions(bool fIsAsyncBreak)
392393
}
393394
catch (Exception e) when (ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true))
394395
{
395-
if (firstException != null)
396+
if (firstException is null)
396397
{
397398
firstException = e;
398399
}
@@ -404,7 +405,7 @@ private async Task<bool> DoInternalBreakActions(bool fIsAsyncBreak)
404405
{
405406
if (this.IsClosed)
406407
{
407-
source.TrySetException(new DebuggerDisposedException(_closeMessage));
408+
source.TrySetException(new DebuggerDisposedException(GetTargetProcessExitedReason()));
408409
}
409410
else
410411
{
@@ -524,7 +525,7 @@ private void Close(string closeMessage)
524525
Debug.Assert(_closeMessage == null, "Why was Close called more than once? Should be impossible.");
525526

526527
_closeMessage = closeMessage;
527-
_transport.Close();
528+
_transport?.Close();
528529
lock (_waitingOperations)
529530
{
530531
foreach (var value in _waitingOperations.Values)
@@ -905,7 +906,7 @@ private Task<Results> CmdAsyncInternal(string command, ResultClass expectedResul
905906
{
906907
if (this.IsClosed)
907908
{
908-
throw new DebuggerDisposedException(_closeMessage);
909+
throw new DebuggerDisposedException(GetTargetProcessExitedReason());
909910
}
910911

911912
id = ++_lastCommandId;
@@ -992,13 +993,13 @@ public void OnDebuggerProcessExit(/*OPTIONAL*/ string exitCode)
992993
if (isMinGWOrCygwin && IsUnsupportedWindowsGdbVersion(_gdbVersion))
993994
{
994995
exception = new MIDebuggerInitializeFailedUnsupportedGdbException(
995-
this.MICommandFactory.Name, _initialErrors.ToList().AsReadOnly(), _initializationLog.ToList().AsReadOnly(), _gdbVersion);
996+
this.MICommandFactory.Name, (_initialErrors?.ToList() ?? new List<string>()).AsReadOnly(), (_initializationLog?.ToList() ?? new List<string>()).AsReadOnly(), _gdbVersion);
996997
SendUnsupportedWindowsGdbEvent(_gdbVersion);
997998
}
998999
else
9991000
{
10001001
exception = new MIDebuggerInitializeFailedException(
1001-
this.MICommandFactory.Name, _initialErrors.ToList().AsReadOnly(), _initializationLog.ToList().AsReadOnly());
1002+
this.MICommandFactory.Name, (_initialErrors?.ToList() ?? new List<string>()).AsReadOnly(), (_initializationLog?.ToList() ?? new List<string>()).AsReadOnly());
10021003
}
10031004

10041005
_initialErrors = null;
@@ -1029,7 +1030,7 @@ public void OnDebuggerProcessExit(/*OPTIONAL*/ string exitCode)
10291030
{
10301031
if (DebuggerExitEvent != null)
10311032
{
1032-
DebuggerExitEvent(this, null);
1033+
DebuggerExitEvent(this, EventArgs.Empty);
10331034
}
10341035
}
10351036
}
@@ -1419,8 +1420,7 @@ this.LaunchOptions is LocalLaunchOptions &&
14191420

14201421
private void OnNotificationOutput(string cmd)
14211422
{
1422-
Results results = null;
1423-
if ((results = MICommandFactory.IsModuleLoad(cmd)) != null)
1423+
if (MICommandFactory.IsModuleLoad(cmd) is Results results)
14241424
{
14251425
if (LibraryLoadEvent != null)
14261426
{
@@ -1460,12 +1460,12 @@ private void OnNotificationOutput(string cmd)
14601460
else if (cmd.StartsWith("thread-created,", StringComparison.Ordinal))
14611461
{
14621462
results = _miResults.ParseResultList(cmd.Substring("thread-created,".Length));
1463-
ThreadCreatedEvent(this, new ResultEventArgs(results, 0));
1463+
ThreadCreatedEvent?.Invoke(this, new ResultEventArgs(results, 0));
14641464
}
14651465
else if (cmd.StartsWith("thread-exited,", StringComparison.Ordinal))
14661466
{
14671467
results = _miResults.ParseResultList(cmd.Substring("thread-exited,".Length));
1468-
ThreadExitedEvent(this, new ResultEventArgs(results, 0));
1468+
ThreadExitedEvent?.Invoke(this, new ResultEventArgs(results, 0));
14691469
}
14701470
else if (cmd.StartsWith("telemetry,", StringComparison.Ordinal))
14711471
{
@@ -1619,14 +1619,15 @@ private async void PostCommand(string cmd)
16191619

16201620
private void SendToTransport(string cmd)
16211621
{
1622-
_transport.Send(cmd);
1622+
ITransport transport = _transport ?? throw new InvalidOperationException();
1623+
transport.Send(cmd);
16231624

16241625
// https://github.com/Microsoft/MIEngine/issues/616 :
16251626
// If it is local gdb (MinGW/Cygwin) on Windows, we need to send an extra line after commands
16261627
// so that if it errors, the error will come through.
16271628
if (this.SendNewLineAfterCmd)
16281629
{
1629-
_transport.Send(String.Empty);
1630+
transport.Send(String.Empty);
16301631
}
16311632
}
16321633

src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngin
6464
_libraryLoaded = new List<string>();
6565
_loadOrder = 0;
6666
_deleteEntryPointBreakpoint = false;
67-
MICommandFactory = MICommandFactory.GetInstance(launchOptions.DebuggerMIMode, this);
6867
_waitDialog = (MICommandFactory.SupportsStopOnDynamicLibLoad() && launchOptions.WaitDynamicLibLoad) ? new HostWaitDialog(ResourceStrings.LoadingSymbolMessage, ResourceStrings.LoadingSymbolCaption) : null;
6968
Natvis = new Natvis.Natvis(this, launchOptions.ShowDisplayString, configStore);
7069

0 commit comments

Comments
 (0)