Add more checks in FaultHandler.
Make the code more robust when thinking it is dealing with an implicit
null check.
Test: test.py
Bug: 170587281
Change-Id: I5e1177377fb2dcee687a9f84693831f7d2de4b67
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 8b748d2..2f8085c 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -569,8 +569,7 @@
}
}
- if (OatQuickMethodHeader::NterpMethodHeader != nullptr &&
- OatQuickMethodHeader::NterpMethodHeader->Contains(pc)) {
+ if (OatQuickMethodHeader::IsNterpPc(pc)) {
return OatQuickMethodHeader::NterpMethodHeader;
}
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index bc6acec..66fb3c7 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -25,8 +25,11 @@
#include "base/safe_copy.h"
#include "base/stl_util.h"
#include "dex/dex_file_types.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "mirror/class.h"
#include "mirror/object_reference.h"
+#include "oat_file.h"
#include "oat_quick_method_header.h"
#include "sigchain.h"
#include "thread-current-inl.h"
@@ -265,6 +268,34 @@
LOG(FATAL) << "Attempted to remove non existent handler " << handler;
}
+static bool IsKnownPc(uintptr_t pc, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Check whether the pc is within nterp range.
+ if (OatQuickMethodHeader::IsNterpPc(pc)) {
+ return true;
+ }
+
+ // Check whether the pc is in the JIT code cache.
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ if (jit != nullptr && jit->GetCodeCache()->ContainsPc(reinterpret_cast<const void*>(pc))) {
+ return true;
+ }
+
+ if (method->IsObsolete()) {
+ // Obsolete methods never happen on AOT code.
+ return false;
+ }
+
+ // Note: at this point, we trust it's truly an ArtMethod we found at the bottom of the stack,
+ // and we can find its oat file through it.
+ const OatDexFile* oat_dex_file = method->GetDeclaringClass()->GetDexFile().GetOatDexFile();
+ if (oat_dex_file != nullptr &&
+ oat_dex_file->GetOatFile()->Contains(reinterpret_cast<const void*>(pc))) {
+ return true;
+ }
+
+ return false;
+}
+
// This function is called within the signal handler. It checks that
// the mutator_lock is held (shared). No annotalysis is done.
bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool check_dex_pc) {
@@ -329,6 +360,11 @@
return false;
}
+ if (!IsKnownPc(return_pc, method_obj)) {
+ VLOG(signals) << "PC not in Java code";
+ return false;
+ }
+
const OatQuickMethodHeader* method_header = method_obj->GetOatQuickMethodHeader(return_pc);
if (method_header == nullptr) {
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
index a725724..e347588 100644
--- a/runtime/oat_quick_method_header.h
+++ b/runtime/oat_quick_method_header.h
@@ -39,6 +39,11 @@
bool IsNterpMethodHeader() const;
+ static bool IsNterpPc(uintptr_t pc) {
+ return OatQuickMethodHeader::NterpMethodHeader != nullptr &&
+ OatQuickMethodHeader::NterpMethodHeader->Contains(pc);
+ }
+
static OatQuickMethodHeader* FromCodePointer(const void* code_ptr) {
uintptr_t code = reinterpret_cast<uintptr_t>(code_ptr);
uintptr_t header = code - OFFSETOF_MEMBER(OatQuickMethodHeader, code_);