changeset 51139:c95334202a14

8207342: error occurred during error reporting (printing register info) Summary: os::print_location misses a check if the pointer is readable. Reviewed-by: goetz, coleenp
author mdoerr
date Wed, 18 Jul 2018 11:27:14 +0200
parents 914f305ba6fa
children 1edcf36fe15f
files src/hotspot/os/aix/misc_aix.cpp src/hotspot/os/aix/misc_aix.hpp src/hotspot/os/aix/porting_aix.cpp src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp src/hotspot/share/code/codeHeapState.cpp src/hotspot/share/code/codeHeapState.hpp src/hotspot/share/runtime/os.cpp src/hotspot/share/runtime/os.hpp
diffstat 9 files changed, 70 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/os/aix/misc_aix.cpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/os/aix/misc_aix.cpp	Wed Jul 18 11:27:14 2018 +0200
@@ -49,16 +49,3 @@
   const int rc = pthread_mutex_unlock(cs);
   assert0(rc == 0);
 }
-
-bool MiscUtils::is_readable_pointer(const void* p) {
-  if (!CanUseSafeFetch32()) {
-    return true;
-  }
-  int* const aligned = (int*) align_down(p, 4);
-  int cafebabe = 0xcafebabe;
-  int deadbeef = 0xdeadbeef;
-  return (SafeFetch32(aligned, cafebabe) != cafebabe) ||
-         (SafeFetch32(aligned, deadbeef) != deadbeef);
-}
-
-
--- a/src/hotspot/os/aix/misc_aix.hpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/os/aix/misc_aix.hpp	Wed Jul 18 11:27:14 2018 +0200
@@ -88,13 +88,6 @@
       _pcsobj->leave();
     }
   };
-
-  // Returns true if pointer can be dereferenced without triggering a segment
-  // violation. Returns false if pointer is invalid.
-  // Note: Depends on stub routines; prior to stub routine generation, will
-  // always return true. Use CanUseSafeFetch32 to handle this case.
-  bool is_readable_pointer(const void* p);
-
 }
 
 #endif // OS_AIX_VM_MISC_AIX_HPP
--- a/src/hotspot/os/aix/porting_aix.cpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/os/aix/porting_aix.cpp	Wed Jul 18 11:27:14 2018 +0200
@@ -142,7 +142,7 @@
   // in that case I try reading the traceback table unsafe - I rather risk secondary crashes in
   // error files than not having a callstack.)
 #define CHECK_POINTER_READABLE(p) \
