From 3e93e0b809f2c6cb4a466af92ec678cbc82863e4 Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Wed, 8 Dec 2021 16:20:39 +0000 Subject: [PATCH] 8276769: -Xshare:auto should tolerate problems in the CDS archive Reviewed-by: iklam, ccheung --- src/hotspot/share/cds/filemap.cpp | 228 +++++++++++------- src/hotspot/share/include/cds.h | 4 +- src/hotspot/share/runtime/arguments.cpp | 37 ++- src/hotspot/share/runtime/arguments.hpp | 2 +- .../cds/appcds/SharedArchiveConsistency.java | 16 +- .../dynamicArchive/ArchiveConsistency.java | 101 +++++--- .../DynamicArchiveTestBase.java | 6 +- 7 files changed, 259 insertions(+), 135 deletions(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 72a0d35bca72d..89a4d90d2570e 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -121,7 +121,6 @@ void FileMapInfo::fail_continue(const char *msg, ...) { fail_exit(msg, ap); } else { if (log_is_enabled(Info, cds)) { - ResourceMark rm; LogStream ls(Log(cds)::info()); ls.print("UseSharedSpaces: "); ls.vprint_cr(msg, ap); @@ -1042,15 +1041,20 @@ void FileMapInfo::validate_non_existent_class_paths() { } } -// a utility class for checking file header +// A utility class for reading/validating the GenericCDSFileMapHeader portion of +// a CDS archive's header. The file header of all CDS archives with versions from +// CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12) are guaranteed to always start +// with GenericCDSFileMapHeader. This makes it possible to read important information +// from a CDS archive created by a different version of HotSpot, so that we can +// automatically regenerate the archive as necessary (JDK-8261455). class FileHeaderHelper { int _fd; - GenericCDSFileMapHeader _header; + bool _is_valid; + GenericCDSFileMapHeader* _header; + const char* _base_archive_name; public: - FileHeaderHelper() { - _fd = -1; - } + FileHeaderHelper() : _fd(-1), _is_valid(false), _header(nullptr), _base_archive_name(nullptr) {} ~FileHeaderHelper() { if (_fd != -1) { @@ -1059,8 +1063,10 @@ class FileHeaderHelper { } bool initialize(const char* archive_name) { + log_info(cds)("Opening shared archive: %s", archive_name); _fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); if (_fd < 0) { + FileMapInfo::fail_continue("Specified shared archive not found (%s)", archive_name); return false; } return initialize(_fd); @@ -1069,117 +1075,185 @@ class FileHeaderHelper { // for an already opened file, do not set _fd bool initialize(int fd) { assert(fd != -1, "Archive should be opened"); + + + // First read the generic header so we know the exact size of the actual header. + GenericCDSFileMapHeader gen_header; size_t size = sizeof(GenericCDSFileMapHeader); lseek(fd, 0, SEEK_SET); - size_t n = os::read(fd, (void*)&_header, (unsigned int)size); + size_t n = os::read(fd, (void*)&gen_header, (unsigned int)size); if (n != size) { - vm_exit_during_initialization("Unable to read generic CDS file map header from shared archive"); + FileMapInfo::fail_continue("Unable to read generic CDS file map header from shared archive"); return false; } + + if (gen_header._magic != CDS_ARCHIVE_MAGIC && + gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { + FileMapInfo::fail_continue("The shared archive file has a bad magic number: %#x", gen_header._magic); + return false; + } + + if (gen_header._version < CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) { + FileMapInfo::fail_continue("Cannot handle shared archive file version %d. Must be at least %d", + gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION); + return false; + } + + size_t filelen = os::lseek(fd, 0, SEEK_END); + if (gen_header._header_size >= filelen) { + FileMapInfo::fail_continue("Archive file header larger than archive file"); + return false; + } + + // Read the actual header and perform more checks + size = gen_header._header_size; + _header = (GenericCDSFileMapHeader*)NEW_C_HEAP_ARRAY(char, size, mtInternal); + lseek(fd, 0, SEEK_SET); + n = os::read(fd, (void*)_header, (unsigned int)size); + if (n != size) { + FileMapInfo::fail_continue("Unable to read actual CDS file map header from shared archive"); + return false; + } + + if (!check_crc()) { + return false; + } + + if (!check_and_init_base_archive_name()) { + return false; + } + + // All fields in the GenericCDSFileMapHeader has been validated. + _is_valid = true; return true; } GenericCDSFileMapHeader* get_generic_file_header() { - return &_header; - } - - char* read_base_archive_name() { - assert(_fd != -1, "Archive should be open"); - size_t name_size = _header._base_archive_name_size; - assert(name_size != 0, "For non-default base archive, name size should be non-zero!"); - char* base_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal); - lseek(_fd, _header._base_archive_name_offset, SEEK_SET); // position to correct offset. - size_t n = os::read(_fd, base_name, (unsigned int)name_size); - if (n != name_size) { - log_info(cds)("Unable to read base archive name from archive"); - FREE_C_HEAP_ARRAY(char, base_name); - return nullptr; + assert(_header != nullptr && _is_valid, "must be a valid archive file"); + return _header; + } + + const char* base_archive_name() { + assert(_header != nullptr && _is_valid, "must be a valid archive file"); + return _base_archive_name; + } + + private: + bool check_crc() { + if (VerifySharedSpaces) { + FileMapHeader* header = (FileMapHeader*)_header; + int actual_crc = header->compute_crc(); + if (actual_crc != header->crc()) { + log_info(cds)("_crc expected: %d", header->crc()); + log_info(cds)(" actual: %d", actual_crc); + FileMapInfo::fail_continue("Header checksum verification failed."); + return false; + } } - if (base_name[name_size - 1] != '\0' || strlen(base_name) != name_size - 1) { - log_info(cds)("Base archive name is damaged"); - FREE_C_HEAP_ARRAY(char, base_name); - return nullptr; + return true; + } + + bool check_and_init_base_archive_name() { + unsigned int name_offset = _header->_base_archive_name_offset; + unsigned int name_size = _header->_base_archive_name_size; + unsigned int header_size = _header->_header_size; + + if (name_offset + name_size < name_offset) { + FileMapInfo::fail_continue("base_archive_name offset/size overflow: " UINT32_FORMAT "/" UINT32_FORMAT, + name_offset, name_size); + return false; } - if (!os::file_exists(base_name)) { - log_info(cds)("Base archive %s does not exist", base_name); - FREE_C_HEAP_ARRAY(char, base_name); - return nullptr; + if (_header->_magic == CDS_ARCHIVE_MAGIC) { + if (name_offset != 0) { + FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_offset"); + return false; + } + if (name_size != 0) { + FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_size"); + return false; + } + } else { + assert(_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC, "must be"); + if ((name_size == 0 && name_offset != 0) || + (name_size != 0 && name_offset == 0)) { + // If either is zero, both must be zero. This indicates that we are using the default base archive. + FileMapInfo::fail_continue("Invalid base_archive_name offset/size: " UINT32_FORMAT "/" UINT32_FORMAT, + name_offset, name_size); + return false; + } + if (name_size > 0) { + if (name_offset + name_size > header_size) { + FileMapInfo::fail_continue("Invalid base_archive_name offset/size (out of range): " + UINT32_FORMAT " + " UINT32_FORMAT " > " UINT32_FORMAT , + name_offset, name_size, header_size); + return false; + } + const char* name = ((const char*)_header) + _header->_base_archive_name_offset; + if (name[name_size - 1] != '\0' || strlen(name) != name_size - 1) { + FileMapInfo::fail_continue("Base archive name is damaged"); + return false; + } + if (!os::file_exists(name)) { + FileMapInfo::fail_continue("Base archive %s does not exist", name); + return false; + } + _base_archive_name = name; + } } - return base_name; + return true; } }; bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { FileHeaderHelper file_helper; if (!file_helper.initialize(archive_name)) { - // do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths() - // requires a shared archive name. The open_for_read() function will log a message regarding - // failure in opening a shared archive. + // Any errors are reported by fail_continue(). return false; } GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); if (is_static) { if (header->_magic != CDS_ARCHIVE_MAGIC) { - vm_exit_during_initialization("Not a base shared archive", archive_name); - return false; - } - if (header->_base_archive_name_offset != 0) { - log_info(cds)("_base_archive_name_offset should be 0"); - log_info(cds)("_base_archive_name_offset = " UINT32_FORMAT, header->_base_archive_name_offset); + fail_continue("Not a base shared archive: %s", archive_name); return false; } } else { if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { - vm_exit_during_initialization("Not a top shared archive", archive_name); + fail_continue("Not a top shared archive: %s", archive_name); return false; } - unsigned int name_size = header->_base_archive_name_size; - unsigned int name_offset = header->_base_archive_name_offset; - unsigned int header_size = header->_header_size; - if (name_offset + name_size != header_size) { - log_info(cds)("_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size"); - log_info(cds)(" _base_archive_name_size = " UINT32_FORMAT, name_size); - log_info(cds)(" _base_archive_name_offset = " UINT32_FORMAT, name_offset); - log_info(cds)(" _header_size = " UINT32_FORMAT, header_size); - return false; - } - char* base_name = file_helper.read_base_archive_name(); - if (base_name == nullptr) { - return false; - } - FREE_C_HEAP_ARRAY(char, base_name); } return true; } +// Return value: +// false: +// is not a valid archive. *base_archive_name is set to null. +// true && (*base_archive_name) == NULL: +// is a valid static archive. +// true && (*base_archive_name) != NULL: +// is a valid dynamic archive. bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, char** base_archive_name) { FileHeaderHelper file_helper; + *base_archive_name = NULL; + if (!file_helper.initialize(archive_name)) { return false; } GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { - // Not a dynamic header, no need to proceed further. - return false; + assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be"); + return true; } - if ((header->_base_archive_name_size == 0 && header->_base_archive_name_offset != 0) || - (header->_base_archive_name_size != 0 && header->_base_archive_name_offset == 0)) { - fail_continue("Default base archive not set correct"); - return false; - } - if (header->_base_archive_name_size == 0 && - header->_base_archive_name_offset == 0) { + const char* base = file_helper.base_archive_name(); + if (base == nullptr) { *base_archive_name = Arguments::get_default_shared_archive_path(); } else { - // read the base archive name - *base_archive_name = file_helper.read_base_archive_name(); - if (*base_archive_name == nullptr) { - return false; - } + *base_archive_name = os::strdup_check_oom(base); } + return true; } @@ -1247,16 +1321,6 @@ bool FileMapInfo::init_from_file(int fd) { return false; } - if (VerifySharedSpaces) { - int expected_crc = header()->compute_crc(); - if (expected_crc != header()->crc()) { - log_info(cds)("_crc expected: %d", expected_crc); - log_info(cds)(" actual: %d", header()->crc()); - FileMapInfo::fail_continue("Header checksum verification failed."); - return false; - } - } - _file_offset = header()->header_size(); // accounts for the size of _base_archive_name if (is_static()) { @@ -1294,9 +1358,9 @@ bool FileMapInfo::open_for_read() { int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0); if (fd < 0) { if (errno == ENOENT) { - fail_continue("Specified shared archive not found (%s).", _full_path); + fail_continue("Specified shared archive not found (%s)", _full_path); } else { - fail_continue("Failed to open shared archive file (%s).", + fail_continue("Failed to open shared archive file (%s)", os::strerror(errno)); } return false; diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index eeb45ba34c4d7..476f84c34dffb 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -38,6 +38,7 @@ #define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 +#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 12 #define CURRENT_CDS_ARCHIVE_VERSION 12 typedef struct CDSFileMapRegion { @@ -59,7 +60,8 @@ typedef struct CDSFileMapRegion { char* _mapped_base; // Actually mapped address (NULL if this region is not mapped). } CDSFileMapRegion; -// This portion of the archive file header must remain unchanged for _version >= 12. +// This portion of the archive file header must remain unchanged for +// _version >= CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12). // This makes it possible to read important information from a CDS archive created by // a different version of HotSpot, so that we can automatically regenerate the archive as necessary. typedef struct GenericCDSFileMapHeader { diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index adfe1a1fb6a46..fe54fd3cb29d3 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3449,7 +3449,7 @@ jint Arguments::parse_options_buffer(const char* name, char* buffer, const size_ return vm_args->set_args(&options); } -jint Arguments::set_shared_spaces_flags_and_archive_paths() { +void Arguments::set_shared_spaces_flags_and_archive_paths() { if (DumpSharedSpaces) { if (RequireSharedSpaces) { warning("Cannot dump shared archive while using shared archive"); @@ -3459,9 +3459,12 @@ jint Arguments::set_shared_spaces_flags_and_archive_paths() { #if INCLUDE_CDS // Initialize shared archive paths which could include both base and dynamic archive paths // This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly. - init_shared_archive_paths(); + // + // UseSharedSpaces may be disabled if -XX:SharedArchiveFile is invalid. + if (DumpSharedSpaces || UseSharedSpaces) { + init_shared_archive_paths(); + } #endif // INCLUDE_CDS - return JNI_OK; } #if INCLUDE_CDS @@ -3510,7 +3513,9 @@ void Arguments::extract_shared_archive_paths(const char* archive_path, char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); strncpy(cur_path, begin_ptr, len); cur_path[len] = '\0'; - FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/); + if (!FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/)) { + return; + } *base_archive_path = cur_path; begin_ptr = ++end_ptr; @@ -3522,7 +3527,9 @@ void Arguments::extract_shared_archive_paths(const char* archive_path, len = end_ptr - begin_ptr; cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); strncpy(cur_path, begin_ptr, len + 1); - FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/); + if (!FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/)) { + return; + } *top_archive_path = cur_path; } @@ -3566,17 +3573,26 @@ void Arguments::init_shared_archive_paths() { "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option"); } if (archives == 1) { - char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments); + char* base_archive_path = NULL; bool success = - FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &SharedArchivePath); + FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path); if (!success) { - SharedArchivePath = temp_archive_path; + no_shared_spaces("invalid archive"); + } else if (base_archive_path == NULL) { + // User has specified a single archive, which is a static archive. + SharedArchivePath = const_cast(SharedArchiveFile); } else { - SharedDynamicArchivePath = temp_archive_path; + // User has specified a single archive, which is a dynamic archive. + SharedDynamicArchivePath = const_cast(SharedArchiveFile); + SharedArchivePath = base_archive_path; // has been c-heap allocated. } } else { extract_shared_archive_paths((const char*)SharedArchiveFile, &SharedArchivePath, &SharedDynamicArchivePath); + if (SharedArchivePath == NULL) { + assert(SharedDynamicArchivePath == NULL, "must be"); + no_shared_spaces("invalid archive"); + } } if (SharedDynamicArchivePath != nullptr) { @@ -4049,8 +4065,7 @@ jint Arguments::apply_ergo() { GCConfig::arguments()->initialize(); - result = set_shared_spaces_flags_and_archive_paths(); - if (result != JNI_OK) return result; + set_shared_spaces_flags_and_archive_paths(); // Initialize Metaspace flags and alignments Metaspace::ergo_initialize(); diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 0867f5c5c4d9c..40b9308c82b11 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -366,7 +366,7 @@ class Arguments : AllStatic { static void set_use_compressed_oops(); static void set_use_compressed_klass_ptrs(); static jint set_ergonomics_flags(); - static jint set_shared_spaces_flags_and_archive_paths(); + static void set_shared_spaces_flags_and_archive_paths(); // Limits the given heap size by the maximum amount of virtual // memory this process is currently allowed to use. It also takes // the virtual-to-physical ratio of the current GC into account. diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index 57086f343b375..aee023198f5b0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java @@ -112,7 +112,8 @@ public static void main(String... args) throws Exception { // test, should pass System.out.println("1. Normal, should pass but may fail\n"); - String[] execArgs = {"-Xlog:cds=debug", "-cp", jarFile, "Hello"}; + // disable VerifySharedSpaces, it may be turned on by jtreg args + String[] execArgs = {"-Xlog:cds=debug", "-XX:-VerifySharedSpaces", "-cp", jarFile, "Hello"}; // tests that corrupt contents of the archive need to run with // VerifySharedSpaces enabled to detect inconsistencies String[] verifyExecArgs = {"-Xlog:cds", "-XX:+VerifySharedSpaces", "-cp", jarFile, "Hello"}; @@ -172,7 +173,7 @@ public static void main(String... args) throws Exception { System.out.println("\n2d. Corrupt _version, should fail\n"); String modVersion = startNewArchive("modify-version"); copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion); - CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x3FFFFFFF); output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has the wrong version"); output.shouldNotContain("Checksum verification failed"); @@ -180,6 +181,17 @@ public static void main(String... args) throws Exception { output.shouldContain(HELLO_WORLD); } + System.out.println("\n2e. Corrupt _version, should fail\n"); + String modVersion2 = startNewArchive("modify-version2"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion2); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000); + output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); + output.shouldContain("Cannot handle shared archive file version 0. Must be at least 12"); + output.shouldNotContain("Checksum verification failed"); + if (shareAuto) { + output.shouldContain(HELLO_WORLD); + } + // modify content inside regions System.out.println("\n3. Corrupt Content, should fail\n"); for (int i=0; i { for (String s : checkMessages) { output.shouldContain(s); } + output.shouldContain(HELLO_WORLD); }); } else { result.assertAbnormalExit( output -> { for (String s : checkMessages) { output.shouldContain(s); } + output.shouldContain("Unable to use shared archive"); }); } } + private static void startTest(String str) { + System.out.println("\n" + str); + } + private static void doTest(String baseArchiveName, String topArchiveName) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello.jar"); String mainClass = "Hello"; @@ -94,42 +110,36 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws throw new IOException(jsa + " does not exist!"); } - // 1. Modify the CRC values in the header of the top archive. - System.out.println("\n1. Modify the CRC values in the header of the top archive"); + startTest("1. Modify the CRC values in the header of the top archive"); String modTop = getNewArchiveName("modTopRegionsCrc"); File copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, modTop); CDSArchiveUtils.modifyAllRegionsCrc(copiedJsa); + VERIFY_CRC = true; runTwo(baseArchiveName, modTop, - appJar, mainClass, 1, - new String[] {"Header checksum verification failed", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Header checksum verification failed"); + VERIFY_CRC = false; - // 2. Make header size larger than the archive size - System.out.println("\n2. Make header size larger than the archive size"); + startTest("2. Make header size larger than the archive size"); String largerHeaderSize = getNewArchiveName("largerHeaderSize"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, largerHeaderSize); CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetHeaderSize(), (int)copiedJsa.length() + 1024); runTwo(baseArchiveName, largerHeaderSize, - appJar, mainClass, 1, - new String[] {"_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Archive file header larger than archive file"); - // 3. Make base archive path offset beyond of header size - System.out.println("\n3. Make base archive path offset beyond of header size."); + startTest("3. Make base archive name offset beyond of header size."); String wrongBaseArchiveNameOffset = getNewArchiveName("wrongBaseArchiveNameOffset"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseArchiveNameOffset); int fileHeaderSize = (int)CDSArchiveUtils.fileHeaderSize(copiedJsa); int baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetBaseArchiveNameOffset(), baseArchiveNameOffset + 1024); runTwo(baseArchiveName, wrongBaseArchiveNameOffset, - appJar, mainClass, 1, - new String[] {"_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size", - "The shared archive file has an incorrect header size", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Invalid base_archive_name offset/size (out of range)"); - // 4. Make base archive path offset points to middle of name size - System.out.println("\n4. Make base archive path offset points to middle of name size"); + startTest("4. Make base archive name offset points to middle of the base archive name"); String wrongBaseNameOffset = getNewArchiveName("wrongBaseNameOffset"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseNameOffset); int baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa); @@ -137,13 +147,10 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws CDSArchiveUtils.modifyHeaderIntField(copiedJsa, baseArchiveNameOffset, baseArchiveNameOffset + baseArchiveNameSize/2); runTwo(baseArchiveName, wrongBaseNameOffset, - appJar, mainClass, 1, - new String[] {"An error has occurred while processing the shared archive file.", - "Header checksum verification failed", - "Unable to use shared archive"}); + appJar, mainClass, isAuto ? 0 : 1, + "Base archive name is damaged"); - // 5. Make base archive name not terminated with '\0' - System.out.println("\n5. Make base archive name not terminated with '\0'"); + startTest("5. Make base archive name not terminated with '\0'"); String wrongBaseName = getNewArchiveName("wrongBaseName"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName); baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); @@ -152,12 +159,10 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws CDSArchiveUtils.writeData(copiedJsa, offset, new byte[] {(byte)'X'}); runTwo(baseArchiveName, wrongBaseName, - appJar, mainClass, 1, - new String[] {"Base archive name is damaged", - "Header checksum verification failed"}); + appJar, mainClass, isAuto ? 0 : 1, + "Base archive name is damaged"); - // 6. Modify base archive name to a file that doesn't exist. - System.out.println("\n6. Modify base archive name to a file that doesn't exist"); + startTest("6. Modify base archive name to a file that doesn't exist"); String wrongBaseName2 = getNewArchiveName("wrongBaseName2"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName2); baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); @@ -170,8 +175,32 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws (new File(badName)).delete(); runTwo(baseArchiveName, wrongBaseName2, - appJar, mainClass, 1, - new String[] {"Base archive " + badName + " does not exist", - "Header checksum verification failed"}); + appJar, mainClass, isAuto ? 0 : 1, + "Base archive " + badName + " does not exist"); + + // Following three tests: + // -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa + // -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa + // -XX:SharedArchiveFile=non-exist-base.jsa:non-exist-top.jsa + startTest("7. Non-exist base archive"); + String nonExistBase = "non-exist-base.jsa"; + File nonExistBaseFile = new File(nonExistBase); + nonExistBaseFile.delete(); + runTwo(nonExistBase, topArchiveName, + appJar, mainClass, isAuto ? 0 : 1, + "Specified shared archive not found (" + nonExistBase + ")"); + + startTest("8. Non-exist top archive"); + String nonExistTop = "non-exist-top.jsa"; + File nonExistTopFile = new File(nonExistTop); + nonExistTopFile.delete(); + runTwo(baseArchiveName, nonExistTop, + appJar, mainClass, isAuto ? 0 : 1, + "Specified shared archive not found (" + nonExistTop + ")"); + + startTest("9. nost-exist-base and non-exist-top"); + runTwo(nonExistBase, nonExistTop, + appJar, mainClass, isAuto ? 0 : 1, + "Specified shared archive not found (" + nonExistBase + ")"); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java index b61894c1b4bad..b46eb7ea35a01 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java @@ -36,6 +36,7 @@ */ class DynamicArchiveTestBase { private static boolean executedIn_run = false; + private static boolean autoMode = false; // -Xshare:auto private static final WhiteBox WB = WhiteBox.getWhiteBox(); @@ -47,6 +48,7 @@ public static interface DynamicArchiveTestWithArgs { public void run(String args[]) throws Exception; } + public static void setAutoMode(boolean val) { autoMode = val; } /* * Tests for dynamic archives should be written using this pattern: @@ -183,7 +185,7 @@ public static Result run2(String baseArchiveName, String topArchiveName, String (topArchiveName == null) ? baseArchiveName : baseArchiveName + File.pathSeparator + topArchiveName; String[] cmdLine = TestCommon.concat( - "-Xshare:on", + autoMode ? "-Xshare:auto" : "-Xshare:on", "-XX:SharedArchiveFile=" + archiveFiles); cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix); return execProcess("exec", null, cmdLine); @@ -202,7 +204,7 @@ public static Result runWithRelativePath(String baseArchiveName, String topArchi (topArchiveName == null) ? baseArchiveName : baseArchiveName + File.pathSeparator + topArchiveName; String[] cmdLine = TestCommon.concat( - "-Xshare:on", + autoMode ? "-Xshare:auto" : "-Xshare:on", "-XX:SharedArchiveFile=" + archiveFiles); cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix); return execProcess("exec", jarDir, cmdLine);