diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs index acc0c35369..2dbf7c4d23 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/CrashInfoService.cs @@ -508,6 +508,11 @@ public IEnumerable GetNestedExceptions(uint threadId) } } + if (_exception is null) + { + return []; + } + List exceptions = new() { _exception }; @@ -516,8 +521,16 @@ public IEnumerable GetNestedExceptions(uint threadId) void AddExceptions(IEnumerable inner) { + if (inner is null) + { + return; + } foreach (IException exception in inner) { + if (exception is null) + { + continue; + } exceptions.Add(exception); AddExceptions(exception.InnerExceptions); } diff --git a/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs b/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs index cbfd2b1ed8..6432526b97 100644 --- a/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs +++ b/src/SOS/SOS.Extensions/Clrma/ThreadWrapper.cs @@ -149,7 +149,14 @@ private ExceptionWrapper[] NestedExceptions { try { - _nestedExceptions = _crashInfoService.GetNestedExceptions(ThreadId).Select((exception) => new ExceptionWrapper(exception)).ToArray(); + if (_crashInfoService.GetThreadException(ThreadId) is null) + { + _nestedExceptions = Array.Empty(); + } + else + { + _nestedExceptions = _crashInfoService.GetNestedExceptions(ThreadId).Select((exception) => new ExceptionWrapper(exception)).ToArray(); + } } catch (ArgumentOutOfRangeException) { diff --git a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/CrashInfoServiceTests.cs b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/CrashInfoServiceTests.cs new file mode 100644 index 0000000000..a95a1f6bcf --- /dev/null +++ b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/CrashInfoServiceTests.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using Microsoft.Diagnostics.DebugServices; +using Microsoft.Diagnostics.DebugServices.Implementation; +using Xunit; + +namespace Microsoft.Diagnostics.DebugServices.UnitTests +{ + public class CrashInfoServiceTests + { + [Fact] + public void CreateAllowsMessageOnlyNativeAotCrashInfo() + { + string triageJson = """{"version":"1.0.0","runtime_base":"0x7FFF80270000","runtime_type":"4","runtime_version":"9.0.16","reason":"2","thread":"0x7050","message":"Delegate_GarbageCollected"}"""; + + ICrashInfoService crashInfo = CrashInfoService.Create(0, Encoding.UTF8.GetBytes(triageJson), null!); + + Assert.NotNull(crashInfo); + Assert.Equal(CrashReason.EnvironmentFailFast, crashInfo.CrashReason); + Assert.Equal(RuntimeType.NativeAOT, crashInfo.RuntimeType); + Assert.Equal((uint)0x7050, crashInfo.ThreadId); + Assert.Equal("Delegate_GarbageCollected", crashInfo.Message); + Assert.Null(crashInfo.GetException(0)); + Assert.Null(crashInfo.GetThreadException(crashInfo.ThreadId)); + Assert.Empty(crashInfo.GetNestedExceptions(crashInfo.ThreadId)); + } + } +}