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
--- 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;
- }
- if (JNIHandles::is_weak_global_handle((jobject) addr)) {
- st->print_cr(INTPTR_FORMAT " is a weak 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
}
-#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();