diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.NativeAot.cs index 32db59daefe2c..f4c015efe34aa 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.NativeAot.cs @@ -80,18 +80,19 @@ private void InitializeForIpAddressArray(IntPtr[] ipAddresses, int skipFrames, i #if !TARGET_WASM internal void ToString(TraceFormat traceFormat, StringBuilder builder) { - if (_stackFrames == null) + if (_stackFrames != null) { - return; - } - - foreach (StackFrame frame in _stackFrames) - { - frame.AppendToStackTrace(builder); + foreach (StackFrame frame in _stackFrames) + { + frame?.AppendToStackTrace(builder); + } } if (traceFormat == TraceFormat.Normal && builder.Length >= Environment.NewLine.Length) builder.Length -= Environment.NewLine.Length; + + if (traceFormat == TraceFormat.TrailingNewLine && builder.Length == 0) + builder.AppendLine(); } #endif } diff --git a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs index 5e84594fc6297..7ee32a0c42005 100644 --- a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs +++ b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs @@ -403,9 +403,10 @@ private void EmitPointerTypeName(PointerSignatureHandle pointerSigHandle) /// /// Emit function pointer type. /// - private void EmitFunctionPointerTypeName() + private static void EmitFunctionPointerTypeName() { - _outputBuilder.Append("IntPtr"); + // Function pointer types have no textual representation and we have tests making sure + // they show up as empty strings in stack traces, so deliberately do nothing. } /// diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index c76a1ee94d975..0bc3f5f124210 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -172,6 +172,7 @@ private static bool GetLinqExpressionsBuiltWithIsInterpretingOnly() public static bool IsAsyncFileIOSupported => !IsBrowser && !IsWasi; public static bool IsLineNumbersSupported => !IsNativeAot; + public static bool IsILOffsetsSupported => !IsNativeAot; public static bool IsInContainer => GetIsInContainer(); public static bool IsNotInContainer => !IsInContainer; diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameExtensionsTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameExtensionsTests.cs index 3278cf3f5fd39..931fe55adce17 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameExtensionsTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameExtensionsTests.cs @@ -16,21 +16,21 @@ public static IEnumerable StackFrame_TestData() yield return new object[] { new StackFrame(int.MaxValue) }; } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNativeAot))] [MemberData(nameof(StackFrame_TestData))] public void HasNativeImage_StackFrame_ReturnsFalse(StackFrame stackFrame) { Assert.False(stackFrame.HasNativeImage()); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNativeAot))] [MemberData(nameof(StackFrame_TestData))] public void GetNativeIP_StackFrame_ReturnsZero(StackFrame stackFrame) { Assert.Equal(IntPtr.Zero, stackFrame.GetNativeIP()); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNativeAot))] [MemberData(nameof(StackFrame_TestData))] public void GetNativeImageBase_StackFrame_ReturnsZero(StackFrame stackFrame) { @@ -43,7 +43,7 @@ public static IEnumerable HasMethod_TestData() yield return new object[] { new StackFrame(int.MaxValue), false }; } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsILOffsetsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))] [MemberData(nameof(HasMethod_TestData))] public void HasILOffset_Invoke_ReturnsExpected(StackFrame stackFrame, bool expected) @@ -59,6 +59,7 @@ public void HasILOffset_NullStackFrame_ThrowsNullReferenceException() [Theory] [ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/103218", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] [MemberData(nameof(HasMethod_TestData))] public void HasMethod_Invoke_ReturnsExpected(StackFrame stackFrame, bool expected) { @@ -79,6 +80,7 @@ public static IEnumerable HasSource_TestData() } [Theory] + [ActiveIssue("https://github.com/dotnet/runtime/issues/103218", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] [MemberData(nameof(HasSource_TestData))] public void HasSource_Invoke_ReturnsExpected(StackFrame stackFrame, bool expected) { diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameTests.cs index 67ba8fd483eb1..b8f225f33d8cf 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackFrameTests.cs @@ -75,6 +75,7 @@ public void SkipFrames_CallMethod_ReturnsExpected() [Theory] [InlineData(int.MinValue)] [InlineData(int.MaxValue)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/103218", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void SkipFrames_ManyFrames_HasNoMethod(int skipFrames) { var stackFrame = new StackFrame(skipFrames); @@ -123,6 +124,7 @@ public static IEnumerable ToString_TestData() [Theory] [ActiveIssue("https://github.com/mono/mono/issues/15186", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/103156", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] [MemberData(nameof(ToString_TestData))] public void ToString_Invoke_ReturnsExpected(StackFrame stackFrame, string expectedToString) { @@ -168,7 +170,10 @@ private static void VerifyStackFrameSkipFrames(StackFrame stackFrame, bool isFil } else { - Assert.True(stackFrame.GetILOffset() >= 0, $"Expected GetILOffset() {stackFrame.GetILOffset()} for {stackFrame} to be greater or equal to zero."); + if (PlatformDetection.IsILOffsetsSupported) + { + Assert.True(stackFrame.GetILOffset() >= 0, $"Expected GetILOffset() {stackFrame.GetILOffset()} for {stackFrame} to be greater or equal to zero."); + } } // GetMethod returns null for unknown frames. diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs index a095dc87007c0..b0470c1c8a5bd 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs @@ -9,7 +9,7 @@ namespace System.Diagnostics.SymbolStore.Tests { public class StackTraceSymbolsTests { - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [ActiveIssue("https://github.com/dotnet/runtime/issues/51399", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] public void StackTraceSymbolsDoNotLockFile() { diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs index 93bdf3840bbd1..1b2c9fb7274ef 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs @@ -47,7 +47,7 @@ public void MethodsToSkip_Get_ReturnsZero() public void Ctor_Default() { var stackTrace = new StackTrace(); - VerifyFrames(stackTrace, false); + VerifyFrames(stackTrace, false, 0); } [Theory] @@ -57,7 +57,7 @@ public void Ctor_Default() public void Ctor_FNeedFileInfo(bool fNeedFileInfo) { var stackTrace = new StackTrace(fNeedFileInfo); - VerifyFrames(stackTrace, fNeedFileInfo); + VerifyFrames(stackTrace, fNeedFileInfo, 0); } [Theory] @@ -73,7 +73,7 @@ public void Ctor_SkipFrames(int skipFrames) Assert.Equal(emptyStackTrace.FrameCount - skipFrames, stackTrace.FrameCount); Assert.Equal(expectedMethods, stackTrace.GetFrames().Select(f => f.GetMethod())); - VerifyFrames(stackTrace, false); + VerifyFrames(stackTrace, false, skipFrames); } [Fact] @@ -99,7 +99,7 @@ public void Ctor_SkipFrames_FNeedFileInfo(int skipFrames, bool fNeedFileInfo) Assert.Equal(emptyStackTrace.FrameCount - skipFrames, stackTrace.FrameCount); Assert.Equal(expectedMethods, stackTrace.GetFrames().Select(f => f.GetMethod())); - VerifyFrames(stackTrace, fNeedFileInfo); + VerifyFrames(stackTrace, fNeedFileInfo, skipFrames); } [Theory] @@ -117,7 +117,7 @@ public void Ctor_LargeSkipFramesFNeedFileInfo_GetFramesReturnsEmpty(bool fNeedFi public void Ctor_ThrownException_GetFramesReturnsExpected() { var stackTrace = new StackTrace(InvokeException()); - VerifyFrames(stackTrace, false); + VerifyFrames(stackTrace, false, 0); } [Fact] @@ -137,7 +137,7 @@ public void Ctor_EmptyException_GetFramesReturnsEmpty() public void Ctor_Bool_ThrownException_GetFramesReturnsExpected(bool fNeedFileInfo) { var stackTrace = new StackTrace(InvokeException(), fNeedFileInfo); - VerifyFrames(stackTrace, fNeedFileInfo); + VerifyFrames(stackTrace, fNeedFileInfo, 0); } [Theory] @@ -171,7 +171,7 @@ public void Ctor_Exception_SkipFrames(int skipFrames) Assert.Equal(expectedMethods, frames.Select(f => f.GetMethod())); if (frames != null) { - VerifyFrames(stackTrace, false); + VerifyFrames(stackTrace, false, skipFrames); } } @@ -211,7 +211,7 @@ public void Ctor_Exception_SkipFrames_FNeedFileInfo(int skipFrames, bool fNeedFi Assert.Equal(expectedMethods, frames.Select(f => f.GetMethod())); if (frames != null) { - VerifyFrames(stackTrace, fNeedFileInfo); + VerifyFrames(stackTrace, fNeedFileInfo, skipFrames); } } @@ -450,7 +450,7 @@ private class ClassWithConstructor public ClassWithConstructor() => StackTrace = new StackTrace(); } - private static void VerifyFrames(StackTrace stackTrace, bool hasFileInfo) + private static void VerifyFrames(StackTrace stackTrace, bool hasFileInfo, int skippedFrames) { Assert.True(stackTrace.FrameCount > 0); @@ -467,7 +467,11 @@ private static void VerifyFrames(StackTrace stackTrace, bool hasFileInfo) Assert.Equal(0, stackFrame.GetFileLineNumber()); Assert.Equal(0, stackFrame.GetFileColumnNumber()); } - Assert.NotNull(stackFrame.GetMethod()); + + // On native AOT, the reflection invoke infrastructure uses compiler-generated code + // that doesn't have a reflection method associated. Limit the checks. + if (!PlatformDetection.IsNativeAot || (i + skippedFrames) == 0) + Assert.NotNull(stackFrame.GetMethod()); } } } diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 654827596930d..8b20609971559 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -518,7 +518,6 @@ -