Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,77 @@ 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
Comment thread
mdh1418 marked this conversation as resolved.
// See: https://github.com/dotnet/runtime/pull/123824
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");

Comment thread
jonathanpeppers marked this conversation as resolved.
// CoreCLR logs the managed stack trace via the DOTNET logcat tag when crash reporting
// runs before signal chaining. The output includes:
// E DOTNET : Got a SIGSEGV while executing native code. ...
// E DOTNET : at <namespace>.CrashHelper.ForceNativeSegfault()
string logcatFile = Path.Combine (Root, builder.ProjectDirectory, "crash-logcat.log");
bool foundSigsegv = false;
bool foundManagedFrame = false;
Assert.IsTrue (
MonitorAdbLogcat (
(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),
Comment thread
jonathanpeppers marked this conversation as resolved.
"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.");
Comment on lines +825 to +846
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test passed:

Image

@mdh1418 is there anything else here we should be asserting?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I suppose if there's anything else that is critical for diagnosing how the crash occurred? I suppose you could check for native crashes what the signal was. See the Sigsegv example in dotnet/runtime#123824.

That said, CrashReportBeforeSignalChaining was merged (2/13) before managed callstacks logging was merged (2/18), so as long as this test doesn't run on a version of the runtime that is between those two it should work.

For what it's worth, this config option also guards the inproc crash reporter's json file added by dotnet/runtime#126916, which is in progress to be added to logcat in dotnet/runtime#128105

}

[Test]
[Category ("UsesDevice")]
[TestCaseSource (nameof (Get_SmokeTestBuildAndRunWithSpecialCharacters_Data))]
Expand Down