diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index cc29f209160ee..78fd2a678886e 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -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) { diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 0d5727b98f443..fe093aee116b6 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -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) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 35a5be77b6058..65071769bc4cb 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -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 diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 45aaa769856af..b2edad395cef0 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -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); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 0b3ccf9c747aa..7bbb978b8064f 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -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. diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java index 73efc0e5e4605..76ea10d77cbbe 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java @@ -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 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)); } }