--- old/src/hotspot/share/classfile/classLoader.cpp 2019-08-22 08:26:22.293313543 -0700 +++ new/src/hotspot/share/classfile/classLoader.cpp 2019-08-22 08:26:22.053304903 -0700 @@ -72,9 +72,6 @@ #include "utilities/events.hpp" #include "utilities/hashtable.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_CDS -#include "classfile/sharedPathsMiscInfo.hpp" -#endif // Entry points in zip.dll for loading zip/jar file entries @@ -146,7 +143,6 @@ ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL; ClassPathEntry* ClassLoader::_module_path_entries = NULL; ClassPathEntry* ClassLoader::_last_module_path_entry = NULL; -SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; #endif // helper routines @@ -284,13 +280,12 @@ return pkgEntryTable->lookup_only(pkg_symbol); } -ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() { - char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass); - strcpy(copy, dir); - _dir = copy; +const char* ClassPathEntry::copy_path(const char* path) { + char* copy = NEW_C_HEAP_ARRAY(char, strlen(path)+1, mtClass); + strcpy(copy, path); + return copy; } - ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { // construct full path name assert((_dir != NULL) && (name != NULL), "sanity"); @@ -330,9 +325,7 @@ ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append, bool from_class_path_attr) : ClassPathEntry() { _zip = zip; - char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass); - strcpy(copy, zip_name); - _zip_name = copy; + _zip_name = copy_path(zip_name); _from_class_path_attr = from_class_path_attr; } @@ -417,8 +410,7 @@ assert(_singleton == NULL, "VM supports only one jimage"); DEBUG_ONLY(_singleton = this); size_t len = strlen(name) + 1; - _name = NEW_C_HEAP_ARRAY(const char, len, mtClass); - strncpy((char *)_name, name, len); + _name = copy_path(name); } ClassPathImageEntry::~ClassPathImageEntry() { @@ -571,30 +563,10 @@ } else { trace_class_path("bootstrap loader class path=", sys_class_path); } -#if INCLUDE_CDS - if (DumpSharedSpaces || DynamicDumpSharedSpaces) { - _shared_paths_misc_info->add_boot_classpath(sys_class_path); - } -#endif setup_boot_search_path(sys_class_path); } #if INCLUDE_CDS -int ClassLoader::get_shared_paths_misc_info_size() { - return _shared_paths_misc_info->get_used_bytes(); -} - -void* ClassLoader::get_shared_paths_misc_info() { - return _shared_paths_misc_info->buffer(); -} - -bool ClassLoader::check_shared_paths_misc_info(void *buf, int size, bool is_static) { - SharedPathsMiscInfo* checker = new SharedPathsMiscInfo((char*)buf, size); - bool result = checker->check(is_static); - delete checker; - return result; -} - void ClassLoader::setup_app_search_path(const char *class_path) { assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity"); @@ -977,11 +949,6 @@ } return true; } else { -#if INCLUDE_CDS - if (DumpSharedSpaces || DynamicDumpSharedSpaces) { - _shared_paths_misc_info->add_nonexist_path(path); - } -#endif return false; } } @@ -1601,12 +1568,7 @@ load_zip_library(); // lookup jimage library entry points load_jimage_library(); -#if INCLUDE_CDS - // initialize search path - if (DumpSharedSpaces || DynamicDumpSharedSpaces) { - _shared_paths_misc_info = new SharedPathsMiscInfo(); - } -#endif + setup_bootstrap_search_path(); } @@ -1614,7 +1576,6 @@ void ClassLoader::initialize_shared_path() { if (DumpSharedSpaces || DynamicDumpSharedSpaces) { ClassLoaderExt::setup_search_paths(); - _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check() } } --- old/src/hotspot/share/classfile/classLoader.hpp 2019-08-22 08:26:22.933336580 -0700 +++ new/src/hotspot/share/classfile/classLoader.hpp 2019-08-22 08:26:22.697328085 -0700 @@ -47,17 +47,19 @@ class ClassPathEntry : public CHeapObj { private: ClassPathEntry* volatile _next; +protected: + const char* copy_path(const char*path); public: ClassPathEntry* next() const; virtual ~ClassPathEntry() {} void set_next(ClassPathEntry* next); - virtual bool is_modules_image() const = 0; - virtual bool is_jar_file() const = 0; + virtual bool is_modules_image() const { return false; } + virtual bool is_jar_file() const { return false; } // Is this entry created from the "Class-path" attribute from a JAR Manifest? - virtual bool from_class_path_attr() const = 0; + virtual bool from_class_path_attr() const { return false; } virtual const char* name() const = 0; - virtual JImageFile* jimage() const = 0; - virtual void close_jimage() = 0; + virtual JImageFile* jimage() const { return NULL; } + virtual void close_jimage() {} // Constructor ClassPathEntry() : _next(NULL) {} // Attempt to locate file_name through this class path entry. @@ -73,18 +75,14 @@ private: const char* _dir; // Name of directory public: - bool is_modules_image() const { return false; } - bool is_jar_file() const { return false; } - bool from_class_path_attr() const { return false; } const char* name() const { return _dir; } - JImageFile* jimage() const { return NULL; } - void close_jimage() {} - ClassPathDirEntry(const char* dir); + ClassPathDirEntry(const char* dir) { + _dir = copy_path(dir); + } virtual ~ClassPathDirEntry() {} ClassFileStream* open_stream(const char* name, TRAPS); }; - // Type definitions for zip file and zip file entry typedef void* jzfile; typedef struct { @@ -104,12 +102,9 @@ const char* _zip_name; // Name of zip archive bool _from_class_path_attr; // From the "Class-path" attribute of a jar file public: - bool is_modules_image() const { return false; } bool is_jar_file() const { return true; } bool from_class_path_attr() const { return _from_class_path_attr; } const char* name() const { return _zip_name; } - JImageFile* jimage() const { return NULL; } - void close_jimage() {} ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append, bool from_class_path_attr); virtual ~ClassPathZipEntry(); u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS); @@ -126,8 +121,6 @@ DEBUG_ONLY(static ClassPathImageEntry* _singleton;) public: bool is_modules_image() const; - bool is_jar_file() const { return false; } - bool from_class_path_attr() const { return false; } bool is_open() const { return _jimage != NULL; } const char* name() const { return _name == NULL ? "" : _name; } JImageFile* jimage() const { return _jimage; } @@ -156,8 +149,6 @@ void add_to_list(ClassPathEntry* new_entry); }; -class SharedPathsMiscInfo; - class ClassLoader: AllStatic { public: enum ClassLoaderType { @@ -230,8 +221,6 @@ static ClassPathEntry* _last_append_entry; // Info used by CDS - CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;) - CDS_ONLY(static ClassPathEntry* _app_classpath_entries;) CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;) CDS_ONLY(static ClassPathEntry* _module_path_entries;) @@ -416,10 +405,6 @@ } return num_entries; } - static void finalize_shared_paths_misc_info(); - static int get_shared_paths_misc_info_size(); - static void* get_shared_paths_misc_info(); - static bool check_shared_paths_misc_info(void* info, int size, bool is_static); static void exit_with_path_failure(const char* error, const char* message); static char* skip_uri_protocol(char* source); static void record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS); --- old/src/hotspot/share/classfile/classLoaderExt.cpp 2019-08-22 08:26:23.561359185 -0700 +++ new/src/hotspot/share/classfile/classLoaderExt.cpp 2019-08-22 08:26:23.325350691 -0700 @@ -30,7 +30,6 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/klassFactory.hpp" #include "classfile/modules.hpp" -#include "classfile/sharedPathsMiscInfo.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmSymbols.hpp" #include "memory/allocation.inline.hpp" @@ -74,7 +73,6 @@ trace_class_path("app loader class path (skipped)=", app_class_path); } else { trace_class_path("app loader class path=", app_class_path); - shared_paths_misc_info()->add_app_classpath(app_class_path); ClassLoader::setup_app_search_path(app_class_path); } } @@ -222,7 +220,6 @@ } void ClassLoaderExt::setup_search_paths() { - shared_paths_misc_info()->record_app_offset(); ClassLoaderExt::setup_app_search_path(); } @@ -248,12 +245,6 @@ result->set_class_loader_type(classloader_type); } -void ClassLoaderExt::finalize_shared_paths_misc_info() { - if (!_has_app_classes) { - shared_paths_misc_info()->pop_app(); - } -} - // Load the class of the given name from the location given by path. The path is specified by // the "source:" in the class list file (see classListParser.cpp), and can be a directory or // a JAR file. --- old/src/hotspot/share/classfile/classLoaderExt.hpp 2019-08-22 08:26:24.185381647 -0700 +++ new/src/hotspot/share/classfile/classLoaderExt.hpp 2019-08-22 08:26:23.949373152 -0700 @@ -47,9 +47,6 @@ static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size); static void setup_app_search_path(); // Only when -Xshare:dump static void process_module_table(ModuleEntryTable* met, TRAPS); - static SharedPathsMiscInfo* shared_paths_misc_info() { - return (SharedPathsMiscInfo*)_shared_paths_misc_info; - } // index of first app JAR in shared classpath entry table static jshort _app_class_paths_start_index; // index of first modular JAR in shared modulepath entry table @@ -84,8 +81,6 @@ return read_manifest(entry, manifest_size, false, THREAD); } - static void finalize_shared_paths_misc_info(); - static jshort app_class_paths_start_index() { return _app_class_paths_start_index; } static jshort app_module_paths_start_index() { return _app_module_paths_start_index; } --- old/src/hotspot/share/include/cds.h 2019-08-22 08:26:24.965409725 -0700 +++ new/src/hotspot/share/include/cds.h 2019-08-22 08:26:24.725401085 -0700 @@ -36,7 +36,7 @@ #define NUM_CDS_REGIONS 8 // this must be the same as MetaspaceShared::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 -#define CURRENT_CDS_ARCHIVE_VERSION 6 +#define CURRENT_CDS_ARCHIVE_VERSION 7 #define INVALID_CDS_ARCHIVE_VERSION -1 struct CDSFileMapRegion { --- old/src/hotspot/share/memory/filemap.cpp 2019-08-22 08:26:25.741437657 -0700 +++ new/src/hotspot/share/memory/filemap.cpp 2019-08-22 08:26:25.501429018 -0700 @@ -240,7 +240,6 @@ // JVM version string ... changes on each build. get_header_version(_jvm_ident); - ClassLoaderExt::finalize_shared_paths_misc_info(); _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index(); _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index(); _num_module_paths = ClassLoader::num_module_path_entries(); @@ -287,26 +286,31 @@ FileMapInfo::fail_stop("Unable to open file %s.", cpe->name()); } - size_t len = strlen(cpe->name()) + 1; + // No need to save the name of the module file, as it will be computed at run time + // to allow relocation of the JDK directory. + const char* name = is_modules_image ? "" : cpe->name(); + size_t len = strlen(name) + 1; _name = MetadataFactory::new_array(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD); - strcpy(_name->data(), cpe->name()); + strcpy(_name->data(), name); +} + +const char* SharedClassPathEntry::name() const { + if (UseSharedSpaces && is_modules_image()) { + // In order to validate the runtime modules image file size against the archived + // size information, we need to obtain the runtime modules image path. The recorded + // dump time modules image path in the archive may be different from the runtime path + // if the JDK image has beed moved after generating the archive. + return ClassLoader::get_jrt_entry()->name(); + } else { + return _name->data(); + } } bool SharedClassPathEntry::validate(bool is_class_path) { assert(UseSharedSpaces, "runtime only"); struct stat st; - const char* name; - - // In order to validate the runtime modules image file size against the archived - // size information, we need to obtain the runtime modules image path. The recorded - // dump time modules image path in the archive may be different from the runtime path - // if the JDK image has beed moved after generating the archive. - if (is_modules_image()) { - name = ClassLoader::get_jrt_entry()->name(); - } else { - name = this->name(); - } + const char* name = this->name(); bool ok = true; log_info(class, path)("checking shared classpath entry: %s", name); @@ -414,7 +418,7 @@ // 3. module path ClassPathEntry *mpe = ClassLoader::module_path_entries(); while (mpe != NULL) { - log_info(class, path)("add module path %s",mpe->name()); + log_info(class, path)("add module path %s", mpe->name()); SharedClassPathEntry* ent = shared_path(i); ent->init(false, mpe, THREAD); EXCEPTION_MARK; @@ -704,6 +708,20 @@ return true; } +void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) { + LogTarget(Info, class, path) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print("%s", msg); + const char* prefix = ""; + for (int i = start_idx; i < end_idx; i++) { + ls.print("%s%s", prefix, shared_path(i)->name()); + prefix = os::path_separator(); + } + ls.cr(); + } +} + bool FileMapInfo::validate_shared_path_table() { assert(UseSharedSpaces, "runtime only"); @@ -732,6 +750,9 @@ } } + log_paths("Expecting BOOT path=", 0, _header->_app_class_paths_start_index); + log_paths("Expecting -Djava.class.path=", _header->_app_class_paths_start_index, _header->_app_module_paths_start_index); + int module_paths_start_index = _header->_app_module_paths_start_index; int shared_app_paths_len = 0; @@ -855,9 +876,6 @@ if (dynamic_header->_base_archive_is_default) { *base_archive_name = Arguments::get_default_shared_archive_path(); } else { - // skip over the _paths_misc_info - sz = dynamic_header->_paths_misc_info_size; - lseek(fd, (long)sz, SEEK_CUR); // read the base archive name size_t name_size = dynamic_header->_base_archive_name_size; if (name_size == 0) { @@ -948,18 +966,7 @@ } } - _file_offset = n; - - size_t info_size = _header->_paths_misc_info_size; - _paths_misc_info = NEW_C_HEAP_ARRAY(char, info_size, mtClass); - n = os::read(fd, _paths_misc_info, (unsigned int)info_size); - if (n != info_size) { - fail_continue("Unable to read the shared path info header."); - FREE_C_HEAP_ARRAY(char, _paths_misc_info); - _paths_misc_info = NULL; - return false; - } - _file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name + _file_offset = n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name if (is_static) { // just checking the last region is sufficient since the archive is written @@ -1041,10 +1048,6 @@ // Write the header to the file, seek to the next allocation boundary. void FileMapInfo::write_header() { - int info_size = ClassLoader::get_shared_paths_misc_info_size(); - - _header->_paths_misc_info_size = info_size; - char* base_archive_name = NULL; if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) { base_archive_name = (char*)Arguments::GetSharedArchivePath(); @@ -1054,7 +1057,6 @@ assert(is_file_position_aligned(), "must be"); write_bytes(_header, _header->_header_size); - write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size); if (base_archive_name != NULL) { write_bytes(base_archive_name, (size_t)_header->_base_archive_name_size); } @@ -1751,7 +1753,7 @@ // // Validation of the archive is done in two steps: // -// [1] validate_header() - done here. This checks the header, including _paths_misc_info. +// [1] validate_header() - done here. // [2] validate_shared_path_table - this is done later, because the table is in the RW // region of the archive, which is not mapped yet. bool FileMapInfo::initialize(bool is_static) { @@ -1855,22 +1857,7 @@ } bool FileMapInfo::validate_header(bool is_static) { - bool status = _header->validate(); - - if (status) { - if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size, is_static)) { - if (!PrintSharedArchiveAndExit) { - fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)"); - status = false; - } - } - } - - if (_paths_misc_info != NULL) { - FREE_C_HEAP_ARRAY(char, _paths_misc_info); - _paths_misc_info = NULL; - } - return status; + return _header->validate(); } // Check if a given address is within one of the shared regions @@ -1922,7 +1909,7 @@ ClassPathEntry* ent = _classpath_entries_for_jvmti[i]; if (ent == NULL) { if (i == 0) { - ent = ClassLoader:: get_jrt_entry(); + ent = ClassLoader::get_jrt_entry(); assert(ent != NULL, "must be"); } else { SharedClassPathEntry* scpe = shared_path(i); --- old/src/hotspot/share/memory/filemap.hpp 2019-08-22 08:26:26.389460983 -0700 +++ new/src/hotspot/share/memory/filemap.hpp 2019-08-22 08:26:26.149452344 -0700 @@ -68,17 +68,17 @@ bool has_timestamp() { return _timestamp != 0; } - bool is_dir() { return _type == dir_entry; } - bool is_modules_image() { return _type == modules_image_entry; } - bool is_jar() { return _type == jar_entry; } - bool is_signed() { return _type == signed_jar_entry; } - void set_is_signed() { + bool is_dir() const { return _type == dir_entry; } + bool is_modules_image() const { return _type == modules_image_entry; } + bool is_jar() const { return _type == jar_entry; } + bool is_signed() const { return _type == signed_jar_entry; } + void set_is_signed() { _type = signed_jar_entry; } bool from_class_path_attr() { return _from_class_path_attr; } time_t timestamp() const { return _timestamp; } long filesize() const { return _filesize; } - const char* name() const { return _name->data(); } + const char* name() const; const char* manifest() const { return (_manifest == NULL) ? NULL : (const char*)_manifest->data(); } @@ -147,19 +147,6 @@ // size of the base archive name including NULL terminator int _base_archive_name_size; - // The _paths_misc_info is a variable-size structure that records "miscellaneous" - // information during dumping. It is generated and validated by the - // SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for - // detailed description. - // - // The _paths_misc_info data is stored as a byte array in the archive file header, - // immediately after the _header field. This information is used only when - // checking the validity of the archive and is deallocated after the archive is loaded. - // - // Note that the _paths_misc_info does NOT include information for JAR files - // that existed during dump time. Their information is stored in _shared_path_table. - int _paths_misc_info_size; - // The following is a table of all the class path entries that were used // during dumping. At run time, we require these files to exist and have the same // size/modification time, or else the archive will refuse to load. @@ -246,6 +233,8 @@ bool init_from_file(int fd, bool is_static); static void metaspace_pointers_do(MetaspaceClosure* it); + void log_paths(const char* msg, int start_idx, int end_idx); + public: FileMapInfo(bool is_static); ~FileMapInfo(); --- old/src/hotspot/share/prims/cdsoffsets.cpp 2019-08-22 08:26:27.025483877 -0700 +++ new/src/hotspot/share/prims/cdsoffsets.cpp 2019-08-22 08:26:26.785475238 -0700 @@ -53,7 +53,6 @@ ADD_NEXT(_all, "FileMapHeader::_space[0]", offset_of(FileMapHeader, _space)); \ ADD_NEXT(_all, "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc)); \ ADD_NEXT(_all, "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used)); \ - ADD_NEXT(_all, "FileMapHeader::_paths_misc_info_size", offset_of(FileMapHeader, _paths_misc_info_size)); \ ADD_NEXT(_all, "file_header_size", sizeof(FileMapHeader)); \ ADD_NEXT(_all, "DynamicArchiveHeader::_base_archive_crc", offset_of(DynamicArchiveHeader, _base_archive_crc)); \ ADD_NEXT(_all, "CDSFileMapRegion_size", sizeof(CDSFileMapRegion)); --- old/test/hotspot/jtreg/runtime/cds/appcds/AppendClasspath.java 2019-08-22 08:26:27.649506338 -0700 +++ new/test/hotspot/jtreg/runtime/cds/appcds/AppendClasspath.java 2019-08-22 08:26:27.409497699 -0700 @@ -95,19 +95,5 @@ "-cp", appJar2 + File.pathSeparator + appJar, "HelloMore") .assertAbnormalExit(errorMessage1, errorMessage2); - - // FAIL: 4) non-existing jar during dump time but jar exists during runtime - TestCommon.testDump(classPath, TestCommon.list("Hello")); - - Files.copy(Paths.get(classDir, "hello.jar"), - Paths.get(classDir, newFile), - StandardCopyOption.REPLACE_EXISTING); - - TestCommon.run( - "-cp", classPath, - "-Xlog:class+path=trace", - "Hello") - .assertAbnormalExit(errorMessage1, errorMessage2); - } } --- old/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java 2019-08-22 08:26:28.901551406 -0700 +++ new/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java 2019-08-22 08:26:28.657542623 -0700 @@ -61,7 +61,6 @@ public static int offset_version; // CDSFileMapHeaderBase::_version public static int offset_jvm_ident; // FileMapHeader::_jvm_ident public static int sp_offset_crc; // CDSFileMapRegion::_crc - public static int offset_paths_misc_info_size; public static int file_header_size = -1;// total size of header, variant, need calculation public static int CDSFileMapRegion_size; // size of CDSFileMapRegion public static int sp_offset; // offset of CDSFileMapRegion @@ -117,12 +116,6 @@ // this is not real header size, it is struct size int_size = wb.getOffsetForName("int_size"); file_header_size = wb.getOffsetForName("file_header_size"); - offset_paths_misc_info_size = wb.getOffsetForName("FileMapHeader::_paths_misc_info_size") - - offset_magic; - int path_misc_info_size = (int)readInt(fc, offset_paths_misc_info_size, int_size); - file_header_size += path_misc_info_size; - System.out.println("offset_paths_misc_info_size = " + offset_paths_misc_info_size); - System.out.println("path_misc_info_size = " + path_misc_info_size); System.out.println("file_header_size = " + file_header_size); file_header_size = (int)align_up_page(file_header_size); System.out.println("file_header_size (aligned to page) = " + file_header_size); @@ -405,10 +398,9 @@ output.shouldNotContain("Checksum verification failed"); copyFile(orgJsaFile, jsa); - // modify _jvm_ident and _paths_misc_info_size, test should fail - System.out.println("\n2a. Corrupt _jvm_ident and _paths_misc_info_size, should fail\n"); + // modify _jvm_ident, test should fail + System.out.println("\n2a. Corrupt _jvm_ident, should fail\n"); modifyJvmIdent(); - modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE); output = TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file was created by a different version or build of HotSpot"); output.shouldNotContain("Checksum verification failed"); @@ -422,19 +414,17 @@ output.shouldContain("Hello World"); copyFile(orgJsaFile, jsa); - // modify _magic and _paths_misc_info_size, test should fail - System.out.println("\n2c. Corrupt _magic and _paths_misc_info_size, should fail\n"); + // modify _magic, test should fail + System.out.println("\n2c. Corrupt _magic, should fail\n"); modifyHeaderIntField(offset_magic, 0x00000000); - modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE); output = TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has a bad magic number"); output.shouldNotContain("Checksum verification failed"); copyFile(orgJsaFile, jsa); - // modify _version and _paths_misc_info_size, test should fail - System.out.println("\n2d. Corrupt _version and _paths_misc_info_size, should fail\n"); + // modify _version, test should fail + System.out.println("\n2d. Corrupt _version, should fail\n"); modifyHeaderIntField(offset_version, 0x00000000); - modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE); output = TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has the wrong version"); output.shouldNotContain("Checksum verification failed"); --- old/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java 2019-08-22 08:26:29.537574300 -0700 +++ new/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java 2019-08-22 08:26:29.297565661 -0700 @@ -24,7 +24,7 @@ /* * @test - * @summary ensure -XX:+TraceClassPaths showing entire expecting app classpath + * @summary ensure -Xlog:class+path showing entire expecting app classpath * @requires vm.cds * @library /test/lib * @modules jdk.jartool/sun.tools.jar @@ -85,22 +85,23 @@ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps + "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar"; - String myCP = longClassPath + ps + appJar; + String dumpCP = longClassPath + ps + appJar; // Dump an archive with a specified JAR file in -classpath - TestCommon.testDump(myCP, TestCommon.list("Hello")); + TestCommon.testDump(dumpCP, TestCommon.list("Hello")); - // Then try to execute the archive with a different classpath and with -XX:+TraceClassPaths. - // The diagnosis "expecting" app classpath trace should show the entire classpath. + // Then try to execute the archive with a different classpath and with -Xlog:class+path. + // The diagnostic "expecting" app classpath trace should show the entire classpath (excluding any non-existent dump-time paths). + String recordedCP = dummyJar + ps + appJar; TestCommon.run( - "-XX:+TraceClassPaths", "-Xlog:cds", + "-Xlog:class+path", "-Xlog:cds", "-cp", appJar, "Hello") .assertAbnormalExit(output -> { output.shouldContain("Unable to use shared archive"); output.shouldContain("shared class paths mismatch"); - // the "expecting" app classpath from -XX:+TraceClassPaths should not + // the "expecting" app classpath from -Xlog:class+path should not // be truncated - output.shouldContain(myCP); + output.shouldContain(recordedCP); }); } } --- /dev/null 2019-02-25 13:26:02.045529497 -0800 +++ new/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java 2019-08-22 08:26:29.921588123 -0700 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Handling of non-existent classpath elements during dump time and run time + * @requires vm.cds + * @library /test/lib + * @modules jdk.jartool/sun.tools.jar + * @compile test-classes/Hello.java + * @compile test-classes/HelloMore.java + * @run driver NonExistClasspath + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import jdk.test.lib.process.OutputAnalyzer; + +public class NonExistClasspath { + public static void main(String[] args) throws Exception { + String appJar = JarBuilder.getOrCreateHelloJar(); + doTest(appJar, false); + doTest(appJar, true); + } + + static void doTest(String appJar, boolean bootcp) throws Exception { + String classDir = System.getProperty("test.classes"); + String newFile = "non-exist.jar"; + String nonExistPath = classDir + File.separator + newFile; + final String errorMessage1 = "Unable to use shared archive"; + final String errorMessage2 = "shared class paths mismatch"; + final String errorMessage3 = (bootcp ? "BOOT" : "APP") + " classpath mismatch"; + + (new File(nonExistPath)).delete(); + + String classPath = nonExistPath + File.pathSeparator + appJar; + TestCommon.testDump("foobar", TestCommon.list("Hello"), make_args(bootcp, classPath)); + + // The nonExistPath doesn't exist yet, so we should be able to run without problem + TestCommon.run(make_args(bootcp, + classPath, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Replace nonExistPath with another non-existent file in the CP, it should still work + TestCommon.run(make_args(bootcp, + nonExistPath + ".duh" + File.pathSeparator + appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Add a few more non-existent files in the CP, it should still work + TestCommon.run(make_args(bootcp, + nonExistPath + ".duh" + File.pathSeparator + + nonExistPath + ".daa" + File.pathSeparator + + nonExistPath + ".boo" + File.pathSeparator + + appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Or, remove all non-existent paths from the CP, it should still work + TestCommon.run(make_args(bootcp, + appJar, + "-Xlog:class+path=trace", + "Hello")) + .assertNormalExit(); + + // Now make nonExistPath exist. CDS will fail to load. + Files.copy(Paths.get(classDir, "hello.jar"), + Paths.get(classDir, newFile), + StandardCopyOption.REPLACE_EXISTING); + + TestCommon.run(make_args(bootcp, + classPath, + "-Xlog:class+path=trace", + "Hello")) + .assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3); + } + + static String[] make_args(boolean bootcp, String cp, String... suffix) { + String args[]; + if (bootcp) { + args = TestCommon.concat("-Xbootclasspath/a:" + cp); + } else { + args = TestCommon.concat("-cp", cp); + } + + return TestCommon.concat(args, suffix); + } +} --- old/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp 2019-08-22 08:26:30.937624695 -0700 +++ /dev/null 2019-02-25 13:26:02.045529497 -0800 @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2014, 2019, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/classLoader.hpp" -#include "classfile/sharedPathsMiscInfo.hpp" -#include "logging/log.hpp" -#include "logging/logStream.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/filemap.hpp" -#include "memory/metaspaceShared.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/arguments.hpp" -#include "runtime/os.inline.hpp" -#include "utilities/ostream.hpp" - -SharedPathsMiscInfo::SharedPathsMiscInfo() { - _app_offset = 0; - _buf_size = INITIAL_BUF_SIZE; - _cur_ptr = _buf_start = NEW_C_HEAP_ARRAY(char, _buf_size, mtClass); - _allocated = true; -} - -SharedPathsMiscInfo::~SharedPathsMiscInfo() { - if (_allocated) { - FREE_C_HEAP_ARRAY(char, _buf_start); - } -} - -void SharedPathsMiscInfo::add_path(const char* path, int type) { - log_info(class, path)("type=%s ", type_name(type)); - ClassLoader::trace_class_path("add misc shared path ", path); - write(path, strlen(path) + 1); - write_jint(jint(type)); -} - -void SharedPathsMiscInfo::ensure_size(size_t needed_bytes) { - assert(_allocated, "cannot modify buffer during validation."); - int used = get_used_bytes(); - int target = used + int(needed_bytes); - if (target > _buf_size) { - _buf_size = _buf_size * 2 + (int)needed_bytes; - _buf_start = REALLOC_C_HEAP_ARRAY(char, _buf_start, _buf_size, mtClass); - _cur_ptr = _buf_start + used; - _end_ptr = _buf_start + _buf_size; - } -} - -void SharedPathsMiscInfo::write(const void* ptr, size_t size) { - ensure_size(size); - memcpy(_cur_ptr, ptr, size); - _cur_ptr += size; -} - -bool SharedPathsMiscInfo::read(void* ptr, size_t size) { - if (_cur_ptr + size <= _end_ptr) { - memcpy(ptr, _cur_ptr, size); - _cur_ptr += size; - return true; - } - return false; -} - -bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(msg, name); - MetaspaceShared::set_archive_loading_failed(); - return false; -} - -void SharedPathsMiscInfo::print_path(outputStream* out, int type, const char* path) { - switch (type) { - case BOOT_PATH: - out->print("Expecting BOOT path=%s", path); - break; - case NON_EXIST: - out->print("Expecting that %s does not exist", path); - break; - case APP_PATH: - ClassLoader::trace_class_path("Expecting -Djava.class.path=", path); - break; - default: - ShouldNotReachHere(); - } -} - -bool SharedPathsMiscInfo::check(bool is_static) { - // The whole buffer must be 0 terminated so that we can use strlen and strcmp - // without fear. - _end_ptr -= sizeof(jint); - if (_cur_ptr >= _end_ptr) { - return fail("Truncated archive file header"); - } - if (*_end_ptr != 0) { - return fail("Corrupted archive file header"); - } - - jshort cur_index = 0; - FileMapHeader* header = is_static ? FileMapInfo::current_info()->header() : - FileMapInfo::dynamic_info()->header(); - jshort max_cp_index = header->max_used_path_index(); - jshort module_paths_start_index = header->app_module_paths_start_index(); - while (_cur_ptr < _end_ptr) { - jint type; - const char* path = _cur_ptr; - _cur_ptr += strlen(path) + 1; - - if (!read_jint(&type)) { - return fail("Corrupted archive file header"); - } - LogTarget(Info, class, path) lt; - if (lt.is_enabled()) { - lt.print("type=%s ", type_name(type)); - LogStream ls(lt); - print_path(&ls, type, path); - ls.cr(); - } - // skip checking the class path(s) which was not referenced during CDS dump - if ((cur_index <= max_cp_index) || (cur_index >= module_paths_start_index)) { - if (!check(type, path, is_static)) { - if (!PrintSharedArchiveAndExit) { - return false; - } - } else { - ClassLoader::trace_class_path("ok"); - } - } else { - ClassLoader::trace_class_path("skipped check"); - } - cur_index++; - } - - return true; -} - -bool SharedPathsMiscInfo::check(jint type, const char* path, bool is_static) { - assert(UseSharedSpaces, "runtime only"); - switch (type) { - case BOOT_PATH: - break; - case NON_EXIST: - { - struct stat st; - if (os::stat(path, &st) == 0) { - // The file actually exists - // But we want it to not exist -> fail - return fail("File must not exist"); - } - } - break; - case APP_PATH: - break; - default: - return fail("Corrupted archive file header"); - } - - return true; -} --- old/src/hotspot/share/classfile/sharedPathsMiscInfo.hpp 2019-08-22 08:26:31.377640534 -0700 +++ /dev/null 2019-02-25 13:26:02.045529497 -0800 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2014, 2019, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP -#define SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP - -#include "classfile/classLoader.hpp" -#include "runtime/os.hpp" - -class outputStream; -// During dumping time, when processing class paths, we build up the dump-time -// classpath. The JAR files that exist are stored in the list ClassLoader::_first_append_entry. -// However, we need to store other "misc" information for run-time checking, such as -// -// + The values of Arguments::get_sysclasspath() used during dumping. -// -// + The class path elements specified during dumping but did not exist -- -// these elements must also be specified at run time, and they also must not -// exist at run time. -// -// These misc items are stored in a linear buffer in SharedPathsMiscInfo. -// The storage format is stream oriented to minimize its size. -// -// When writing the information to the archive file, SharedPathsMiscInfo is stored in -// the archive file header. At run-time, this information is used only during initialization -// (accessed using read() instead of mmap()), and is deallocated afterwards to save space. -// -// The SharedPathsMiscInfo class is used for both creating the the information (during -// dumping time) and validation (at run time). Different constructors are used in the -// two situations. See below. - -class SharedPathsMiscInfo : public CHeapObj { -private: - int _app_offset; -protected: - char* _buf_start; - char* _cur_ptr; - char* _end_ptr; - int _buf_size; - bool _allocated; // was _buf_start allocated by me? - void ensure_size(size_t needed_bytes); - void add_path(const char* path, int type); - - void write(const void* ptr, size_t size); - bool read(void* ptr, size_t size); - -protected: - static bool fail(const char* msg, const char* name = NULL); - bool check(jint type, const char* path, bool is_static); - -public: - enum { - INITIAL_BUF_SIZE = 128 - }; - // This constructor is used when creating the misc information (during dump) - SharedPathsMiscInfo(); - // This constructor is used when validating the misc info (during run time) - SharedPathsMiscInfo(char *buff, int size) { - _app_offset = 0; - _cur_ptr = _buf_start = buff; - _end_ptr = _buf_start + size; - _buf_size = size; - _allocated = false; - } - ~SharedPathsMiscInfo(); - - int get_used_bytes() { - return _cur_ptr - _buf_start; - } - void* buffer() { - return _buf_start; - } - - // writing -- - - // The path must not exist at run-time - void add_nonexist_path(const char* path) { - add_path(path, NON_EXIST); - } - - // The path must exist, and must contain exactly files/dirs - void add_boot_classpath(const char* path) { - add_path(path, BOOT_PATH); - } - - void add_app_classpath(const char* path) { - add_path(path, APP_PATH); - } - void record_app_offset() { - _app_offset = get_used_bytes(); - } - void pop_app() { - _cur_ptr = _buf_start + _app_offset; - write_jint(0); - } - - int write_jint(jint num) { - write(&num, sizeof(num)); - return 0; - } - void write_time(time_t t) { - write(&t, sizeof(t)); - } - void write_long(long l) { - write(&l, sizeof(l)); - } - - bool dump_to_file(int fd) { - int n = get_used_bytes(); - return (os::write(fd, _buf_start, n) == (size_t)n); - } - - // reading -- - -private: - enum { - BOOT_PATH = 1, - APP_PATH = 2, - NON_EXIST = 3 - }; - - const char* type_name(int type) { - switch (type) { - case BOOT_PATH: return "BOOT"; - case APP_PATH: return "APP"; - case NON_EXIST: return "NON_EXIST"; - default: ShouldNotReachHere(); return "?"; - } - } - - void print_path(outputStream* os, int type, const char* path); - - bool read_jint(jint *ptr) { - return read(ptr, sizeof(jint)); - } - bool read_long(long *ptr) { - return read(ptr, sizeof(long)); - } - bool read_time(time_t *ptr) { - return read(ptr, sizeof(time_t)); - } - -public: - bool check(bool is_static); -}; - -#endif // SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP