8303422: Use common functions to exit the VM for -Xshare:dump and CDS errors

Reviewed-by: iklam, coleenp, fparain
This commit is contained in:
Matias Saavedra Silva 2023-04-17 21:38:46 +00:00
parent bb1a7bb3e1
commit e3ece365ce
9 changed files with 82 additions and 66 deletions

View file

@ -331,7 +331,7 @@ address ArchiveBuilder::reserve_buffer() {
ReservedSpace rs(buffer_size, MetaspaceShared::core_region_alignment(), os::vm_page_size()); ReservedSpace rs(buffer_size, MetaspaceShared::core_region_alignment(), os::vm_page_size());
if (!rs.is_reserved()) { if (!rs.is_reserved()) {
log_error(cds)("Failed to reserve " SIZE_FORMAT " bytes of output buffer.", buffer_size); 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 // 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)("my_archive_requested_top = " INTPTR_FORMAT, p2i(my_archive_requested_top));
log_error(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. " log_error(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. "
"Please rerun java -Xshare:dump with a lower value", p2i(_requested_static_archive_bottom)); "Please rerun java -Xshare:dump with a lower value", p2i(_requested_static_archive_bottom));
os::_exit(0); MetaspaceShared::unrecoverable_writing_error();
} }
if (DumpSharedSpaces) { 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); _rw_region.print_out_of_space_msg(name, needed_bytes);
_ro_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), log_error(cds)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name);
"Please reduce the number of shared classes."); MetaspaceShared::unrecoverable_writing_error();
} }

View file

@ -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 // 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 // happens only if you allocate more than 2GB of shared objects and would require
// millions of shared classes. // millions of shared classes.
vm_exit_during_initialization("Out of memory in the CDS archive", log_error(cds)("Out of memory in the CDS archive: Please reduce the number of shared classes.");
"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"); assert(commit <= uncommitted, "sanity");
if (!_vs->expand_by(commit, false)) { if (!_vs->expand_by(commit, false)) {
vm_exit_during_initialization(err_msg("Failed to expand shared space to " SIZE_FORMAT " bytes", log_error(cds)("Failed to expand shared space to " SIZE_FORMAT " bytes",
need_committed_size)); need_committed_size);
MetaspaceShared::unrecoverable_writing_error();
} }
const char* which; const char* which;

View file

@ -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." #define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."
if (RecordDynamicDumpInfo) { if (RecordDynamicDumpInfo) {
vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo" __THEMSG, nullptr); log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG);
MetaspaceShared::unrecoverable_loading_error();
} else { } else {
assert(ArchiveClassesAtExit != nullptr, "sanity"); assert(ArchiveClassesAtExit != nullptr, "sanity");
log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG); log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG);

View file

