Make use of sigchainlib for signal chaining for implicit checks
This adds a preload library that overrides sigaction and sigprocmask
to implement signal chaining. Signal chaining allows us to chain
any signal so that the ART runtime receives it before any signal
handler registered in native code by an application. If the
ART signal handler doesn't want it, it will pass it on to the
user's handler.
ART uses signals for null pointer checks, stack overflow checks and
suspend points.
Also adds an OAT test to test this in isolation.
Change-Id: I9545f9f7343774c091410eb810504d9855fd399f
diff --git a/runtime/Android.mk b/runtime/Android.mk
index c2507b1..a0648b0 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -402,11 +402,13 @@
endif
endif
LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
+ LOCAL_C_INCLUDES += art/sigchainlib
+
LOCAL_SHARED_LIBRARIES += liblog libnativehelper
include external/libcxx/libcxx.mk
LOCAL_SHARED_LIBRARIES += libbacktrace_libc++
ifeq ($$(art_target_or_host),target)
- LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils
+ LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils libsigchain
LOCAL_STATIC_LIBRARIES := libziparchive libz
else # host
LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
@@ -459,3 +461,4 @@
ifeq ($(ART_BUILD_TARGET_DEBUG),true)
$(eval $(call build-libart,target,debug,$(ART_TARGET_CLANG)))
endif
+
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 8d750c5..15c38c1 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -29,12 +29,22 @@
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "scoped_thread_state_change.h"
+#ifdef HAVE_ANDROID_OS
+#include "sigchain.h"
+#endif
#include "verify_object-inl.h"
namespace art {
// Static fault manger object accessed by signal handler.
FaultManager fault_manager;
+extern "C" {
+void art_sigsegv_fault() {
+ // Set a breakpoint here to be informed when a SIGSEGV is unhandled by ART.
+ VLOG(signals)<< "Caught unknown SIGSEGV in ART fault handler - chaining to next handler.";
+}
+}
+
// Signal handler called on SIGSEGV.
static void art_fault_handler(int sig, siginfo_t* info, void* context) {
fault_manager.HandleFault(sig, info, context);
@@ -45,9 +55,13 @@
}
FaultManager::~FaultManager() {
+#ifdef HAVE_ANDROID_OS
+ UnclaimSignalChain(SIGSEGV);
+#endif
sigaction(SIGSEGV, &oldaction_, nullptr); // Restore old handler.
}
+
void FaultManager::Init() {
struct sigaction action;
action.sa_sigaction = art_fault_handler;
@@ -56,7 +70,13 @@
#if !defined(__mips__)
action.sa_restorer = nullptr;
#endif
+
+ // Set our signal handler now.
sigaction(SIGSEGV, &action, &oldaction_);
+#ifdef HAVE_ANDROID_OS
+ // Make sure our signal handler is called before any user handlers.
+ ClaimSignalChain(SIGSEGV, &oldaction_);
+#endif
}
void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
@@ -79,8 +99,13 @@
return;
}
}
- VLOG(signals)<< "Caught unknown SIGSEGV in ART fault handler";
+ art_sigsegv_fault();
+
+#ifdef HAVE_ANDROID_OS
+ InvokeUserSignalHandler(sig, info, context);
+#else
oldaction_.sa_sigaction(sig, info, context);
+#endif
}
void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 23a49cb..361070c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -562,9 +562,20 @@
GetInstrumentation()->ForceInterpretOnly();
}
- if (options->explicit_checks_ != (ParsedOptions::kExplicitSuspendCheck |
- ParsedOptions::kExplicitNullCheck |
- ParsedOptions::kExplicitStackOverflowCheck) || kEnableJavaStackTraceHandler) {
+ bool implicit_checks_supported = false;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ implicit_checks_supported = true;
+ break;
+ default:
+ break;
+ }
+
+ if (implicit_checks_supported &&
+ (options->explicit_checks_ != (ParsedOptions::kExplicitSuspendCheck |
+ ParsedOptions::kExplicitNullCheck |
+ ParsedOptions::kExplicitStackOverflowCheck) || kEnableJavaStackTraceHandler)) {
fault_manager.Init();
// These need to be in a specific order. The null point check handler must be
diff --git a/runtime/thread.h b/runtime/thread.h
index 9a7cb48..08bbcae 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -121,7 +121,7 @@
// of the stack (lowest memory). The higher portion of the memory
// is protected against reads and the lower is available for use while
// throwing the StackOverflow exception.
- static constexpr size_t kStackOverflowProtectedSize = 32 * KB;
+ static constexpr size_t kStackOverflowProtectedSize = 16 * KB;
static constexpr size_t kStackOverflowImplicitCheckSize = kStackOverflowProtectedSize +
kStackOverflowReservedBytes;