Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[.NET 6/7] An alternative to Mono.Runtime.RemoveSignalHandlers/InstallSignalHandlers in .NET 6/7? #79706

Open
akravch opened this issue Dec 15, 2022 · 14 comments

Comments

@akravch
Copy link

akravch commented Dec 15, 2022

TLDR

Is there any API in Android/iOS .NET 6/7 apps to replace Mono.Runtime.RemoveSignalHandlers/InstallSignalHandlers which are unavailable now?

Motivation

We have Xamarin.Android and Xamarin.iOS apps that can catch and report native crashes by installing their own signal handlers like this:

Mono.Runtime.RemoveSignalHandlers();

try
{
    NativeCrashListener.Initialize();
}
finally
{
    Mono.Runtime.InstallSignalHandlers();
}

Migrating from Xamarin to .NET 6 I noticed that the Mono.Runtime type is not accessible any more, even though the Mono runtime is still there for Android and iOS, so obviously, you can't remove and install the handlers like this.

Mono suggests the following alternative:

IntPtr sigbus = Marshal.AllocHGlobal (512);
IntPtr sigsegv = Marshal.AllocHGlobal (512);

// Store Mono's SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, IntPtr.Zero, sigbus);
sigaction (Signal.SIGSEGV, IntPtr.Zero, sigsegv);

// Enable crash reporting libraries
EnableCrashReporting ();

// Restore Mono SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, sigbus, IntPtr.Zero);
sigaction (Signal.SIGSEGV, sigsegv, IntPtr.Zero);

Marshal.FreeHGlobal (sigbus);
Marshal.FreeHGlobal (sigsegv);

We tried both the way Mono recommends and getting rid of the remove/install code at all on our Xamarin apps to see if it makes a difference. Turns out that it does, and the number of crashes that we get significantly differs in both cases. It is hard to say which way is more correct though, since you can only see the difference on big numbers, but in any case the behavior is not the same.

I would still want to apply something similar to the .NET 6 apps, and I wonder whether there is an alternative API I didn't find. I know that there is some API to work with POSIX signals now in .NET 6, so maybe I'm just missing something.

So is there a way to achieve something like that in .NET 6+ apps or any plans to add a new API to support this?

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Dec 15, 2022
@ghost
Copy link

ghost commented Dec 15, 2022

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Issue Details

TLDR

Is there any API in Android/iOS .NET 6/7 apps to replace Mono.Runtime.RemoveSignalHandlers/InstallSignalHandlers which are unavailable now?

Motivation

We have Xamarin.Android and Xamarin.iOS apps that can catch and report native crashes by installing their own signal handlers like this:

Mono.Runtime.RemoveSignalHandlers();

try
{
    NativeCrashListener.Initialize();
}
finally
{
    Mono.Runtime.InstallSignalHandlers();
}

Migrating from Xamarin to .NET 6 I noticed that the Mono.Runtime type is not accessible any more, even though the Mono runtime is still there for Android and iOS, so obviously, you can't remove and install the handlers like this.

Mono suggests the following alternative:

IntPtr sigbus = Marshal.AllocHGlobal (512);
IntPtr sigsegv = Marshal.AllocHGlobal (512);

// Store Mono's SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, IntPtr.Zero, sigbus);
sigaction (Signal.SIGSEGV, IntPtr.Zero, sigsegv);

// Enable crash reporting libraries
EnableCrashReporting ();

// Restore Mono SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, sigbus, IntPtr.Zero);
sigaction (Signal.SIGSEGV, sigsegv, IntPtr.Zero);

Marshal.FreeHGlobal (sigbus);
Marshal.FreeHGlobal (sigsegv);

We tried both the way Mono recommends and getting rid of the remove/install code at all on our Xamarin apps to see if it makes a difference. Turns out that it does, and the number of crashes that we get significantly differs in both cases. It is hard to say which way is more correct though, since you can only see the difference on big numbers, but in any case the behavior is not the same.

I would still want to apply something similar to the .NET 6 apps, and I wonder whether there is an alternative API I didn't find. I know that there is some API to work with POSIX signals now in .NET 6, so maybe I'm just missing something.

So is there a way to achieve something like that in .NET 6+ apps or any plans to add a new API to support this?

Author: akravch
Assignees: -
Labels:

area-System.Runtime.InteropServices

Milestone: -

@lambdageek
Copy link
Member

