8338883: Show warning when CreateCoredumpOnCrash set, but core dump will not happen

Reviewed-by: dholmes, jsjolen
This commit is contained in:
Gerard Ziemski 2024-10-16 15:32:07 +00:00
parent 7625b29920
commit c34fb2c989
6 changed files with 125 additions and 74 deletions

View File

@ -104,49 +104,44 @@ static int clock_tics_per_sec = 100;
size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN;
// Check core dump limit and report possible place where core can be found
void os::check_dump_limit(char* buffer, size_t bufferSize) {
void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
VMError::record_coredump_status(buffer, false);
return;
}
int n;
struct rlimit rlim;
bool success;
char core_path[PATH_MAX];
n = get_core_path(core_path, PATH_MAX);
if (n <= 0) {
jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id());
success = true;
#ifdef LINUX
} else if (core_path[0] == '"') { // redirect to user process
jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path);
success = true;
#endif
} else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path);
success = true;
} else {
switch(rlim.rlim_cur) {
case RLIM_INFINITY:
jio_snprintf(buffer, bufferSize, "%s", core_path);
success = true;
break;
case 0:
jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again");
success = false;
break;
default:
jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K);
success = true;
break;
struct rlimit rlim;
bool success = true;
bool warn = true;
char core_path[PATH_MAX];
if (get_core_path(core_path, PATH_MAX) <= 0) {
jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id());
#ifdef LINUX
} else if (core_path[0] == '"') { // redirect to user process
jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path);
#endif
} else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path);
} else {
switch(rlim.rlim_cur) {
case RLIM_INFINITY:
jio_snprintf(buffer, bufferSize, "%s", core_path);
warn = false;
break;
case 0:
jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again");
success = false;
break;
default:
jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K);
break;
}
}
if (!check_only) {
VMError::record_coredump_status(buffer, success);
} else if (warn) {
warning("CreateCoredumpOnCrash specified, but %s", buffer);
}
}
VMError::record_coredump_status(buffer, success);
}
bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) {

View File

@ -1287,38 +1287,50 @@ void os::shutdown() {
static HANDLE dumpFile = nullptr;
// Check if dump file can be created.
void os::check_dump_limit(char* buffer, size_t buffsz) {
bool status = true;
// Check if core dump is active and if a core dump file can be created
void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line");
status = false;
}
jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
VMError::record_coredump_status(buffer, false);
} else {
bool success = true;
bool warn = true;
#ifndef ASSERT
if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows");
status = false;
}
if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
jio_snprintf(buffer, bufferSize, "Minidumps are not enabled by default on client versions of Windows");
success = false;
warn = true;
}
#endif
if (status) {
const char* cwd = get_current_directory(nullptr, 0);
int pid = current_process_id();
if (cwd != nullptr) {
jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid);
} else {
jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid);
if (success) {
if (!check_only) {
const char* cwd = get_current_directory(nullptr, 0);
int pid = current_process_id();
if (cwd != nullptr) {
jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp", cwd, pid);
} else {
jio_snprintf(buffer, bufferSize, ".\\hs_err_pid%u.mdmp", pid);
}
if (dumpFile == nullptr &&
(dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
== INVALID_HANDLE_VALUE) {
jio_snprintf(buffer, bufferSize, "Failed to create minidump file (0x%x).", GetLastError());
success = false;
}
} else {
// For now on Windows, there are no more checks that we can do
warn = false;
}
}
if (dumpFile == nullptr &&
(dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
== INVALID_HANDLE_VALUE) {
jio_snprintf(buffer, buffsz, "Failed to create minidump file (0x%x).", GetLastError());
status = false;
if (!check_only) {
VMError::record_coredump_status(buffer, success);
} else if (warn) {
warning("CreateCoredumpOnCrash specified, but %s", buffer);
}
}
VMError::record_coredump_status(buffer, status);
}
void os::abort(bool dump_core, void* siginfo, const void* context) {

View File

@ -939,7 +939,7 @@ class os: AllStatic {
// provided buffer as a scratch buffer. The status message which will be written
// into the error log either is file location or a short error message, depending
// on the checking result.
static void check_dump_limit(char* buffer, size_t bufferSize);
static void check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only = false);
// Get the default path to the core file
// Returns the length of the string

View File

@ -65,6 +65,7 @@
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/flags/jvmFlagLimit.hpp"
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
@ -665,6 +666,11 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
log_info(os)("Initialized VM with process ID %d", os::current_process_id());
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && CreateCoredumpOnCrash) {
char buffer[2*JVM_MAXPATHLEN];
os::check_core_dump_prerequisites(buffer, sizeof(buffer), true);
}
// Signal Dispatcher needs to be started before VMInit event is posted
os::initialize_jdk_signal_support(CHECK_JNI_ERR);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020 SAP SE. All rights reserved.
* Copyright (c) 2023, Red Hat, Inc. and/or its affiliates.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -1696,7 +1696,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt
ShowMessageBoxOnError = false;
}
os::check_dump_limit(buffer, sizeof(buffer));
os::check_core_dump_prerequisites(buffer, sizeof(buffer));
// reset signal handlers or exception filter; make sure recursive crashes
// are handled properly.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. 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
@ -29,6 +29,7 @@
* java.management
* jdk.internal.jvmstat/sun.jvmstat.monitor
* @run driver CreateCoredumpOnCrash
* @requires vm.flagless
*/
import jdk.test.lib.process.ProcessTools;
@ -43,24 +44,61 @@ public class CreateCoredumpOnCrash {
}
}
private static String ulimitString(int limit) {
String string = "ulimit -c ";
if (limit != Integer.MAX_VALUE) {
string += limit;
} else {
string += "unlimited";
}
return string+";";
}
public static void main(String[] args) throws Exception {
runTest("-XX:-CreateCoredumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped")
.shouldNotHaveExitValue(0);
.shouldNotHaveExitValue(0);
if (Platform.isWindows()) {
// The old CreateMinidumpOnCrash option should still work
runTest("-XX:-CreateMinidumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped")
.shouldNotHaveExitValue(0);
.shouldNotHaveExitValue(0);
} else {
runTest("-XX:+CreateCoredumpOnCrash").shouldNotContain("CreateCoredumpOnCrash turned off, no core file dumped")
.shouldNotHaveExitValue(0);
}
String exec_cmd[] = {"sh", "-c", "ulimit -c"};
OutputAnalyzer oa = new OutputAnalyzer(Runtime.getRuntime().exec(exec_cmd));
oa.shouldHaveExitValue(0);
if (!oa.contains("0\n")) {
oa = runTest("-XX:+CreateCoredumpOnCrash");
oa.shouldContain("Core dump will be written.");
oa.shouldNotHaveExitValue(0);
oa = runTest("-XX:+CreateCoredumpOnCrash", ulimitString(1024));
oa.shouldContain("warning: CreateCoredumpOnCrash specified, but");
oa.shouldNotHaveExitValue(0);
oa = runTest("-XX:+CreateCoredumpOnCrash", ulimitString(0));
oa.shouldContain("warning: CreateCoredumpOnCrash specified, but");
oa.shouldNotHaveExitValue(0);
} else {
throw new Exception("ulimit is not set correctly, try 'ulimit -c unlimited' and re-run.");
}
}
}
public static OutputAnalyzer runTest(String option) throws Exception {
return new OutputAnalyzer(
ProcessTools.createLimitedTestJavaProcessBuilder(
"-Xmx128m", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", option, Crasher.class.getName())
.start());
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m",
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
option, Crasher.class.getName());
return new OutputAnalyzer(pb.start());
}
public static OutputAnalyzer runTest(String option, String limit) throws Exception {
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xmx128m",
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
option, new String("'"+Crasher.class.getName()+"'"));
String args = "";
for (String s:pb.command()) {
args += s+" ";
}
String exec_cmd[] = {"sh", "-c", limit+args};
return new OutputAnalyzer(Runtime.getRuntime().exec(exec_cmd));
}
}