--- old/src/hotspot/share/classfile/classLoader.cpp 2019-08-27 10:06:36.516996990 -0700 +++ new/src/hotspot/share/classfile/classLoader.cpp 2019-08-27 10:06:36.280988465 -0700 @@ -1534,7 +1534,6 @@ load_zip_library(); // lookup jimage library entry points load_jimage_library(); - setup_bootstrap_search_path(); } --- old/src/hotspot/share/classfile/classLoaderExt.cpp 2019-08-27 10:06:37.029015485 -0700 +++ new/src/hotspot/share/classfile/classLoaderExt.cpp 2019-08-27 10:06:36.789006815 -0700 @@ -210,8 +210,10 @@ char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1); int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start); assert((size_t)n == libname_len, "Unexpected number of characters in string"); - trace_class_path("library = ", libname); - if (!ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */)) { + if (ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */)) { + trace_class_path("library = ", libname); + } else { + trace_class_path("library (non-existent) = ", libname); FileMapInfo::record_non_existent_class_path_entry(libname); } } --- old/src/hotspot/share/memory/filemap.cpp 2019-08-27 10:06:37.533033692 -0700 +++ new/src/hotspot/share/memory/filemap.cpp 2019-08-27 10:06:37.293025022 -0700 @@ -713,6 +713,16 @@ // None of the jar file specified in the runtime -cp exists. return fail("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp); } + + // Handling of non-existent entries in the classpath: we eliminate all the non-existent + // entries from both the dump time classpath (ClassLoader::update_class_path_entry_list) + // and the runtime classpath (FileMapInfo::create_path_array), and check the remaining + // entries. E.g.: + // + // dump : -cp a.jar:NE1:NE2:b.jar -> a.jar:b.jar -> recorded in archive. + // run 1: -cp NE3:a.jar:NE4:b.jar -> a.jar:b.jar -> matched + // run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched + int j = _header->_app_class_paths_start_index; mismatch = check_paths(j, shared_app_paths_len, rp_array); if (mismatch) { @@ -807,9 +817,7 @@ } } - if (!validate_non_existent_class_paths()) { - return false; - } + validate_non_existent_class_paths(); _validating_shared_path_table = false; @@ -825,22 +833,26 @@ return true; } -bool FileMapInfo::validate_non_existent_class_paths() const { +void FileMapInfo::validate_non_existent_class_paths() { + // All of the recorded non-existent paths came from the Class-Path: attribute from the JAR + // files on the app classpath. If any of these are found to exist during runtime, + // it will change how classes are loading for the app loader. For safety, disable + // loading of archived platform/app classes (currently there's no way to disable just the + // app classes). + assert(UseSharedSpaces, "runtime only"); for (int i = _header->_app_module_paths_start_index + _header->_num_module_paths; i < get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = shared_path(i); if (!ent->check_non_existent()) { - fail_continue("file must not exist: %s", ent->name()); - return false; + warning("Archived non-system classes are disabled because the " + "file %s exists", ent->name()); + _header->_has_platform_or_app_classes = false; } } - return true; } - - bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); if (fd < 0) { --- old/src/hotspot/share/memory/filemap.hpp 2019-08-27 10:06:38.053052476 -0700 +++ new/src/hotspot/share/memory/filemap.hpp 2019-08-27 10:06:37.809043662 -0700 @@ -153,17 +153,12 @@ // size of the base archive name including NULL terminator int _base_archive_name_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. - // - // All of these entries must be JAR files. The dumping process would fail if a non-empty - // directory was specified in the classpaths. If an empty directory was specified - // it is checked by the _paths_misc_info as described above. - // - // FIXME -- if JAR files in the tail of the list were specified but not used during dumping, - // they should be removed from this table, to save space and to avoid spurious - // loading failures during runtime. + // The following is a table of all the boot/app/module path entries that were used + // during dumping. At run time, we we validate these entries according to their + // SharedClassPathEntry::_type. See: + // check_nonempty_dir_in_shared_path_table() + // validate_shared_path_table() + // validate_non_existent_class_paths() SharedPathTable _shared_path_table; jshort _app_class_paths_start_index; // Index of first app classpath entry @@ -225,7 +220,6 @@ FileMapHeader * _header; const char* _full_path; - char* _paths_misc_info; char* _base_archive_name; static FileMapInfo* _current_info; @@ -353,7 +347,7 @@ static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS); static void check_nonempty_dir_in_shared_path_table(); bool validate_shared_path_table(); - bool validate_non_existent_class_paths() const; + void validate_non_existent_class_paths(); static void update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS); static int num_non_existent_class_paths(); static void record_non_existent_class_path_entry(const char* path); --- old/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java 2019-08-27 10:06:38.569071116 -0700 +++ new/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java 2019-08-27 10:06:38.325062302 -0700 @@ -116,7 +116,7 @@ output.shouldMatch("should be non-existent: .*cpattrX.jar"); }); - // Now make nonExistPath exist. CDS will fail to load. + // Now make nonExistPath exist. CDS still loads, but archived non-system classes will not be used. Files.copy(Paths.get(cp), Paths.get(nonExistPath), StandardCopyOption.REPLACE_EXISTING); @@ -124,9 +124,8 @@ "-Xlog:class+path", "-cp", cp, "CpAttr6") - .assertAbnormalExit(output -> { - output.shouldMatch("should be non-existent: .*cpattrX.jar"); - output.shouldMatch("file must not exist: .*cpattrX.jar"); + .assertNormalExit(output -> { + output.shouldMatch("Archived non-system classes are disabled because the file .*/cpattrX.jar exists"); }); }