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_);