# HG changeset patch # User stuefe # Date 1544267399 -3600 # Node ID 0de1f006d3c37dbe35e027ff8033315172ca9f37 # Parent 69ccc5584e12ebfb3e48c4ec8b3dc2375b21f23f 8214975: No hs-err file if fatal error is raised during dynamic initialization Reviewed-by: dholmes, dcubed diff -r 69ccc5584e12 -r 0de1f006d3c3 src/hotspot/share/utilities/debug.cpp --- a/src/hotspot/share/utilities/debug.cpp Fri Feb 01 10:27:45 2019 +0100 +++ b/src/hotspot/share/utilities/debug.cpp Sat Dec 08 12:09:59 2018 +0100 @@ -92,6 +92,21 @@ # endif #endif // PRODUCT +#ifdef ASSERT +// This is to test that error reporting works if we assert during dynamic +// initialization of the hotspot. See JDK-8214975. +struct Crasher { + Crasher() { + // Using getenv - no other mechanism would work yet. + const char* s = ::getenv("HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION"); + if (s != NULL && ::strcmp(s, "1") == 0) { + fatal("HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION"); + } + } +}; +static Crasher g_crasher; +#endif // ASSERT + ATTRIBUTE_PRINTF(1, 2) void warning(const char* format, ...) { if (PrintWarnings) { diff -r 69ccc5584e12 -r 0de1f006d3c3 src/hotspot/share/utilities/vmError.cpp --- a/src/hotspot/share/utilities/vmError.cpp Fri Feb 01 10:27:45 2019 +0100 +++ b/src/hotspot/share/utilities/vmError.cpp Sat Dec 08 12:09:59 2018 +0100 @@ -1189,16 +1189,6 @@ volatile intptr_t VMError::first_error_tid = -1; -// An error could happen before tty is initialized or after it has been -// destroyed. -// Please note: to prevent large stack allocations, the log- and -// output-stream use a global scratch buffer for format printing. -// (see VmError::report_and_die(). Access to those streams is synchronized -// in VmError::report_and_die() - there is only one reporting thread at -// any given time. -fdStream VMError::out(defaultStream::output_fd()); -fdStream VMError::log; // error log used by VMError::report_and_die() - /** Expand a pattern into a buffer starting at pos and open a file using constructed path */ static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) { int fd = -1; @@ -1303,9 +1293,25 @@ Thread* thread, address pc, void* siginfo, void* context, const char* filename, int lineno, size_t size) { - // Don't allocate large buffer on stack + // A single scratch buffer to be used from here on. + // Do not rely on it being preserved across function calls. static char buffer[O_BUFLEN]; + + // File descriptor to tty to print an error summary to. + // Hard wired to stdout; see JDK-8215004 (compatibility concerns). + static const int fd_out = 1; // stdout + + // File descriptor to the error log file. + static int fd_log = -1; + + // Use local fdStream objects only. Do not use global instances whose initialization + // relies on dynamic initialization (see JDK-8214975). Do not rely on these instances + // to carry over into recursions or invocations from other threads. + fdStream out(fd_out); out.set_scratch_buffer(buffer, sizeof(buffer)); + + // Depending on the re-entrance depth at this point, fd_log may be -1 or point to an open hs-err file. + fdStream log(fd_log); log.set_scratch_buffer(buffer, sizeof(buffer)); // How many errors occurred in error handler when reporting first_error. @@ -1451,15 +1457,15 @@ // see if log file is already open if (!log.is_open()) { // open log file - int fd = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer)); - if (fd != -1) { + fd_log = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer)); + if (fd_log != -1) { out.print_raw("# An error report file with more information is saved as:\n# "); out.print_raw_cr(buffer); - log.set_fd(fd); + log.set_fd(fd_log); } else { out.print_raw_cr("# Can not save log file, dump to screen.."); - log.set_fd(defaultStream::output_fd()); + log.set_fd(fd_out); } } @@ -1468,8 +1474,9 @@ _current_step = 0; _current_step_info = ""; - if (log.fd() != defaultStream::output_fd()) { - close(log.fd()); + if (fd_log != -1) { + close(fd_log); + fd_log = -1; } log.set_fd(-1); diff -r 69ccc5584e12 -r 0de1f006d3c3 src/hotspot/share/utilities/vmError.hpp --- a/src/hotspot/share/utilities/vmError.hpp Fri Feb 01 10:27:45 2019 +0100 +++ b/src/hotspot/share/utilities/vmError.hpp Sat Dec 08 12:09:59 2018 +0100 @@ -122,9 +122,6 @@ void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); static void report_and_die(const char* message, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(2, 3); - static fdStream out; - static fdStream log; // error log used by VMError::report_and_die() - // Timeout handling. // Hook functions for platform dependend functionality: static void reporting_started(); diff -r 69ccc5584e12 -r 0de1f006d3c3 test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java Sat Dec 08 12:09:59 2018 +0100 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, SAP. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @bug 8214975 + * @summary No hs-err file if fatal error is raised during dynamic initialization. + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @requires (vm.debug == true) + * @requires os.family == "linux" + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.regex.Pattern; +import java.util.Map; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class VeryEarlyAssertTest { + + public static void main(String[] args) throws Exception { + + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xmx64M", + "-XX:-CreateCoredumpOnCrash", + "-version"); + Map env = pb.environment(); + env.put("HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION", "1"); + + OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); + + // we should have crashed with an assert with a specific message: + output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*"); + output_detail.shouldMatch("#.*HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION.*"); + + // 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"); + } + + // scan hs-err file: File should contain the same assertion message. Other than that, + // do not expect too much: file will be littered with secondary errors. The test + // should test that we get a hs-err file at all. + 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(".*HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION.*") + }; + 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."); + + } + +} + +