Skip to content

Commit

Permalink
8338883: Show warning when CreateCoredumpOnCrash set, but core dump w…
Browse files Browse the repository at this point in the history
…ill not happen

Reviewed-by: dholmes, jsjolen
  • Loading branch information
Gerard Ziemski committed Oct 16, 2024
1 parent 7625b29 commit c34fb2c
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 73 deletions.
67 changes: 31 additions & 36 deletions src/hotspot/os/posix/os_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
} else {
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);
success = true;
} 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);
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;
} 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) {
Expand Down
60 changes: 36 additions & 24 deletions src/hotspot/os/windows/os_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/os.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/runtime/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/utilities/vmError.cpp
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand Down
58 changes: 48 additions & 10 deletions test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -29,6 +29,7 @@
* java.management
* jdk.internal.jvmstat/sun.jvmstat.monitor
* @run driver CreateCoredumpOnCrash
* @requires vm.flagless
*/

import jdk.test.lib.process.ProcessTools;
Expand All @@ -43,24 +44,61 @@ public static void main(String[] args) {
}
}

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));
}
}

0 comments on commit c34fb2c

Please sign in to comment.