@ -80,29 +80,6 @@
#define O_BINARY 0 // otherwise do nothing. #define O_BINARY 0 // otherwise do nothing.
#endif #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. // 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 // 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 // If we can't access a jar file in the boot path, then we can't
// make assumptions about where classes get loaded from. // 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 // 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) ? const char* hint_msg = log_is_enabled(Info, class, path) ?
"" : " (hint: enable -Xlog:class+path=info to diagnose the failure)"; "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)";
if (RequireSharedSpaces) { if (RequireSharedSpaces) {
fail_stop("%s%s", mismatch_msg, hint_msg); log_error(cds)("%s%s", mismatch_msg, hint_msg);
MetaspaceShared::unrecoverable_loading_error();
} else { } else {
log_warning(cds)("%s%s", mismatch_msg, hint_msg); 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) { void FileMapInfo::seek_to_position(size_t pos) {
if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) { 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); remove(_full_path);
int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444);
if (fd < 0) { if (fd < 0) {
fail_stop("Unable to create shared archive file %s: (%s).", _full_path, log_error(cds)("Unable to create shared archive file %s: (%s).", _full_path,
os::strerror(errno)); os::strerror(errno));
MetaspaceShared::unrecoverable_writing_error();
} }
_fd = fd; _fd = fd;
_file_open = true; _file_open = true;
@ -1731,11 +1712,12 @@ size_t FileMapInfo::write_heap_regions(GrowableArray<MemRegion>* regions,
int arr_len = regions == nullptr ? 0 : regions->length(); int arr_len = regions == nullptr ? 0 : regions->length();
if (arr_len > max_num_regions) { if (arr_len > max_num_regions) {
fail_stop("Unable to write archive heap memory regions: " log_error(cds)("Unable to write archive heap memory regions: "
"number of memory regions exceeds maximum due to fragmentation. " "number of memory regions exceeds maximum due to fragmentation. "
"Please increase java heap size " "Please increase java heap size "
"(current MaxHeapSize is " SIZE_FORMAT ", InitialHeapSize is " SIZE_FORMAT ").", "(current MaxHeapSize is " SIZE_FORMAT ", InitialHeapSize is " SIZE_FORMAT ").",
MaxHeapSize, InitialHeapSize); MaxHeapSize, InitialHeapSize);
MetaspaceShared::unrecoverable_writing_error();
} }
size_t total_size = 0; 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. // If the shared archive is corrupted, close it and remove it.
close(); close();
remove(_full_path); 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; _file_offset += nbytes;
} }
@ -1810,7 +1792,7 @@ void FileMapInfo::write_bytes_aligned(const void* buffer, size_t nbytes) {
void FileMapInfo::close() { void FileMapInfo::close() {
if (_file_open) { if (_file_open) {
if (::close(_fd) < 0) { 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; _file_open = false;
_fd = -1; _fd = -1;
@ -2537,7 +2519,7 @@ void FileMapInfo::unmap_region(int i) {
void FileMapInfo::assert_mark(bool check) { void FileMapInfo::assert_mark(bool check) {
if (!check) { if (!check) {
fail_stop("Mark mismatch while restoring from shared file."); MetaspaceShared::unrecoverable_loading_error("Mark mismatch while restoring from shared file.");
} }
} }

View file

@ -482,8 +482,6 @@ public:
// Remap the shared readonly space to shared readwrite, private. // Remap the shared readonly space to shared readwrite, private.
bool remap_shared_readonly_as_readwrite(); bool remap_shared_readonly_as_readwrite();
// Errors.
static void fail_stop(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
static bool memory_mapping_failed() { static bool memory_mapping_failed() {
CDS_ONLY(return _memory_mapping_failed;) CDS_ONLY(return _memory_mapping_failed;)
NOT_CDS(return false;) NOT_CDS(return false;)

View file

@ -735,7 +735,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) {
ResourceMark rm; ResourceMark rm;
log_error(cds, heap)("Class %s not allowed in archive heap. Must be in java.base%s", log_error(cds, heap)("Class %s not allowed in archive heap. Must be in java.base%s",
ik->external_name(), extra_msg); ik->external_name(), extra_msg);
os::_exit(1); MetaspaceShared::unrecoverable_writing_error();
} }
bool KlassSubGraphInfo::is_non_early_klass(Klass* k) { 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. // these objects that are referenced (directly or indirectly) by static fields.
ResourceMark rm; ResourceMark rm;
log_error(cds, heap)("Cannot archive object of class %s", orig_obj->klass()->external_name()); 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 // 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. // object that is referenced (directly or indirectly) by static fields.
if (java_lang_Class::is_instance(orig_obj) && subgraph_info != _default_subgraph_info) { 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); 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)) { 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 // 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 // objects cannot be archived. Bail out for now. We might need to fix this in the future if
// we have a real use case. // we have a real use case.
os::_exit(1); MetaspaceShared::unrecoverable_writing_error();
} }
} }
} }

View file

@ -267,8 +267,8 @@ void MetaspaceShared::initialize_for_static_dump() {
size_t symbol_rs_size = LP64_ONLY(3 * G) NOT_LP64(128 * M); size_t symbol_rs_size = LP64_ONLY(3 * G) NOT_LP64(128 * M);
_symbol_rs = ReservedSpace(symbol_rs_size); _symbol_rs = ReservedSpace(symbol_rs_size);
if (!_symbol_rs.is_reserved()) { if (!_symbol_rs.is_reserved()) {
vm_exit_during_initialization("Unable to reserve memory for symbols", log_error(cds)("Unable to reserve memory for symbols: %ld bytes.", symbol_rs_size);
err_msg(SIZE_FORMAT " bytes.", symbol_rs_size)); MetaspaceShared::unrecoverable_writing_error();
} }
_symbol_region.init(&_symbol_rs, &_symbol_vs); _symbol_region.init(&_symbol_rs, &_symbol_vs);
} }
@ -309,7 +309,8 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename)
ResourceMark rm(current); ResourceMark rm(current);
if (utf8_length == 0x7fffffff) { if (utf8_length == 0x7fffffff) {
// buf_len will overflown 32-bit value. // 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; int buf_len = utf8_length+1;
char* utf8_buffer = NEW_RESOURCE_ARRAY(char, buf_len); 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"); "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 MetaspaceShared::exit_after_static_dump();
// (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);
} }
class CollectCLDClosure : public CLDClosure { class CollectCLDClosure : public CLDClosure {
@ -677,12 +675,13 @@ void MetaspaceShared::preload_and_dump() {
preload_and_dump_impl(THREAD); preload_and_dump_impl(THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { 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 = " log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
SIZE_FORMAT "M", MaxHeapSize/M)); SIZE_FORMAT "M", MaxHeapSize/M);
MetaspaceShared::unrecoverable_writing_error();
} else { } else {
log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); 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 { } else {
// On success, the VM_PopulateDumpSharedSpace op should have // 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() { void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled"); assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled");
MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE; MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
@ -950,9 +980,9 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
DynamicDumpSharedSpaces = false; DynamicDumpSharedSpaces = false;
log_info(cds)("Unable to map shared spaces"); log_info(cds)("Unable to map shared spaces");
if (PrintSharedArchiveAndExit) { if (PrintSharedArchiveAndExit) {
vm_exit_during_initialization("Unable to use shared archive."); MetaspaceShared::unrecoverable_loading_error("Unable to use shared archive.");
} else if (RequireSharedSpaces) { } 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; delete dynamic_mapinfo;
} }
if (RequireSharedSpaces && has_failed) { 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()) { if (!mapinfo->initialize()) {
delete(mapinfo); delete(mapinfo);
if (RequireSharedSpaces) { if (RequireSharedSpaces) {
FileMapInfo::fail_stop("Failed to initialize dynamic archive"); MetaspaceShared::unrecoverable_loading_error("Failed to initialize dynamic archive");
} }
return nullptr; return nullptr;
} }

View file

@ -116,6 +116,10 @@ public:
static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false); 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; static void serialize(SerializeClosure* sc) NOT_CDS_RETURN;
// JVM/TI RedefineClasses() support: // JVM/TI RedefineClasses() support:

View file

@ -797,7 +797,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) {
// refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern
// but bail out for safety. // but bail out for safety.
log_error(cds)("Too many strings to be archived: " SIZE_FORMAT, _items_count); 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); objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK);