Skip to content

[mono][ios] Mono prevents crash logs from being generated in case SIGSEGV is raised from native code #106064

Closed
@ivanpovazan

Description

@ivanpovazan

Description

While investigating the behavior of the crash reported in: #105245 on iOS device we noticed that such error does not:

  1. Produce any useful information in the Console.app
  2. It did not generate a crash report on a device

Repro

  1. Install official .NET 9 preview 6 release
  2. Install MAUI workloads
  3. Create a MAUI template app
  4. Build/run it on a physical device in Debug mode:
dotnet build -f net9.0-ios -r ios-arm64 -t:Run -p:_DeviceName=XXXXXX
  1. Console.app shows only that the program exited:
default  14:14:51.131793+0200  SpringBoard  [app<com.companyname.myapp(80F7F2DD-E9BB-43D8-AB25-7A0DE1A64558)>:6714] Process exited: <RBSProcessExitContext| voluntary>.
  1. No crash logs are generated on a device

Investigation

As initially assumed, the crash was not caused by asserting from the runtime (where we abort() properly), but instead the code was trying to read from an invalid memory address (something like 0xa8) so SIGSEGV was raised.
The mono's signal handler catches this, but does not remove it self as a SIGSEGV handler when it starts handling the signal.
After the handling is done, the handler returns, but the same signal is caught again and on second handling the program exits out with -1 in case of double faulting:

} else {
g_async_safe_printf ("\nAn error has occurred in the native fault reporting. Some diagnostic information will be unavailable.\n");
g_async_safe_printf ("\nExiting early due to double fault.\n");
_exit (-1);

This causes the app to silently exit not including any information about the crash.
Additionally, the messages from the signal handler (like information about the native and managed stack traces) that are using g_async_safe_printf are not shown in the system log.

FWIW In the signal handler we do unregister the runtime for some signals, but not for SIGSEGV:

g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
/* On some systems we get a SIGILL when calling abort (), because it might
* fail to raise SIGABRT */
g_assert (sigaction (SIGILL, &sa, NULL) != -1);
/* Remove SIGCHLD, it uses the finalizer thread */
g_assert (sigaction (SIGCHLD, &sa, NULL) != -1);
/* Remove SIGQUIT, we are already dumping threads */
g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);

Proposal

  1. Investigate if we can unregister the SIGSEGV handler if we've detected that the signal it's not coming from managed code (to distinguish NullReferenceException)
  2. Try using a platform specific logging mechanism so that messages from the signal handler end up in the system log when a fatal error occurs

PS Thanks @lambdageek for assistance

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-Diagnostics-monoin-prThere is an active PR which will close this issue when it is mergedos-iosApple iOS

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions