8074552: SafeFetch32 and SafeFetchN do not work in error handling
authordholmes
Thu, 12 Mar 2015 19:34:50 -0400
changeset 29573 2d800e5d575f
parent 29572 cf3e05e32c13
child 29574 ab0121071f54
8074552: SafeFetch32 and SafeFetchN do not work in error handling Reviewed-by: dholmes, goetz Contributed-by: Thomas Stufe <thomas.stuefe@gmail.com>
hotspot/src/os/aix/vm/vmError_aix.cpp
hotspot/src/os/bsd/vm/os_bsd.hpp
hotspot/src/os/bsd/vm/vmError_bsd.cpp
hotspot/src/os/linux/vm/os_linux.hpp
hotspot/src/os/linux/vm/vmError_linux.cpp
hotspot/src/os/solaris/vm/os_solaris.hpp
hotspot/src/os/solaris/vm/vmError_solaris.cpp
hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp
hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp
hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp
hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp
hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp
hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/stubRoutines.cpp
hotspot/src/share/vm/runtime/stubRoutines.hpp
hotspot/src/share/vm/utilities/vmError.cpp
hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java
--- a/hotspot/src/os/aix/vm/vmError_aix.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/aix/vm/vmError_aix.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -109,7 +109,15 @@
   }
   sigthreadmask(SIG_UNBLOCK, &newset, NULL);
 
-  VMError err(NULL, sig, NULL, info, ucVoid);
+  // support safefetch faults in error handling
+  ucontext_t* const uc = (ucontext_t*) ucVoid;
+  address const pc = uc ? os::Aix::ucontext_get_pc(uc) : NULL;
+  if (uc && pc && StubRoutines::is_safefetch_fault(pc)) {
+    os::Aix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
+    return;
+  }
+
+  VMError err(NULL, sig, pc, info, ucVoid);
   err.report_and_die();
 }
 
--- a/hotspot/src/os/bsd/vm/os_bsd.hpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/bsd/vm/os_bsd.hpp	Thu Mar 12 19:34:50 2015 -0400
@@ -99,6 +99,7 @@
   static void set_page_size(int val)                                { _page_size = val; }
 
   static address   ucontext_get_pc(ucontext_t* uc);
+  static void ucontext_set_pc(ucontext_t* uc, address pc);
   static intptr_t* ucontext_get_sp(ucontext_t* uc);
   static intptr_t* ucontext_get_fp(ucontext_t* uc);
 
--- a/hotspot/src/os/bsd/vm/vmError_bsd.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/bsd/vm/vmError_bsd.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -112,7 +112,16 @@
   }
   pthread_sigmask(SIG_UNBLOCK, &newset, NULL);
 
-  VMError err(NULL, sig, NULL, info, ucVoid);
+  // support safefetch faults in error handling
+  ucontext_t* const uc = (ucontext_t*) ucVoid;
+  address const pc = uc ? os::Bsd::ucontext_get_pc(uc) : NULL;
+
+  if (uc && pc && StubRoutines::is_safefetch_fault(pc)) {
+    os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
+    return;
+  }
+
+  VMError err(NULL, sig, pc, info, ucVoid);
   err.report_and_die();
 }
 
--- a/hotspot/src/os/linux/vm/os_linux.hpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/linux/vm/os_linux.hpp	Thu Mar 12 19:34:50 2015 -0400
@@ -143,6 +143,7 @@
   static int vm_default_page_size(void)                             { return _vm_default_page_size; }
 
   static address   ucontext_get_pc(ucontext_t* uc);
+  static void ucontext_set_pc(ucontext_t* uc, address pc);
   static intptr_t* ucontext_get_sp(ucontext_t* uc);
   static intptr_t* ucontext_get_fp(ucontext_t* uc);
 
--- a/hotspot/src/os/linux/vm/vmError_linux.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/linux/vm/vmError_linux.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -112,7 +112,16 @@
   }
   pthread_sigmask(SIG_UNBLOCK, &newset, NULL);
 
-  VMError err(NULL, sig, NULL, info, ucVoid);
+  // support safefetch faults in error handling
+  ucontext_t* const uc = (ucontext_t*) ucVoid;
+  address const pc = uc ? os::Linux::ucontext_get_pc(uc) : NULL;
+
+  if (uc && pc && StubRoutines::is_safefetch_fault(pc)) {
+    os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
+    return;
+  }
+
+  VMError err(NULL, sig, pc, info, ucVoid);
   err.report_and_die();
 }
 
--- a/hotspot/src/os/solaris/vm/os_solaris.hpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/solaris/vm/os_solaris.hpp	Thu Mar 12 19:34:50 2015 -0400
@@ -137,6 +137,7 @@
   // ucontext_get_fp() is only used by Solaris X86 (see note below)
   static intptr_t*   ucontext_get_fp(ucontext_t* uc);
   static address    ucontext_get_pc(ucontext_t* uc);
+  static void ucontext_set_pc(ucontext_t* uc, address pc);
 
   // For Analyzer Forte AsyncGetCallTrace profiling support:
   // Parameter ret_fp is only used by Solaris X86.
--- a/hotspot/src/os/solaris/vm/vmError_solaris.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os/solaris/vm/vmError_solaris.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -109,7 +109,15 @@
   }
   thr_sigsetmask(SIG_UNBLOCK, &newset, NULL);
 
-  VMError err(NULL, sig, NULL, info, ucVoid);
+  // support safefetch faults in error handling
+  ucontext_t* const uc = (ucontext_t*) ucVoid;
+  address const pc = uc ? os::Solaris::ucontext_get_pc(uc) : NULL;
+  if (uc && pc && StubRoutines::is_safefetch_fault(pc)) {
+    os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
+    return;
+  }
+
+  VMError err(NULL, sig, pc, info, ucVoid);
   err.report_and_die();
 }
 
--- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -397,7 +397,7 @@
           // continue at the next instruction after the faulting read. Returning
           // garbage from this read is ok.
           thread->set_pending_unsafe_access_error();
-          uc->uc_mcontext.jmp_context.iar = ((unsigned long)pc) + 4;
+          os::Aix::ucontext_set_pc(uc, pc + 4);
           return 1;
         }
       }
@@ -420,7 +420,7 @@
         // continue at the next instruction after the faulting read. Returning
         // garbage from this read is ok.
         thread->set_pending_unsafe_access_error();
-        uc->uc_mcontext.jmp_context.iar = ((unsigned long)pc) + 4;
+        os::Aix::ucontext_set_pc(uc, pc + 4);
         return 1;
       }
     }
@@ -445,7 +445,7 @@
   if (stub != NULL) {
     // Save all thread context in case we need to restore it.
     if (thread != NULL) thread->set_saved_exception_pc(pc);
-    uc->uc_mcontext.jmp_context.iar = (unsigned long)stub;
+    os::Aix::ucontext_set_pc(uc, stub);
     return 1;
   }
 
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -309,6 +309,10 @@
   return (address)uc->context_pc;
 }
 
+void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) {
+  uc->context_pc = (intptr_t)pc ;
+}
+
 intptr_t* os::Bsd::ucontext_get_sp(ucontext_t * uc) {
   return (intptr_t*)uc->context_sp;
 }
@@ -463,7 +467,7 @@
     pc = (address) os::Bsd::ucontext_get_pc(uc);
 
     if (StubRoutines::is_safefetch_fault(pc)) {
-      uc->context_pc = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
+      os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
       return 1;
     }
 
@@ -703,7 +707,7 @@
     // save all thread context in case we need to restore it
     if (thread != NULL) thread->set_saved_exception_pc(pc);
 
-    uc->context_pc = (intptr_t)stub;
+    os::Bsd::ucontext_set_pc(uc, stub);
     return true;
   }
 
--- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -107,6 +107,10 @@
   return NULL;
 }
 
+void os::Bsd::ucontext_set_pc(ucontext_t * uc, address pc) {
+  ShouldNotCallThis();
+}
+
 ExtendedPC os::fetch_frame_from_context(void* ucVoid,
                                         intptr_t** ret_sp,
                                         intptr_t** ret_fp) {
--- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -113,6 +113,14 @@
   return (address)uc->uc_mcontext.regs->nip;
 }
 
+// modify PC in ucontext.
+// Note: Only use this for an ucontext handed down to a signal handler. See comment
+// in ucontext_get_pc.
+void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) {
+  guarantee(uc->uc_mcontext.regs != NULL, "only use ucontext_set_pc in sigaction context");
+  uc->uc_mcontext.regs->nip = (unsigned long)pc;
+}
+
 intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) {
   return (intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/];
 }
@@ -213,7 +221,7 @@
   if (uc) {
     address const pc = os::Linux::ucontext_get_pc(uc);
     if (pc && StubRoutines::is_safefetch_fault(pc)) {
-      uc->uc_mcontext.regs->nip = (unsigned long)StubRoutines::continuation_for_safefetch_fault(pc);
+      os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
       return true;
     }
   }
@@ -360,7 +368,7 @@
           // continue at the next instruction after the faulting read. Returning
           // garbage from this read is ok.
           thread->set_pending_unsafe_access_error();
-          uc->uc_mcontext.regs->nip = ((unsigned long)pc) + 4;
+          os::Linux::ucontext_set_pc(uc, pc + 4);
           return true;
         }
       }
@@ -379,7 +387,7 @@
         // continue at the next instruction after the faulting read. Returning
         // garbage from this read is ok.
         thread->set_pending_unsafe_access_error();
-        uc->uc_mcontext.regs->nip = ((unsigned long)pc) + 4;
+        os::Linux::ucontext_set_pc(uc, pc + 4);
         return true;
       }
     }
@@ -402,7 +410,7 @@
   if (stub != NULL) {
     // Save all thread context in case we need to restore it.
     if (thread != NULL) thread->set_saved_exception_pc(pc);
-    uc->uc_mcontext.regs->nip = (unsigned long)stub;
+    os::Linux::ucontext_set_pc(uc, stub);
     return true;
   }
 
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -85,11 +85,6 @@
   CON_O7,
 };
 
-static inline void set_cont_address(sigcontext* ctx, address addr) {
-  SIG_PC(ctx)  = (intptr_t)addr;
-  SIG_NPC(ctx) = (intptr_t)(addr+4);
-}
-
 // For Forte Analyzer AsyncGetCallTrace profiling support - thread is
 // currently interrupted by SIGPROF.
 // os::Solaris::fetch_frame_from_ucontext() tries to skip nested
@@ -351,6 +346,12 @@
   return (address) SIG_PC((sigcontext*)uc);
 }
 
+void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) {
+  sigcontext_t* ctx = (sigcontext_t*) uc;
+  SIG_PC(ctx)  = (intptr_t)addr;
+  SIG_NPC(ctx) = (intptr_t)(addr+4);
+}
+
 intptr_t* os::Linux::ucontext_get_sp(ucontext_t *uc) {
   return (intptr_t*)
     ((intptr_t)SIG_REGS((sigcontext*)uc).u_regs[CON_O6] + STACK_BIAS);
@@ -366,7 +367,7 @@
 
 inline static bool checkPrefetch(sigcontext* uc, address pc) {
   if (StubRoutines::is_safefetch_fault(pc)) {
-    set_cont_address(uc, address(StubRoutines::continuation_for_safefetch_fault(pc)));
+    os::Linux::ucontext_set_pc((ucontext_t*)uc, StubRoutines::continuation_for_safefetch_fault(pc));
     return true;
   }
   return false;
@@ -666,7 +667,7 @@
       // save all thread context in case we need to restore it
       thread->set_saved_exception_pc(pc);
       thread->set_saved_exception_npc(npc);
-      set_cont_address(uc, stub);
+      os::Linux::ucontext_set_pc((ucontext_t*)uc, stub);
       return true;
     }
   }
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -122,6 +122,10 @@
   return (address)uc->uc_mcontext.gregs[REG_PC];
 }
 
+void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) {
+  uc->uc_mcontext.gregs[REG_PC] = (intptr_t)pc;
+}
+
 intptr_t* os::Linux::ucontext_get_sp(ucontext_t * uc) {
   return (intptr_t*)uc->uc_mcontext.gregs[REG_SP];
 }
@@ -279,7 +283,7 @@
     pc = (address) os::Linux::ucontext_get_pc(uc);
 
     if (StubRoutines::is_safefetch_fault(pc)) {
-      uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
+      os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
       return 1;
     }
 
@@ -514,7 +518,7 @@
     // save all thread context in case we need to restore it
     if (thread != NULL) thread->set_saved_exception_pc(pc);
 
-    uc->uc_mcontext.gregs[REG_PC] = (greg_t)stub;
+    os::Linux::ucontext_set_pc(uc, stub);
     return true;
   }
 
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -100,6 +100,10 @@
   ShouldNotCallThis();
 }
 
+void os::Linux::ucontext_set_pc(ucontext_t * uc, address pc) {
+  ShouldNotCallThis();
+}
+
 ExtendedPC os::fetch_frame_from_context(void* ucVoid,
                                         intptr_t** ret_sp,
                                         intptr_t** ret_fp) {
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -184,6 +184,11 @@
   return ExtendedPC(pc);
 }
 
+void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) {
+  uc->uc_mcontext.gregs [REG_PC]  = (greg_t) pc;
+  uc->uc_mcontext.gregs [REG_nPC] = (greg_t) (pc + 4);
+}
+
 // Assumes ucontext is valid
 intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) {
   return (intptr_t*)((intptr_t)uc->uc_mcontext.gregs[REG_SP] + STACK_BIAS);
@@ -355,8 +360,7 @@
 
     // SafeFetch() support
     if (StubRoutines::is_safefetch_fault(pc)) {
-      uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
-      uc->uc_mcontext.gregs[REG_nPC] = uc->uc_mcontext.gregs[REG_PC] + 4;
+      os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
       return 1;
     }
 
@@ -494,8 +498,7 @@
 
     // simulate a branch to the stub (a "call" in the safepoint stub case)
     // factor me: setPC
-    uc->uc_mcontext.gregs[REG_PC ] = (greg_t)stub;
-    uc->uc_mcontext.gregs[REG_nPC] = (greg_t)(stub + 4);
+    os::Solaris::ucontext_set_pc(uc, stub);
 
 #ifndef PRODUCT
     if (TraceJumps) thread->record_jump(stub, NULL, __FILE__, __LINE__);
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -174,6 +174,10 @@
   return ExtendedPC((address)uc->uc_mcontext.gregs[REG_PC]);
 }
 
+void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) {
+  uc->uc_mcontext.gregs [REG_PC]  = (greg_t) pc;
+}
+
 // Assumes ucontext is valid
 intptr_t* os::Solaris::ucontext_get_sp(ucontext_t *uc) {
   return (intptr_t*)uc->uc_mcontext.gregs[REG_SP];
@@ -411,7 +415,7 @@
     pc = (address) uc->uc_mcontext.gregs[REG_PC];
 
     if (StubRoutines::is_safefetch_fault(pc)) {
-      uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
+      os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
       return true;
     }
 
@@ -614,8 +618,7 @@
     if (thread != NULL) thread->set_saved_exception_pc(pc);
     // 12/02/99: On Sparc it appears that the full context is also saved
     // but as yet, no one looks at or restores that saved context
-    // factor me: setPC
-    uc->uc_mcontext.gregs[REG_PC] = (greg_t)stub;
+    os::Solaris::ucontext_set_pc(uc, stub);
     return true;
   }
 
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Thu Mar 12 19:34:50 2015 -0400
@@ -921,6 +921,9 @@
           "If > 0, provokes an error inside VM error handler (a secondary " \
           "crash). see test_error_handler() in debug.cpp.")                 \
                                                                             \
