--- old/src/os/aix/vm/vmError_aix.cpp 2015-03-10 17:59:06.324500000 +0100 +++ new/src/os/aix/vm/vmError_aix.cpp 2015-03-10 17:59:06.140467000 +0100 @@ -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(); } --- old/src/os/bsd/vm/os_bsd.hpp 2015-03-10 17:59:07.269551000 +0100 +++ new/src/os/bsd/vm/os_bsd.hpp 2015-03-10 17:59:07.061573000 +0100 @@ -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); --- old/src/os/bsd/vm/vmError_bsd.cpp 2015-03-10 17:59:08.062632000 +0100 +++ new/src/os/bsd/vm/vmError_bsd.cpp 2015-03-10 17:59:07.898631000 +0100 @@ -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(); } --- old/src/os/linux/vm/os_linux.hpp 2015-03-10 17:59:09.098715000 +0100 +++ new/src/os/linux/vm/os_linux.hpp 2015-03-10 17:59:08.864666000 +0100 @@ -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); --- old/src/os/linux/vm/vmError_linux.cpp 2015-03-10 17:59:10.015764000 +0100 +++ new/src/os/linux/vm/vmError_linux.cpp 2015-03-10 17:59:09.784741000 +0100 @@ -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(); } --- old/src/os/solaris/vm/os_solaris.hpp 2015-03-10 17:59:11.041859000 +0100 +++ new/src/os/solaris/vm/os_solaris.hpp 2015-03-10 17:59:10.832801000 +0100 @@ -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. --- old/src/os/solaris/vm/vmError_solaris.cpp 2015-03-10 17:59:11.922898000 +0100 +++ new/src/os/solaris/vm/vmError_solaris.cpp 2015-03-10 17:59:11.747904000 +0100 @@ -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(); } --- old/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp 2015-03-10 17:59:12.840972000 +0100 +++ new/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp 2015-03-10 17:59:12.682941000 +0100 @@ -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; } --- old/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp 2015-03-10 17:59:13.692045000 +0100 +++ new/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp 2015-03-10 17:59:13.468993000 +0100 @@ -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; } --- old/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp 2015-03-10 17:59:14.557080000 +0100 +++ new/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp 2015-03-10 17:59:14.404068000 +0100 @@ -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) { --- old/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp 2015-03-10 17:59:15.548162000 +0100 +++ new/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp 2015-03-10 17:59:15.366168000 +0100 @@ -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; } --- old/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp 2015-03-10 17:59:16.470532000 +0100 +++ new/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp 2015-03-10 17:59:16.300208000 +0100 @@ -351,6 +351,10 @@ return (address) SIG_PC((sigcontext*)uc); } +void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) { + set_cont_address((sigcontext_t*) uc, pc); +} + 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); --- old/src/os_cpu/linux_x86/vm/os_linux_x86.cpp 2015-03-10 17:59:17.503330000 +0100 +++ new/src/os_cpu/linux_x86/vm/os_linux_x86.cpp 2015-03-10 17:59:17.283305000 +0100 @@ -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; } --- old/src/os_cpu/linux_zero/vm/os_linux_zero.cpp 2015-03-10 17:59:18.665379000 +0100 +++ new/src/os_cpu/linux_zero/vm/os_linux_zero.cpp 2015-03-10 17:59:18.494374000 +0100 @@ -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) { --- old/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp 2015-03-10 17:59:19.565471000 +0100 +++ new/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp 2015-03-10 17:59:19.407435000 +0100 @@ -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__); --- old/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp 2015-03-10 17:59:20.570568000 +0100 +++ new/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp 2015-03-10 17:59:20.408558000 +0100 @@ -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; } --- old/src/share/vm/runtime/globals.hpp 2015-03-10 17:59:21.492599000 +0100 +++ new/src/share/vm/runtime/globals.hpp 2015-03-10 17:59:21.296592000 +0100 @@ -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") \ \ --- old/src/share/vm/runtime/stubRoutines.cpp 2015-03-10 17:59:22.717703000 +0100 +++ new/src/share/vm/runtime/stubRoutines.cpp 2015-03-10 17:59:22.433674000 +0100 @@ -210,8 +210,36 @@ assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything"); } } -#endif +// 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,17 @@ 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)) + if (CanUseSafeFetch32()) { + test_safefetch32(); + } + if (CanUseSafeFetchN()) { + test_safefetchN(); + } +#endif + #endif } --- old/src/share/vm/runtime/stubRoutines.hpp 2015-03-10 17:59:23.746777000 +0100 +++ new/src/share/vm/runtime/stubRoutines.hpp 2015-03-10 17:59:23.577751000 +0100 @@ -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 --- old/src/share/vm/utilities/vmError.cpp 2015-03-10 17:59:24.622833000 +0100 +++ new/src/share/vm/utilities/vmError.cpp 2015-03-10 17:59:24.455809000 +0100 @@ -358,19 +358,39 @@ // 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(14, "(test secondary crash 2)") + STEP(12, "(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 STEP(15, "(printing type of error)") --- /dev/null 2011-11-04 17:17:15.000000000 +0100 +++ new/test/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java 2015-03-10 17:59:25.345900000 +0100 @@ -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."); + + } + +} +