8214975: No hs-err file if fatal error is raised during dynamic initialization
Reviewed-by: dholmes, dcubed
--- 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) {
--- 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);
--- 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();
--- /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<String, String> 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.");
+
+ }
+
+}
+
+