+  notproduct(bool, TestSafeFetchInErrorHandler, false,                      \
+          "If true, tests SafeFetch inside error handler.")                 \
+                                                                            \
   develop(bool, Verbose, false,                                             \
           "Print additional debugging information from other modes")        \
                                                                             \
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -210,8 +210,36 @@
     assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything");
   }
 }
+
+// simple test for SafeFetch32
+static void test_safefetch32() {
+  int dummy = 17;
+  int* const p_invalid = (int*) get_segfault_address();
+  int* const p_valid = &dummy;
+  int result_invalid = SafeFetch32(p_invalid, 0xABC);
+  assert(result_invalid == 0xABC, "SafeFetch32 error");
+  int result_valid = SafeFetch32(p_valid, 0xABC);
+  assert(result_valid == 17, "SafeFetch32 error");
+}
+
+// simple test for SafeFetchN
+static void test_safefetchN() {
+#ifdef _LP64
+  const intptr_t v1 = UCONST64(0xABCD00000000ABCD);
+  const intptr_t v2 = UCONST64(0xDEFD00000000DEFD);
+#else
+  const intptr_t v1 = 0xABCDABCD;
+  const intptr_t v2 = 0xDEFDDEFD;
 #endif
-
+  intptr_t dummy = v1;
+  intptr_t* const p_invalid = (intptr_t*) get_segfault_address();
+  intptr_t* const p_valid = &dummy;
+  intptr_t result_invalid = SafeFetchN(p_invalid, v2);
+  assert(result_invalid == v2, "SafeFetchN error");
+  intptr_t result_valid = SafeFetchN(p_valid, v2);
+  assert(result_valid == v1, "SafeFetchN error");
+}
+#endif
 
 void StubRoutines::initialize2() {
   if (_code2 == NULL) {
@@ -300,6 +328,13 @@
   test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_conjoint_words), sizeof(jlong));
   test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_disjoint_words), sizeof(jlong));
 
+  // test safefetch routines
+  // Not on Windows 32bit until 8074860 is fixed
+#if ! (defined(_WIN32) && defined(_M_IX86))
+  test_safefetch32();
+  test_safefetchN();
+#endif
+
 #endif
 }
 
--- a/hotspot/src/share/vm/runtime/stubRoutines.hpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp	Thu Mar 12 19:34:50 2015 -0400
@@ -458,4 +458,9 @@
   return StubRoutines::SafeFetchN_stub()(adr, errValue);
 }
 
+
+// returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated)
+inline bool CanUseSafeFetch32() { return StubRoutines::SafeFetch32_stub() ? true : false; }
+inline bool CanUseSafeFetchN()  { return StubRoutines::SafeFetchN_stub() ? true : false; }
+
 #endif // SHARE_VM_RUNTIME_STUBROUTINES_HPP
--- a/hotspot/src/share/vm/utilities/vmError.cpp	Wed Mar 11 18:49:22 2015 -0400
+++ b/hotspot/src/share/vm/utilities/vmError.cpp	Thu Mar 12 19:34:50 2015 -0400
@@ -358,18 +358,38 @@
 
   // test secondary error handling. Test it twice, to test that resetting
   // error handler after a secondary crash works.
-  STEP(13, "(test secondary crash 1)")
+  STEP(11, "(test secondary crash 1)")
+    if (_verbose && TestCrashInErrorHandler != 0) {
+      st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...",
+        TestCrashInErrorHandler);
+      controlled_crash(TestCrashInErrorHandler);
+    }
+
+  STEP(12, "(test secondary crash 2)")
     if (_verbose && TestCrashInErrorHandler != 0) {
       st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...",
         TestCrashInErrorHandler);
       controlled_crash(TestCrashInErrorHandler);
     }
 
