From e3ece365ce7dc92dd9d0a7ad9eb53ed9ea87f48d Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 17 Apr 2023 21:38:46 +0000 Subject: [PATCH] 8303422: Use common functions to exit the VM for -Xshare:dump and CDS errors Reviewed-by: iklam, coleenp, fparain --- src/hotspot/share/cds/archiveBuilder.cpp | 8 +-- src/hotspot/share/cds/archiveUtils.cpp | 9 ++-- src/hotspot/share/cds/dynamicArchive.cpp | 3 +- src/hotspot/share/cds/filemap.cpp | 54 +++++++------------ src/hotspot/share/cds/filemap.hpp | 2 - src/hotspot/share/cds/heapShared.cpp | 8 +-- src/hotspot/share/cds/metaspaceShared.cpp | 58 ++++++++++++++++----- src/hotspot/share/cds/metaspaceShared.hpp | 4 ++ src/hotspot/share/classfile/stringTable.cpp | 2 +- 9 files changed, 82 insertions(+), 66 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index f69596dd41e..1a73c4ab2ac 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -331,7 +331,7 @@ address ArchiveBuilder::reserve_buffer() { ReservedSpace rs(buffer_size, MetaspaceShared::core_region_alignment(), os::vm_page_size()); if (!rs.is_reserved()) { log_error(cds)("Failed to reserve " SIZE_FORMAT " bytes of output buffer.", buffer_size); - os::_exit(0); + MetaspaceShared::unrecoverable_writing_error(); } // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when @@ -381,7 +381,7 @@ address ArchiveBuilder::reserve_buffer() { log_error(cds)("my_archive_requested_top = " INTPTR_FORMAT, p2i(my_archive_requested_top)); log_error(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. " "Please rerun java -Xshare:dump with a lower value", p2i(_requested_static_archive_bottom)); - os::_exit(0); + MetaspaceShared::unrecoverable_writing_error(); } if (DumpSharedSpaces) { @@ -1269,8 +1269,8 @@ void ArchiveBuilder::report_out_of_space(const char* name, size_t needed_bytes) _rw_region.print_out_of_space_msg(name, needed_bytes); _ro_region.print_out_of_space_msg(name, needed_bytes); - vm_exit_during_initialization(err_msg("Unable to allocate from '%s' region", name), - "Please reduce the number of shared classes."); + log_error(cds)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name); + MetaspaceShared::unrecoverable_writing_error(); } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 260424fcb37..9f99d1d98fc 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -164,8 +164,8 @@ char* DumpRegion::expand_top_to(char* newtop) { // This is just a sanity check and should not appear in any real world usage. This // happens only if you allocate more than 2GB of shared objects and would require // millions of shared classes. - vm_exit_during_initialization("Out of memory in the CDS archive", - "Please reduce the number of shared classes."); + log_error(cds)("Out of memory in the CDS archive: Please reduce the number of shared classes."); + MetaspaceShared::unrecoverable_writing_error(); } } @@ -190,8 +190,9 @@ void DumpRegion::commit_to(char* newtop) { assert(commit <= uncommitted, "sanity"); if (!_vs->expand_by(commit, false)) { - vm_exit_during_initialization(err_msg("Failed to expand shared space to " SIZE_FORMAT " bytes", - need_committed_size)); + log_error(cds)("Failed to expand shared space to " SIZE_FORMAT " bytes", + need_committed_size); + MetaspaceShared::unrecoverable_writing_error(); } const char* which; diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index e553f6598fd..36728e459c6 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -367,7 +367,8 @@ void DynamicArchive::check_for_dynamic_dump() { #define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." if (RecordDynamicDumpInfo) { - vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo" __THEMSG, nullptr); + log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); + MetaspaceShared::unrecoverable_loading_error(); } else { assert(ArchiveClassesAtExit != nullptr, "sanity"); log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index da3775d28e2..8a0d55fd105 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -80,29 +80,6 @@ #define O_BINARY 0 // otherwise do nothing. #endif -// Complain and stop. All error conditions occurring during the writing of -// an archive file should stop the process. Unrecoverable errors during -// the reading of the archive file should stop the process. - -static void fail_exit(const char *msg, va_list ap) { - // This occurs very early during initialization: tty is not initialized. - jio_fprintf(defaultStream::error_stream(), - "An error has occurred while processing the" - " shared archive file.\n"); - jio_vfprintf(defaultStream::error_stream(), msg, ap); - jio_fprintf(defaultStream::error_stream(), "\n"); - // Do not change the text of the below message because some tests check for it. - vm_exit_during_initialization("Unable to use shared archive.", nullptr); -} - - -void FileMapInfo::fail_stop(const char *msg, ...) { - va_list ap; - va_start(ap, msg); - fail_exit(msg, ap); // Never returns. - va_end(ap); // for completeness. -} - // Fill in the fileMapInfo structure with data about this VM instance. // This method copies the vm version info into header_version. If the version is too @@ -367,7 +344,8 @@ void SharedClassPathEntry::init(bool is_modules_image, // // If we can't access a jar file in the boot path, then we can't // make assumptions about where classes get loaded from. - FileMapInfo::fail_stop("Unable to open file %s.", cpe->name()); + log_error(cds)("Unable to open file %s.", cpe->name()); + MetaspaceShared::unrecoverable_loading_error(); } // No need to save the name of the module file, as it will be computed at run time @@ -1097,7 +1075,8 @@ bool FileMapInfo::validate_shared_path_table() { const char* hint_msg = log_is_enabled(Info, class, path) ? "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)"; if (RequireSharedSpaces) { - fail_stop("%s%s", mismatch_msg, hint_msg); + log_error(cds)("%s%s", mismatch_msg, hint_msg); + MetaspaceShared::unrecoverable_loading_error(); } else { log_warning(cds)("%s%s", mismatch_msg, hint_msg); } @@ -1447,7 +1426,8 @@ bool FileMapInfo::init_from_file(int fd) { void FileMapInfo::seek_to_position(size_t pos) { if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) { - fail_stop("Unable to seek to position " SIZE_FORMAT, pos); + log_error(cds)("Unable to seek to position %ld", pos); + MetaspaceShared::unrecoverable_loading_error(); } } @@ -1493,8 +1473,9 @@ void FileMapInfo::open_for_write() { remove(_full_path); int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); if (fd < 0) { - fail_stop("Unable to create shared archive file %s: (%s).", _full_path, - os::strerror(errno)); + log_error(cds)("Unable to create shared archive file %s: (%s).", _full_path, + os::strerror(errno)); + MetaspaceShared::unrecoverable_writing_error(); } _fd = fd; _file_open = true; @@ -1731,11 +1712,12 @@ size_t FileMapInfo::write_heap_regions(GrowableArray* regions, int arr_len = regions == nullptr ? 0 : regions->length(); if (arr_len > max_num_regions) { - fail_stop("Unable to write archive heap memory regions: " - "number of memory regions exceeds maximum due to fragmentation. " - "Please increase java heap size " - "(current MaxHeapSize is " SIZE_FORMAT ", InitialHeapSize is " SIZE_FORMAT ").", - MaxHeapSize, InitialHeapSize); + log_error(cds)("Unable to write archive heap memory regions: " + "number of memory regions exceeds maximum due to fragmentation. " + "Please increase java heap size " + "(current MaxHeapSize is " SIZE_FORMAT ", InitialHeapSize is " SIZE_FORMAT ").", + MaxHeapSize, InitialHeapSize); + MetaspaceShared::unrecoverable_writing_error(); } size_t total_size = 0; @@ -1769,7 +1751,7 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { // If the shared archive is corrupted, close it and remove it. close(); remove(_full_path); - fail_stop("Unable to write to shared archive file."); + MetaspaceShared::unrecoverable_writing_error("Unable to write to shared archive file."); } _file_offset += nbytes; } @@ -1810,7 +1792,7 @@ void FileMapInfo::write_bytes_aligned(const void* buffer, size_t nbytes) { void FileMapInfo::close() { if (_file_open) { if (::close(_fd) < 0) { - fail_stop("Unable to close the shared archive file."); + MetaspaceShared::unrecoverable_loading_error("Unable to close the shared archive file."); } _file_open = false; _fd = -1; @@ -2537,7 +2519,7 @@ void FileMapInfo::unmap_region(int i) { void FileMapInfo::assert_mark(bool check) { if (!check) { - fail_stop("Mark mismatch while restoring from shared file."); + MetaspaceShared::unrecoverable_loading_error("Mark mismatch while restoring from shared file."); } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 0a21613e300..b415ec6c0d3 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -482,8 +482,6 @@ public: // Remap the shared readonly space to shared readwrite, private. bool remap_shared_readonly_as_readwrite(); - // Errors. - static void fail_stop(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2); static bool memory_mapping_failed() { CDS_ONLY(return _memory_mapping_failed;) NOT_CDS(return false;) diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 1ef4ea67734..cc04f61d0c2 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -735,7 +735,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) { ResourceMark rm; log_error(cds, heap)("Class %s not allowed in archive heap. Must be in java.base%s", ik->external_name(), extra_msg); - os::_exit(1); + MetaspaceShared::unrecoverable_writing_error(); } bool KlassSubGraphInfo::is_non_early_klass(Klass* k) { @@ -1213,7 +1213,7 @@ bool HeapShared::archive_reachable_objects_from(int level, // these objects that are referenced (directly or indirectly) by static fields. ResourceMark rm; log_error(cds, heap)("Cannot archive object of class %s", orig_obj->klass()->external_name()); - os::_exit(1); + MetaspaceShared::unrecoverable_writing_error(); } // java.lang.Class instances cannot be included in an archived object sub-graph. We only support @@ -1223,7 +1223,7 @@ bool HeapShared::archive_reachable_objects_from(int level, // object that is referenced (directly or indirectly) by static fields. if (java_lang_Class::is_instance(orig_obj) && subgraph_info != _default_subgraph_info) { log_error(cds, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", level); - os::_exit(1); + MetaspaceShared::unrecoverable_writing_error(); } if (has_been_seen_during_subgraph_recording(orig_obj)) { @@ -1252,7 +1252,7 @@ bool HeapShared::archive_reachable_objects_from(int level, // We don't know how to handle an object that has been archived, but some of its reachable // objects cannot be archived. Bail out for now. We might need to fix this in the future if // we have a real use case. - os::_exit(1); + MetaspaceShared::unrecoverable_writing_error(); } } } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 2e762d29a31..a874668035f 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -267,8 +267,8 @@ void MetaspaceShared::initialize_for_static_dump() { size_t symbol_rs_size = LP64_ONLY(3 * G) NOT_LP64(128 * M); _symbol_rs = ReservedSpace(symbol_rs_size); if (!_symbol_rs.is_reserved()) { - vm_exit_during_initialization("Unable to reserve memory for symbols", - err_msg(SIZE_FORMAT " bytes.", symbol_rs_size)); + log_error(cds)("Unable to reserve memory for symbols: %ld bytes.", symbol_rs_size); + MetaspaceShared::unrecoverable_writing_error(); } _symbol_region.init(&_symbol_rs, &_symbol_vs); } @@ -309,7 +309,8 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) ResourceMark rm(current); if (utf8_length == 0x7fffffff) { // buf_len will overflown 32-bit value. - vm_exit_during_initialization(err_msg("string length too large: %d", utf8_length)); + log_error(cds)("string length too large: %d", utf8_length); + MetaspaceShared::unrecoverable_loading_error(); } int buf_len = utf8_length+1; char* utf8_buffer = NEW_RESOURCE_ARRAY(char, buf_len); @@ -564,10 +565,7 @@ void VM_PopulateDumpSharedSpace::doit() { "for testing purposes only and should not be used in a production environment"); } - // There may be pending VM operations. We have changed some global states - // (such as vmClasses::_klasses) that may cause these VM operations - // to fail. For safety, forget these operations and exit the VM directly. - os::_exit(0); + MetaspaceShared::exit_after_static_dump(); } class CollectCLDClosure : public CLDClosure { @@ -677,12 +675,13 @@ void MetaspaceShared::preload_and_dump() { preload_and_dump_impl(THREAD); if (HAS_PENDING_EXCEPTION) { if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { - vm_direct_exit(-1, err_msg("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " - SIZE_FORMAT "M", MaxHeapSize/M)); + log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " + SIZE_FORMAT "M", MaxHeapSize/M); + MetaspaceShared::unrecoverable_writing_error(); } else { log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); - vm_direct_exit(-1, "VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); + MetaspaceShared::unrecoverable_writing_error("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); } } else { // On success, the VM_PopulateDumpSharedSpace op should have @@ -902,6 +901,37 @@ bool MetaspaceShared::is_shared_dynamic(void* p) { } } +// This function is called when the JVM is unable to load the specified archive(s) due to one +// of the following conditions. +// - There's an error that indicates that the archive(s) files were corrupt or otherwise damaged. +// - When -XX:+RequireSharedSpaces is specified, AND the JVM cannot load the archive(s) due +// to version or classpath mismatch. +void MetaspaceShared::unrecoverable_loading_error(const char* message) { + log_error(cds)("An error has occurred while processing the shared archive file."); + if (message != nullptr) { + log_error(cds)("%s", message); + } + vm_exit_during_initialization("Unable to use shared archive.", nullptr); +} + +// This function is called when the JVM is unable to write the specified CDS archive due to an +// unrecoverable error. +void MetaspaceShared::unrecoverable_writing_error(const char* message) { + log_error(cds)("An error has occurred while writing the shared archive file."); + if (message != nullptr) { + log_error(cds)("%s", message); + } + vm_exit(1); +} + +// We have finished dumping the static archive. At this point, there may be pending VM +// operations. We have changed some global states (such as vmClasses::_klasses) that +// may cause these VM operations to fail. For safety, forget these operations and +// exit the VM directly. +void MetaspaceShared::exit_after_static_dump() { + os::_exit(0); +} + void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled"); MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE; @@ -950,9 +980,9 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { DynamicDumpSharedSpaces = false; log_info(cds)("Unable to map shared spaces"); if (PrintSharedArchiveAndExit) { - vm_exit_during_initialization("Unable to use shared archive."); + MetaspaceShared::unrecoverable_loading_error("Unable to use shared archive."); } else if (RequireSharedSpaces) { - FileMapInfo::fail_stop("Unable to map shared spaces"); + MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); } } @@ -967,7 +997,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { delete dynamic_mapinfo; } if (RequireSharedSpaces && has_failed) { - FileMapInfo::fail_stop("Unable to map shared spaces"); + MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); } } @@ -995,7 +1025,7 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { if (!mapinfo->initialize()) { delete(mapinfo); if (RequireSharedSpaces) { - FileMapInfo::fail_stop("Failed to initialize dynamic archive"); + MetaspaceShared::unrecoverable_loading_error("Failed to initialize dynamic archive"); } return nullptr; } diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 9c79cb17a36..9e410b257c4 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -116,6 +116,10 @@ public: static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false); + static void unrecoverable_loading_error(const char* message = nullptr); + static void unrecoverable_writing_error(const char* message = nullptr); + static void exit_after_static_dump(); + static void serialize(SerializeClosure* sc) NOT_CDS_RETURN; // JVM/TI RedefineClasses() support: diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index f84491ce06a..8db4c08c966 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -797,7 +797,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern // but bail out for safety. log_error(cds)("Too many strings to be archived: " SIZE_FORMAT, _items_count); - os::_exit(1); + MetaspaceShared::unrecoverable_writing_error(); } objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK);