From 550e7b84723c7a3fabfd66c2a58274bac2884b48 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 13 May 2026 11:12:13 -0500 Subject: [PATCH 1/2] Add NativeCrashProducesManagedStackTrace device test Adds an MSBuildDeviceIntegration test that verifies the System.Runtime.CrashReportBeforeSignalChaining config option works end-to-end on CoreCLR. The test builds a Release app that triggers a native SIGSEGV via P/Invoke to libc memset(NULL), then checks logcat for the managed stack trace logged by the DOTNET tag before Android's signal handler takes over. See: https://github.com/dotnet/android/pull/11291 See: https://github.com/dotnet/runtime/pull/123735 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tests/InstallAndRunTests.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 7f88cfe0caf..56d605822e9 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -775,6 +775,65 @@ public void UnhandledExceptionFromButtonClick ([Values (AndroidRuntime.MonoVM, A $"Output did not contain {expectedRaiser}!"); } + [Test] + public void NativeCrashProducesManagedStackTrace ([Values (AndroidRuntime.CoreCLR)] AndroidRuntime runtime) + { + // This test verifies that when a native crash (SIGSEGV) occurs, the .NET runtime + // logs a managed stack trace in logcat BEFORE Android's signal handler takes over. + // This is enabled by the System.Runtime.CrashReportBeforeSignalChaining config option. + // See: https://github.com/dotnet/android/pull/11291 + // See: https://github.com/dotnet/runtime/pull/123735 + const bool isRelease = true; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { + return; + } + + proj = new XamarinAndroidApplicationProject (packageName: PackageUtils.MakePackageName (runtime)) { + IsRelease = isRelease, + }; + proj.SetRuntime (runtime); + proj.SetProperty ("AllowUnsafeBlocks", "true"); + proj.SetAndroidSupportedAbis (DeviceAbi); + + proj.MainActivity = proj.DefaultMainActivity + .Replace ("//${USINGS}", "using System.Runtime.InteropServices;") + .Replace ("//${AFTER_ONCREATE}", """ + // Force a native crash (SIGSEGV) via P/Invoke to libc memset with a null pointer. + // The .NET runtime's crash reporting should log the managed stack trace before + // Android's signal handler aborts the process. + CrashHelper.ForceNativeSegfault (); + """) + .Replace ("//${AFTER_MAINACTIVITY}", """ + static class CrashHelper + { + [DllImport ("libc", EntryPoint = "memset")] + static extern unsafe void MemSet (void* ptr, int value, nuint count); + + public static unsafe void ForceNativeSegfault () + { + MemSet (null, 0, (nuint)1); + } + } + """); + + builder = CreateApkBuilder (); + Assert.IsTrue (builder.Install (proj), "Install should have succeeded."); + ClearAdbLogcat (); + AdbStartActivity ($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); + + // CoreCLR logs the managed stack trace via the DOTNET logcat tag when crash reporting + // runs before signal chaining. The stack trace JSON includes method names like + // "ForceNativeSegfault" from the managed frames leading up to the crash. + string logcatFile = Path.Combine (Root, builder.ProjectDirectory, "crash-logcat.log"); + Assert.IsTrue ( + MonitorAdbLogcat ( + (line) => line.Contains ("DOTNET") && line.Contains ("ForceNativeSegfault"), + logcatFilePath: logcatFile, + timeout: 30), + "Crash reporting should have logged a managed stack trace containing 'ForceNativeSegfault' via the DOTNET logcat tag. " + + "Verify the System.Runtime.CrashReportBeforeSignalChaining config option is set and the runtime supports it."); + } + [Test] [Category ("UsesDevice")] [TestCaseSource (nameof (Get_SmokeTestBuildAndRunWithSpecialCharacters_Data))] From 5a95eba5f8fee1a6b03520f8a9990628c4f27015 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 14 May 2026 08:45:56 -0500 Subject: [PATCH 2/2] Assert SIGSEGV signal and add runtime PR reference - Assert that logcat contains both SIGSEGV signal and ForceNativeSegfault managed frame from the DOTNET tag - Add reference to dotnet/runtime#123824 which implements the managed callstack logging Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tests/InstallAndRunTests.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 56d605822e9..ecec32bfab0 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -783,6 +783,7 @@ public void NativeCrashProducesManagedStackTrace ([Values (AndroidRuntime.CoreCL // This is enabled by the System.Runtime.CrashReportBeforeSignalChaining config option. // See: https://github.com/dotnet/android/pull/11291 // See: https://github.com/dotnet/runtime/pull/123735 + // See: https://github.com/dotnet/runtime/pull/123824 const bool isRelease = true; if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { return; @@ -822,15 +823,26 @@ public static unsafe void ForceNativeSegfault () AdbStartActivity ($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); // CoreCLR logs the managed stack trace via the DOTNET logcat tag when crash reporting - // runs before signal chaining. The stack trace JSON includes method names like - // "ForceNativeSegfault" from the managed frames leading up to the crash. + // runs before signal chaining. The output includes: + // E DOTNET : Got a SIGSEGV while executing native code. ... + // E DOTNET : at .CrashHelper.ForceNativeSegfault() string logcatFile = Path.Combine (Root, builder.ProjectDirectory, "crash-logcat.log"); + bool foundSigsegv = false; + bool foundManagedFrame = false; Assert.IsTrue ( MonitorAdbLogcat ( - (line) => line.Contains ("DOTNET") && line.Contains ("ForceNativeSegfault"), + (line) => { + if (line.Contains ("DOTNET") && line.Contains ("SIGSEGV")) { + foundSigsegv = true; + } + if (line.Contains ("DOTNET") && line.Contains ("ForceNativeSegfault")) { + foundManagedFrame = true; + } + return foundSigsegv && foundManagedFrame; + }, logcatFilePath: logcatFile, timeout: 30), - "Crash reporting should have logged a managed stack trace containing 'ForceNativeSegfault' via the DOTNET logcat tag. " + + "Crash reporting should have logged 'SIGSEGV' and a managed stack trace containing 'ForceNativeSegfault' via the DOTNET logcat tag. " + "Verify the System.Runtime.CrashReportBeforeSignalChaining config option is set and the runtime supports it."); }