-  STEP(14, "(test secondary crash 2)")
-    if (_verbose && TestCrashInErrorHandler != 0) {
-      st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...",
-        TestCrashInErrorHandler);
-      controlled_crash(TestCrashInErrorHandler);
+  STEP(13, "(test safefetch in error handler)")
+    // test whether it is safe to use SafeFetch32 in Crash Handler. Test twice
+    // to test that resetting the signal handler works correctly.
+    if (_verbose && TestSafeFetchInErrorHandler) {
+      st->print_cr("Will test SafeFetch...");
+      if (CanUseSafeFetch32()) {
+        int* const invalid_pointer = (int*) get_segfault_address();
+        const int x = 0x76543210;
+        int i1 = SafeFetch32(invalid_pointer, x);
+        int i2 = SafeFetch32(invalid_pointer, x);
+        if (i1 == x && i2 == x) {
+          st->print_cr("SafeFetch OK."); // Correctly deflected and returned default pattern
+        } else {
+          st->print_cr("??");
+        }
+      } else {
+        st->print_cr("not possible; skipped.");
+      }
     }
 #endif // PRODUCT
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java	Thu Mar 12 19:34:50 2015 -0400
@@ -0,0 +1,92 @@
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.regex.Pattern;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.Platform;
+import com.oracle.java.testlibrary.ProcessTools;
+
+/*
+ * @test
+ * @bug 8074552
+ * @summary SafeFetch32 and SafeFetchN do not work in error handling
+ * @library /testlibrary
+ * @author Thomas Stuefe (SAP)
+ */
+
+public class SafeFetchInErrorHandlingTest {
+
+
+  public static void main(String[] args) throws Exception {
+
+    if (!Platform.isDebugBuild()) {
+      return;
+    }
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+        "-XX:+UnlockDiagnosticVMOptions",
+        "-Xmx100M",
+        "-XX:ErrorHandlerTest=14",
+        "-XX:+TestSafeFetchInErrorHandler",
+        "-version");
+
+    OutputAnalyzer output_detail = new OutputAnalyzer(pb.start());
+
+    // we should have crashed with a SIGSEGV
+    output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*");
+    output_detail.shouldMatch("# +(?:SIGSEGV|EXCEPTION_ACCESS_VIOLATION).*");
+
+    // extract hs-err file
+    String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1);
+    if (hs_err_file == null) {
+      throw new RuntimeException("Did not find hs-err file in output.\n");
+    }
+
+    File f = new File(hs_err_file);
+    if (!f.exists()) {
+      throw new RuntimeException("hs-err file missing at "
+          + f.getAbsolutePath() + ".\n");
+    }
+
+    System.out.println("Found hs_err file. Scanning...");
+
+    FileInputStream fis = new FileInputStream(f);
+    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+    String line = null;
+
+    Pattern [] pattern = new Pattern[] {
+        Pattern.compile("Will test SafeFetch..."),
+        Pattern.compile("SafeFetch OK."),
+    };
+    int currentPattern = 0;
+
+    String lastLine = null;
+    while ((line = br.readLine()) != null) {
+      if (currentPattern < pattern.length) {
+        if (pattern[currentPattern].matcher(line).matches()) {
+          System.out.println("Found: " + line + ".");
+          currentPattern ++;
+        }
+      }
+      lastLine = line;
+    }
+    br.close();
+
+    if (currentPattern < pattern.length) {
+      throw new RuntimeException("hs-err file incomplete (first missing pattern: " +  currentPattern + ")");
+    }
+
+    if (!lastLine.equals("END.")) {
+      throw new RuntimeException("hs-err file incomplete (missing END marker.)");
+    } else {
+      System.out.println("End marker found.");
+    }
+
+    System.out.println("OK.");
+
+  }
+
+}
+