-  if (!MiscUtils::is_readable_pointer(p)) { \
+  if (!os::is_readable_pointer(p)) { \
     trcVerbose("pc not readable"); \
     return false; \
   }
@@ -230,7 +230,7 @@
       const short l = MIN2<short>(*((short*)pc2), namelen - 1);
       // Be very careful.
       int i = 0; char* const p = (char*)pc2 + sizeof(short);
-      while (i < l && MiscUtils::is_readable_pointer(p + i)) {
+      while (i < l && os::is_readable_pointer(p + i)) {
         p_name[i] = p[i];
         i++;
       }
@@ -489,7 +489,7 @@
   const struct tbtable* tb = NULL;
   int displacement = -1;
 
-  if (!MiscUtils::is_readable_pointer(pc)) {
+  if (!os::is_readable_pointer(pc)) {
     st->print("(invalid)");
     return;
   }
@@ -697,7 +697,7 @@
   print_info_for_pc(st, cur_iar, buf, buf_size, demangle);
   st->cr();
 
-  if (cur_iar && MiscUtils::is_readable_pointer(cur_iar)) {
+  if (cur_iar && os::is_readable_pointer(cur_iar)) {
     decode_instructions_at_pc(
       "Decoded instructions at iar:",
       cur_iar, 32, 16, st);
@@ -710,7 +710,7 @@
   print_info_for_pc(st, cur_lr, buf, buf_size, demangle);
   st->cr();
 
-  if (cur_lr && MiscUtils::is_readable_pointer(cur_lr)) {
+  if (cur_lr && os::is_readable_pointer(cur_lr)) {
     decode_instructions_at_pc(
       "Decoded instructions at lr:",
       cur_lr, 32, 16, st);
@@ -729,7 +729,7 @@
   // Check and print rtoc.
   st->print("rtoc: "  PTR64_FORMAT " ", p2i(cur_rtoc));
   if (cur_rtoc == NULL || cur_rtoc == (codeptr_t)-1 ||
-      !MiscUtils::is_readable_pointer(cur_rtoc)) {
+      !os::is_readable_pointer(cur_rtoc)) {
     st->print("(invalid)");
   } else if (((uintptr_t)cur_rtoc) & 0x7) {
     st->print("(unaligned)");
--- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp	Wed Jul 18 11:27:14 2018 +0200
@@ -603,7 +603,9 @@
   st->print_cr("Register to memory mapping:");
   st->cr();
 
-  // this is only for the "general purpose" registers
+  st->print("pc ="); print_location(st, (intptr_t)uc->uc_mcontext.regs->nip);
+  st->print("lr ="); print_location(st, (intptr_t)uc->uc_mcontext.regs->link);
+  st->print("ctr ="); print_location(st, (intptr_t)uc->uc_mcontext.regs->ctr);
   for (int i = 0; i < 32; i++) {
     st->print("r%-2d=", i);
     print_location(st, uc->uc_mcontext.regs->gpr[i]);
--- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp	Wed Jul 18 11:27:14 2018 +0200
@@ -628,7 +628,19 @@
 }
 
 void os::print_register_info(outputStream *st, const void *context) {
-  st->print("Not ported\n");
+  if (context == NULL) return;
+
+  const ucontext_t *uc = (const ucontext_t*)context;
+
+  st->print_cr("Register to memory mapping:");
+  st->cr();
+
+  st->print("pc ="); print_location(st, (intptr_t)uc->uc_mcontext.psw.addr);
+  for (int i = 0; i < 16; i++) {
+    st->print("r%-2d=", i);
+    print_location(st, uc->uc_mcontext.gregs[i]);
+  }
+  st->cr();
 }
 
 #ifndef PRODUCT
--- a/src/hotspot/share/code/codeHeapState.cpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/share/code/codeHeapState.cpp	Wed Jul 18 11:27:14 2018 +0200
@@ -2129,8 +2129,8 @@
       bool blob_initialized = (this_blob != NULL) && (this_blob->header_size() >= 0) && (this_blob->relocation_size() >= 0) &&
                               ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) &&
                               ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) &&
-                              is_readable_pointer((address)(this_blob->relocation_begin())) &&
-                              is_readable_pointer(this_blob->content_begin());
+                              os::is_readable_pointer((address)(this_blob->relocation_begin())) &&
+                              os::is_readable_pointer(this_blob->content_begin());
       // blob could have been flushed, freed, and merged.
       // this_blob < last_blob is an indicator for that.
       if (blob_initialized && (this_blob > last_blob)) {
@@ -2145,7 +2145,7 @@
         }
         // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack
         const char* blob_name = this_blob->name();
-        if ((blob_name == NULL) || !is_readable_pointer(blob_name)) {
+        if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) {
           blob_name = "<unavailable>";
         }
 
@@ -2170,7 +2170,7 @@
         nmethod*    nm     = this_blob->as_nmethod_or_null();
         Method*     method = (nm == NULL) ? NULL : nm->method();  // may be uninitialized, i.e. != NULL, but invalid
         if ((nm != NULL) && (method != NULL) && (cbType != nMethod_dead) && (cbType != nMethod_inconstruction) &&
-            is_readable_pointer(method) && is_readable_pointer(method->constants())) {
+            os::is_readable_pointer(method) && os::is_readable_pointer(method->constants())) {
           ResourceMark rm;
           //---<  collect all data to locals as quickly as possible  >---
           unsigned int total_size = nm->total_size();
@@ -2369,7 +2369,7 @@
 }
 
 CodeHeapState::blobType CodeHeapState::get_cbType(CodeBlob* cb) {
-  if ((cb != NULL) && is_readable_pointer(cb)) {
+  if ((cb != NULL) && os::is_readable_pointer(cb)) {
     if (cb->is_runtime_stub())                return runtimeStub;
     if (cb->is_deoptimization_stub())         return deoptimizationStub;
     if (cb->is_uncommon_trap_stub())          return uncommonTrapStub;
@@ -2392,17 +2392,3 @@
   }
   return noType;
 }
-
-// Check if pointer can be read from (4-byte read access).
-// Helps to prove validity of a not-NULL pointer.
-// Returns true in very early stages of VM life when stub is not yet generated.
-#define SAFEFETCH_DEFAULT true
-bool CodeHeapState::is_readable_pointer(const void* p) {
-  if (!CanUseSafeFetch32()) {
-    return SAFEFETCH_DEFAULT;
-  }
-  int* const aligned = (int*) align_down((intptr_t)p, 4);
-  int cafebabe = 0xcafebabe;  // tester value 1
-  int deadbeef = 0xdeadbeef;  // tester value 2
-  return (SafeFetch32(aligned, cafebabe) != cafebabe) || (SafeFetch32(aligned, deadbeef) != deadbeef);
-}
--- a/src/hotspot/share/code/codeHeapState.hpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/share/code/codeHeapState.hpp	Wed Jul 18 11:27:14 2018 +0200
@@ -95,7 +95,6 @@
   static void print_line_delim(outputStream* out, bufferedStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
   static void print_line_delim(outputStream* out, outputStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
   static blobType get_cbType(CodeBlob* cb);
-  static bool is_readable_pointer(const void* p);
 
  public:
   static void discard(outputStream* out, CodeHeap* heap);
--- a/src/hotspot/share/runtime/os.cpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/share/runtime/os.cpp	Wed Jul 18 11:27:14 2018 +0200
@@ -995,6 +995,22 @@
   st->print_cr(" elapsed time: %d seconds (%dd %dh %dm %ds)", eltime, eldays, elhours, elmins, elsecs);
 }
 
+
+// Check if pointer can be read from (4-byte read access).
+// Helps to prove validity of a not-NULL pointer.
+// Returns true in very early stages of VM life when stub is not yet generated.
+#define SAFEFETCH_DEFAULT true
+bool os::is_readable_pointer(const void* p) {
+  if (!CanUseSafeFetch32()) {
+    return SAFEFETCH_DEFAULT;
+  }
+  int* const aligned = (int*) align_down((intptr_t)p, 4);
+  int cafebabe = 0xcafebabe;  // tester value 1
+  int deadbeef = 0xdeadbeef;  // tester value 2
+  return (SafeFetch32(aligned, cafebabe) != cafebabe) || (SafeFetch32(aligned, deadbeef) != deadbeef);
+}
+
+
 // moved from debug.cpp (used to be find()) but still called from there
 // The verbose parameter is only set by the debug code in one case
 void os::print_location(outputStream* st, intptr_t x, bool verbose) {
@@ -1094,21 +1110,26 @@
       return;
     }
   }
-  if (JNIHandles::is_global_handle((jobject) addr)) {
-    st->print_cr(INTPTR_FORMAT " is a global jni handle", p2i(addr));
-    return;
+
+  bool accessible = is_readable_pointer(addr);
+
+  if (align_down((intptr_t)addr, sizeof(intptr_t)) != 0 && accessible) {
+    if (JNIHandles::is_global_handle((jobject) addr)) {
+      st->print_cr(INTPTR_FORMAT " is a global jni handle", p2i(addr));
+      return;
+    }
+    if (JNIHandles::is_weak_global_handle((jobject) addr)) {
+      st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr));
+      return;
+    }
+#ifndef PRODUCT
+    // we don't keep the block list in product mode
+    if (JNIHandles::is_local_handle((jobject) addr)) {
+      st->print_cr(INTPTR_FORMAT " is a local jni handle", p2i(addr));
+      return;
+    }
+#endif
   }
-  if (JNIHandles::is_weak_global_handle((jobject) addr)) {
-    st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr));
-    return;
-  }
-#ifndef PRODUCT
-  // we don't keep the block list in product mode
-  if (JNIHandles::is_local_handle((jobject) addr)) {
-    st->print_cr(INTPTR_FORMAT " is a local jni handle", p2i(addr));
-    return;
-  }
-#endif
 
   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
     // Check for privilege stack
@@ -1155,6 +1176,11 @@
     return;
   }
 
+  if (accessible) {
+    st->print_cr(INTPTR_FORMAT " points into unknown readable memory", p2i(addr));
+    return;
+  }
+
   st->print_cr(INTPTR_FORMAT " is an unknown value", p2i(addr));
 }
 
--- a/src/hotspot/share/runtime/os.hpp	Tue Jul 17 19:59:38 2018 -0700
+++ b/src/hotspot/share/runtime/os.hpp	Wed Jul 18 11:27:14 2018 +0200
@@ -412,6 +412,9 @@
   static void    make_polling_page_unreadable();
   static void    make_polling_page_readable();
 
+  // Check if pointer points to readable memory (by 4-byte read access)
+  static bool    is_readable_pointer(const void* p);
+
   // Routines used to serialize the thread state without using membars
   static void    serialize_thread_states();