-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[mono] Chain SIGSEGV
native crashes to the default SIGSEGV
handler
#110741
base: main
Are you sure you want to change the base?
[mono] Chain SIGSEGV
native crashes to the default SIGSEGV
handler
#110741
Conversation
I'm a little curious if this works on Android or if we have the same issue there? As you said, this is really old code and nothing changed in the runtime around this for a long time, so a little curious how long this has been an issue. Did you end up without a chained signal handler on iOS? If that is the case, we hit this condition:
Meaning we won't add anything to chain, that would lead to returning back from signal handler re-executing the faulting instruction, |
An alternative could be to add an internal chained function in runtime in case you end up with default SIGSEGV handler, that function could restore the default handler and re-raise the signal. That will make sure we get the default handler executed and it won't change the current logic. The default handler should never return, so you could probably end that function with g_assert_not_reached. |
Will run some manual tests.
Yes, on iOS chaining has no effect, since we only have the default handler active at the point of registering our handlers.
You mean instead of calling struct sigaction sa;
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGSEGV, &sa, NULL);
raise (SIGSEGV); and call it instead of |
either like that or you could store the struct from original signal handler when installing it and then when restored the exact same struct back to make sure you get all flags restored, like what's done in remove_signal_handler, but I don't think we should remove anything from the table (its not locked), but you could get the old struct back and restore that since it should be the SIG_DFL. |
de59b5b
to
1cfbbca
Compare
On Android, during registration of Mono signal handlers we get:
which means that original handlers on Android don't have |
SIGSEGV
crash when chaining fails on iOS-like platformsSIGSEGV
native crashes to default handler on iOS-like platforms
SIGSEGV
native crashes to default handler on iOS-like platformsSIGSEGV
native crashes to the default SIGSEGV
handler
LGTM! |
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
Description
The problem
When
SIGSEGV
gets raised from native code Mono does not create crash reports on iOS-like platforms.Instead our handler dumps native/managed stack traces and returns from the handler normally at:
runtime/src/mono/mono/mini/mini-runtime.c
Lines 3908 to 3912 in c969265
If it returns normally the code continues at the point the signal occurred, reexecuting the same instruction raising the signal again. This resulted in "double faults" in mono runtime, which we handled in such way that we exit from double faulting with
exit(-1)
:runtime/src/mono/mono/mini/mini-posix.c
Lines 787 to 792 in c969265
preventing any crash log of being created.
This is true even in .NET 7, stack trace of an app that crashes, but does not generate any crash report (full crash report: https://gist.github.com/ivanpovazan/798e5185f13dada2d80e9b023b179a18) :
Crash chaining
On mobile we enable crash chaining
mono_do_crash_chaining=true
and signal chainingmono_do_signal_chaining=true
:https://github.com/xamarin/xamarin-macios/blob/27e1882103ef4bc1c8db16c18533039ecc03ee3e/runtime/monovm-bridge.m#L83-L84
which means that after handling the native crash we chain the signal to any previous handlers defined for the signal. However, during registration of mono signal handlers, the default handler is being ignored:
runtime/src/mono/mono/mini/mini-posix.c
Lines 349 to 356 in c969265
For this reason there is no effect when
mono_chain_signal
is called in the basic setup (no user-defined handler).The fix
In this PR we are changing the logic of preserving original handlers by considering the default SIGSEGV handlers - when
sa.sa_handler == SIG_DFL
for signal chaining as well.When the SIGSEGV native crash occurs and after we finish with our handler, we first try to chain the signal to any saved non-default handler -
sa.sa_handler != SIG_DFL
, if that fails, then we try chaining to the default one -sa.sa_handler == SIG_DFL
. This way we avoid double faulting and properly propagate the SIGSEGV to the OS handler.Test
Tested on MAUI iOS and MacCatalyst apps where now crash reports are properly generated.
Android behaviour is left unchanged.
Fixes: #106064