cc @rolfbjarne @jonpryor @jonathanpeppers do we have any guidance for .NET 6/7 customers who want to use a third party crash reporting library on mobile?

We don't seem to support PosixSignalRegistration on mobile (it throws PNSE) but maybe we should? Although it wouldn't solve the issue with null reference exceptions.

The problem that Mono.Runtime.RemoveSignalHandlers/Mono.Runtime.InstallSignalHandlers were meant to solve is that normally we want the runtime to handle SIGBUS/SIGSEGV first (to handle null managed pointer derefs and convert them to NullReferenceExceptions). Mono's normal signal handler first checks the faulting page and if it is in the managed heap it will create the NRE otherwise it will chain to the signal handler that was registered at runtime startup (normally the system default handler, but in embedders it could be something else).

In order to install a custom crash handler, however, the user code would want to insert itself after mono's default handler. (ie: PosixSignalRegistration.Create (SIGSEGV, ...) would create a chain like this: UserHandler -> MonoHandler -> SystemDefault, but we would like this: MonoHandler -> UserHandler -> SystemDefault). I don't see a way to achieve that with PosixSignalRegistration.

@lambdageek lambdageek added os-android os-ios Apple iOS and removed untriaged New issue has not been triaged by the area owner labels Jan 6, 2023
@ghost
Copy link

ghost commented Jan 6, 2023

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

Issue Details

TLDR

Is there any API in Android/iOS .NET 6/7 apps to replace Mono.Runtime.RemoveSignalHandlers/InstallSignalHandlers which are unavailable now?

Motivation

We have Xamarin.Android and Xamarin.iOS apps that can catch and report native crashes by installing their own signal handlers like this:

Mono.Runtime.RemoveSignalHandlers();

try
{
    NativeCrashListener.Initialize();
}
finally
{
    Mono.Runtime.InstallSignalHandlers();
}

Migrating from Xamarin to .NET 6 I noticed that the Mono.Runtime type is not accessible any more, even though the Mono runtime is still there for Android and iOS, so obviously, you can't remove and install the handlers like this.

Mono suggests the following alternative:

IntPtr sigbus = Marshal.AllocHGlobal (512);
IntPtr sigsegv = Marshal.AllocHGlobal (512);

// Store Mono's SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, IntPtr.Zero, sigbus);
sigaction (Signal.SIGSEGV, IntPtr.Zero, sigsegv);

// Enable crash reporting libraries
EnableCrashReporting ();

// Restore Mono SIGSEGV and SIGBUS handlers
sigaction (Signal.SIGBUS, sigbus, IntPtr.Zero);
sigaction (Signal.SIGSEGV, sigsegv, IntPtr.Zero);

Marshal.FreeHGlobal (sigbus);
Marshal.FreeHGlobal (sigsegv);

We tried both the way Mono recommends and getting rid of the remove/install code at all on our Xamarin apps to see if it makes a difference. Turns out that it does, and the number of crashes that we get significantly differs in both cases. It is hard to say which way is more correct though, since you can only see the difference on big numbers, but in any case the behavior is not the same.

I would still want to apply something similar to the .NET 6 apps, and I wonder whether there is an alternative API I didn't find. I know that there is some API to work with POSIX signals now in .NET 6, so maybe I'm just missing something.

So is there a way to achieve something like that in .NET 6+ apps or any plans to add a new API to support this?

Author: akravch
Assignees: -
Labels:

os-android, os-ios, area-Interop-mono

Milestone: -

@jonathanpeppers
Copy link
Member

What would a coreclr console app do on Linux, for example? AppDomain.CurrentDomain.UnhandledException is for managed-land, is there an equivalent for native crashes?

@jkotas
Copy link
Member

jkotas commented Jan 7, 2023

What would a coreclr console app do on Linux, for example?

Preload the native crash reporting library using LD_PRELOAD.

@rolfbjarne
Copy link
Member

What would a coreclr console app do on Linux, for example?

Preload the native crash reporting library using LD_PRELOAD.

That's not an option on iOS :/

A library initializer in a static library might work:

void initialize_crash_reporting () __attribute__ ((constructor));
void initialize_crash_reporting ()
{
    // initialize...
}

which is a rather steep hill for app developers (since they'd likely be the ones who'd have to write and build the initializing static library to use the actual crash reporting library).

In order to install a custom crash handler, however, the user code would want to insert itself after mono's default handler. (ie: PosixSignalRegistration.Create (SIGSEGV, ...) would create a chain like this: UserHandler -> MonoHandler -> SystemDefault, but we would like this: MonoHandler -> UserHandler -> SystemDefault). I don't see a way to achieve that with PosixSignalRegistration.

Another point is that PosixSignalRegistration only seems to allow managed callbacks. Executing managed code in a signal that causes a crash is not really a good idea at all.

@akravch
Copy link
Author

akravch commented Jan 12, 2023

A library initializer in a static library might work

But can we actually use static libraries in .NET for Android? I believe that was not possible with Xamarin.Android unless it's wrapped into a dynamic library, and loading a dynamic library still happens after Mono signal handlers are installed.

@steveisok steveisok added this to the Future milestone Jan 24, 2023
@akravch
Copy link
Author

akravch commented May 17, 2023

Are there any updates or ideas on this topic? It is still very relevant for me and I wouldn't even mind an ugliest workaround if it existed.

@karpikpl
Copy link

karpikpl commented Jun 8, 2023

Is there a plan to include this in .Net 7/8 ?

What are alternatives for handling process crashes in native code in .NET? If EnableCrashReporting(); is not an option, is there a way to monitor the .Net process in some other way, produce dumps and report them?

@jkotas
Copy link
Member

jkotas commented Jun 9, 2023

This is open design discussion with milestone set to Future. There is no agreed upon plan for how to resolve this issue.

InstallSignalHandlers/RemoveSignalHandlers APIs are difficult to implement 100% reliably and they come with portability issues. I do not think they would be a good addition to the platform.

If the goal is to allow installation of the custom signal handlers before the runtime ones, writing a custom runtime host and registering the signals before the runtime starts is the way to go. This tutorial works for Windows/Linux/macOS apps that typically run on CoreCLR runtime. We do not have a tutorial like this for mobile apps (they use custom hosting) so that would be the piece to fill in.

If the goal is to get good actionable crash dumps, CoreCLR runtime comes with crash dump capabilities: https://learn.microsoft.com/dotnet/core/diagnostics/collect-dumps-crash . The built-in crash dump collector is better than the generic crash dump collectors since it understands the structure of the .NET runtime and the piece that must be saved into the crashdump. We can keep evolving this solution to meet the needs.

If the goal is to allow interception of fatal process crashes, we can consider introducing an API for it. The API would allow registering unmanaged callback. The callback would have to be implemented with signal handler style restrictions in unmanaged code. This callback would be issued for any fatal crashes that are intercepted by the .NET runtime. In addition to fatal signals, this callback would be also issued for Environment.FailFast and other similar situations where the runtime terminates process without giving anybody chance to intercept it today.

@akravch
Copy link
Author

akravch commented Aug 30, 2023

Since custom hosting and dump collection are not options for Android/iOS applications, I would love to see the signal handling API implemented.
I will wait for any updates on the topic. Thank you very much!

@jkotas
Copy link
Member

jkotas commented Aug 31, 2023

I assume that you are interested in 3rd point (allow interception of fatal process crashes). The managed APIs for that can look like this:

This is what the APIs can look like:

// Returns a pointer to a function that can be used to check whether given instruction pointer is managed code.
// The function is safe to call in signal handlers. The 3rd party crash handlers can use this function to check
// whether the .NET runtime is going to handle signal at this instruction pointer.
public static delegate* unmanaged<IntPtr, int> GetIsManagedCode();

// .NET runtime is going to call `fatalErrorHandler` set by this method before its own
// fatal error handling (creating .NET runtime-specific crash dump, etc.). This can be only called once in given
// process. 
// TODO: What should be the signature of the `fatalErrorHandler`?
public static void SetFatalErrorHandler(IntPtr fatalErrorHandler);

Would that work for you?

@rolfbjarne
Copy link
Member

The main scenario here is to use third-party crash reporters.

Then one important question comes up: do we want a solution that would require modifications to any third-party crash reporters that might want to support .NET apps, or do we want a solution that would work with any third-party crash reporters as-is?

The former Mono API (RemoveSignalHandlers/InstallSignalHandlers) is in the latter category, it just required a few lines of code by the app developer.

If we want to go with the former category, the API needs to be designed together with those third-party crash reporter vendors. It doesn't make much sense to design and implement an API that's hard/impossible for them to use.

@jkotas
Copy link
Member

jkotas commented May 28, 2024

API proposal for customization of fatal error handling: #101560

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

7 participants