diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs
index 8f1bb430e7..d09bf213fd 100644
--- a/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs
+++ b/src/Microsoft.Diagnostics.ExtensionCommands/DumpAsyncCommand.cs
@@ -459,7 +459,7 @@ bool ShouldIncludeStack(AsyncObject obj)
// Outputs a line of information for each instance field on the object.
void RenderFields(IAddressableTypedEntity? obj, int depth)
{
- if (obj is not null)
+ if (obj?.Type is not null)
{
string depthTab = new string(' ', depth * TabWidth);
@@ -489,33 +489,36 @@ void RenderFields(IAddressableTypedEntity? obj, int depth)
// Gets a printable description for the specified object.
string Describe(ClrObject obj)
{
- // Default the description to the type name.
- string description = obj.Type.Name;
-
- if (IsStateMachineBox(obj.Type))
+ string description = string.Empty;
+ if (obj.Type?.Name is not null)
{
- // Remove the boilerplate box type from the name.
- int pos = description.IndexOf("StateMachineBox<", StringComparison.Ordinal);
- if (pos >= 0)
+ // Default the description to the type name.
+ description = obj.Type.Name;
+
+ if (IsStateMachineBox(obj.Type))
{
- ReadOnlySpan slice = description.AsSpan(pos + "StateMachineBox<".Length);
- slice = slice.Slice(0, slice.Length - 1); // remove trailing >
- description = slice.ToString();
+ // Remove the boilerplate box type from the name.
+ int pos = description.IndexOf("StateMachineBox<", StringComparison.Ordinal);
+ if (pos >= 0)
+ {
+ ReadOnlySpan slice = description.AsSpan(pos + "StateMachineBox<".Length);
+ slice = slice.Slice(0, slice.Length - 1); // remove trailing >
+ description = slice.ToString();
+ }
}
- }
- else if (TryGetValidObjectField(obj, "m_action", out ClrObject taskDelegate))
- {
- // If we can figure out what the task's delegate points to, append the method signature.
- if (TryGetMethodFromDelegate(runtime, taskDelegate, out ClrMethod? method))
+ else if (TryGetValidObjectField(obj, "m_action", out ClrObject taskDelegate))
+ {
+ // If we can figure out what the task's delegate points to, append the method signature.
+ if (TryGetMethodFromDelegate(runtime, taskDelegate, out ClrMethod? method))
+ {
+ description = $"{description} {{{method!.Signature}}}";
+ }
+ }
+ else if (obj.Address != 0 && taskCompletionSentinel.Address == obj.Address)
{
- description = $"{description} {{{method!.Signature}}}";
+ description = "TaskCompletionSentinel";
}
}
- else if (obj.Address != 0 && taskCompletionSentinel.Address == obj.Address)
- {
- description = "TaskCompletionSentinel";
- }
-
return description;
}
@@ -527,14 +530,17 @@ bool IncludeInOutput(ClrObject obj)
return false;
}
- if (MethodTableAddress is ulong mt && obj.Type.MethodTable != mt)
+ if (obj.Type is not null)
{
- return false;
- }
+ if (MethodTableAddress is ulong mt && obj.Type.MethodTable != mt)
+ {
+ return false;
+ }
- if (NameSubstring is not null && !obj.Type.Name.Contains(NameSubstring))
- {
- return false;
+ if (NameSubstring is not null && obj.Type.Name is not null && !obj.Type.Name.Contains(NameSubstring))
+ {
+ return false;
+ }
}
return true;
@@ -655,37 +661,42 @@ Dictionary CollectObjects()
//
void AddContinuation(ClrObject continuation, List continuations)
{
- if (continuation.Type.Name.StartsWith("System.Collections.Generic.List<", StringComparison.Ordinal))
+ if (continuation.Type is not null)
{
- if (continuation.Type.GetFieldByName("_items") is ClrInstanceField itemsField)
+ if (continuation.Type.Name is not null &&
+ continuation.Type.Name.StartsWith("System.Collections.Generic.List<", StringComparison.Ordinal))
{
- ClrObject itemsObj = itemsField.ReadObject(continuation.Address, interior: false);
- if (!itemsObj.IsNull)
+ if (continuation.Type.GetFieldByName("_items") is ClrInstanceField itemsField)
{
- ClrArray items = itemsObj.AsArray();
- if (items.Rank == 1)
+ ClrObject itemsObj = itemsField.ReadObject(continuation.Address, interior: false);
+ if (!itemsObj.IsNull)
{
- for (int i = 0; i < items.Length; i++)
+ ClrArray items = itemsObj.AsArray();
+ if (items.Rank == 1)
{
- if (items.GetObjectValue(i) is ClrObject { IsValid: true } c)
+ for (int i = 0; i < items.Length; i++)
{
- continuations.Add(ResolveContinuation(c));
+ if (items.GetObjectValue(i) is ClrObject { IsValid: true } c)
+ {
+ continuations.Add(ResolveContinuation(c));
+ }
}
}
}
}
}
- }
- else
- {
- continuations.Add(continuation);
+ else
+ {
+ continuations.Add(continuation);
+ }
}
}
// Tries to get the object contents of a Task's continuations field
bool TryGetContinuation(ClrObject obj, out ClrObject continuation)
{
- if (obj.Type.GetFieldByName("m_continuationObject") is ClrInstanceField continuationObjectField &&
+ if (obj.Type is not null &&
+ obj.Type.GetFieldByName("m_continuationObject") is ClrInstanceField continuationObjectField &&
continuationObjectField.ReadObject(obj.Address, interior: false) is ClrObject { IsValid: true } continuationObject)
{
continuation = ResolveContinuation(continuationObject);
@@ -888,7 +899,7 @@ private void WriteCodeLink(ulong address)
}
/// Gets whether the specified type is an AsyncStateMachineBox{T}.
- private static bool IsStateMachineBox(ClrType type)
+ private static bool IsStateMachineBox(ClrType? type)
{
// Ideally we would compare the metadata token and module for the generic template for the type,
// but that information isn't fully available via ClrMd, nor can it currently find DebugFinalizableAsyncStateMachineBox
diff --git a/src/SOS/SOS.UnitTests/SOS.cs b/src/SOS/SOS.UnitTests/SOS.cs
index 34fffd02ab..a0ec5a83aa 100644
--- a/src/SOS/SOS.UnitTests/SOS.cs
+++ b/src/SOS/SOS.UnitTests/SOS.cs
@@ -14,6 +14,11 @@
using Xunit.Abstractions;
using Xunit.Extensions;
+// Newer SDKs flag MemberData(nameof(Configurations)) with this error
+// Avoid unnecessary zero-length array allocations. Use Array.Empty