Invoke all other registered handlers only for generated code
To get more information for unhandled signals, the nested handler
might be registered to kernel. This will expose an issue in some
scenarios, for example mulit-thread case, because the art default
handler will be replaced in kernel. To solve it, other handlers are
only invoked for generated code.
Change-Id: Ifa9cf4dfdd6a0ef18f88c2e2313b545d26ed826d
Signed-off-by: jgu21 <jinghui.gu@intel.com>
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 52ccbee..5345b89 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -146,43 +146,13 @@
}
}
-void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
- // BE CAREFUL ALLOCATING HERE INCLUDING USING LOG(...)
- //
- // If malloc calls abort, it will be holding its lock.
- // If the handler tries to call malloc, it will deadlock.
- VLOG(signals) << "Handling fault";
- if (IsInGeneratedCode(info, context, true)) {
- VLOG(signals) << "in generated code, looking for handler";
- for (const auto& handler : generated_code_handlers_) {
- VLOG(signals) << "invoking Action on handler " << handler;
- if (handler->Action(sig, info, context)) {
-#ifdef TEST_NESTED_SIGNAL
- // In test mode we want to fall through to stack trace handler
- // on every signal (in reality this will cause a crash on the first
- // signal).
- break;
-#else
- // We have handled a signal so it's time to return from the
- // signal handler to the appropriate place.
- return;
-#endif
- }
- }
- }
-
- // We hit a signal we didn't handle. This might be something for which
- // we can give more information about so call all registered handlers to see
- // if it is.
-
+bool FaultManager::HandleFaultByOtherHandlers(int sig, siginfo_t* info, void* context) {
Thread* self = Thread::Current();
- // If ART is not running, or the thread is not attached to ART pass the
- // signal on to the next handler in the chain.
- if (self == nullptr || Runtime::Current() == nullptr || !Runtime::Current()->IsStarted()) {
- InvokeUserSignalHandler(sig, info, context);
- return;
- }
+ DCHECK(self != nullptr);
+ DCHECK(Runtime::Current() != nullptr);
+ DCHECK(Runtime::Current()->IsStarted());
+
// Now set up the nested signal handler.
// TODO: add SIGSEGV back to the nested signals when we can handle running out stack gracefully.
@@ -231,6 +201,7 @@
break;
}
}
+
if (success) {
// Save the current state and call the handlers. If anything causes a signal
// our nested signal handler will be invoked and this will longjmp to the saved
@@ -247,7 +218,7 @@
}
}
fault_manager.Init();
- return;
+ return true;
}
}
} else {
@@ -265,6 +236,40 @@
// Now put the fault manager back in place.
fault_manager.Init();
+ return false;
+}
+
+void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
+ // BE CAREFUL ALLOCATING HERE INCLUDING USING LOG(...)
+ //
+ // If malloc calls abort, it will be holding its lock.
+ // If the handler tries to call malloc, it will deadlock.
+ VLOG(signals) << "Handling fault";
+ if (IsInGeneratedCode(info, context, true)) {
+ VLOG(signals) << "in generated code, looking for handler";
+ for (const auto& handler : generated_code_handlers_) {
+ VLOG(signals) << "invoking Action on handler " << handler;
+ if (handler->Action(sig, info, context)) {
+#ifdef TEST_NESTED_SIGNAL
+ // In test mode we want to fall through to stack trace handler
+ // on every signal (in reality this will cause a crash on the first
+ // signal).
+ break;
+#else
+ // We have handled a signal so it's time to return from the
+ // signal handler to the appropriate place.
+ return;
+#endif
+ }
+ }
+
+ // We hit a signal we didn't handle. This might be something for which
+ // we can give more information about so call all registered handlers to see
+ // if it is.
+ if (HandleFaultByOtherHandlers(sig, info, context)) {
+ return;
+ }
+ }
// Set a breakpoint in this function to catch unhandled signals.
art_sigsegv_fault();
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index 3b03a14..625b1e8 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -62,6 +62,10 @@
NO_THREAD_SAFETY_ANALYSIS;
private:
+ // The HandleFaultByOtherHandlers function is only called by HandleFault function for generated code.
+ bool HandleFaultByOtherHandlers(int sig, siginfo_t* info, void* context)
+ NO_THREAD_SAFETY_ANALYSIS;
+
std::vector<FaultHandler*> generated_code_handlers_;
std::vector<FaultHandler*> other_handlers_;
struct sigaction oldaction_;