1 /*
   2  * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "cds/aotClassLocation.hpp"
  26 #include "cds/archiveBuilder.hpp"
  27 #include "cds/cdsConfig.hpp"
  28 #include "cds/dynamicArchive.hpp"
  29 #include "cds/filemap.hpp"
  30 #include "cds/metaspaceShared.hpp"
  31 #include "cds/serializeClosure.hpp"
  32 #include "classfile/classLoader.hpp"
  33 #include "classfile/classLoaderData.hpp"
  34 #include "classfile/javaClasses.hpp"
  35 #include "logging/log.hpp"
  36 #include "logging/logStream.hpp"
  37 #include "memory/metadataFactory.hpp"
  38 #include "memory/metaspaceClosure.hpp"
  39 #include "memory/resourceArea.hpp"
  40 #include "oops/array.hpp"
  41 #include "oops/objArrayKlass.hpp"
  42 #include "runtime/arguments.hpp"
  43 #include "utilities/classpathStream.hpp"
  44 #include "utilities/formatBuffer.hpp"
  45 #include "utilities/stringUtils.hpp"
  46 
  47 #include <sys/stat.h>
  48 #include <errno.h>
  49 
  50 AOTClassLocationConfig* AOTClassLocationConfig::_dumptime_instance = nullptr;
  51 const AOTClassLocationConfig* AOTClassLocationConfig::_runtime_instance = nullptr;
  52 
  53 // A ClassLocationStream represents a list of code locations, which can be iterated using
  54 // start() and has_next().
  55 class ClassLocationStream {
  56 protected:
  57   GrowableArray<const char*> _array;
  58   int _current;
  59 
  60   // Add one path to this stream.
  61   void add_one_path(const char* path) {
  62     _array.append(path);
  63   }
  64 
  65   // Add all paths specified in cp; cp must be from -classpath or -Xbootclasspath/a.
  66   void add_paths_in_classpath(const char* cp) {
  67     ClasspathStream cp_stream(cp);
  68     while (cp_stream.has_next()) {
  69       add_one_path(cp_stream.get_next());
  70     }
  71   }
  72 
  73 public:
  74   ClassLocationStream() : _array(), _current(0) {}
  75 
  76   void print(outputStream* st) const {
  77     const char* sep = "";
  78     for (int i = 0; i < _array.length(); i++) {
  79       st->print("%s%s", sep, _array.at(i));
  80       sep = os::path_separator();
  81     }
  82   }
  83 
  84   void add(ClassLocationStream& css) {
  85     for (css.start(); css.has_next();) {
  86       add_one_path(css.get_next());
  87     }
  88   }
  89 
  90   // Iteration
  91   void start() { _current = 0; }
  92   bool has_next() const { return _current < _array.length(); }
  93   const char* get_next() {
  94     return _array.at(_current++);
  95   }
  96 
  97   int current() const { return _current; }
  98   bool is_empty() const { return _array.length() == 0; }
  99 };
 100 
 101 class BootCpClassLocationStream : public ClassLocationStream {
 102 public:
 103   BootCpClassLocationStream() : ClassLocationStream() {
 104     // Arguments::get_boot_class_path() contains $JAVA_HOME/lib/modules, but we treat that separately
 105     for (const char* bootcp = Arguments::get_boot_class_path(); *bootcp != '\0'; ++bootcp) {
 106       if (*bootcp == *os::path_separator()) {
 107         ++bootcp;
 108         add_paths_in_classpath(bootcp);
 109         break;
 110       }
 111     }
 112   }
 113 };
 114 
 115 class AppCpClassLocationStream : public ClassLocationStream {
 116 public:
 117   AppCpClassLocationStream() : ClassLocationStream() {
 118     const char* appcp = Arguments::get_appclasspath();
 119     if (strcmp(appcp, ".") == 0) {
 120       appcp = "";
 121     }
 122     add_paths_in_classpath(appcp);
 123   }
 124 };
 125 
 126 class ModulePathClassLocationStream : public ClassLocationStream {
 127   bool _has_non_jar_modules;
 128 public:
 129   ModulePathClassLocationStream();
 130   bool has_non_jar_modules() { return _has_non_jar_modules; }
 131 };
 132 
 133 // AllClassLocationStreams is used to iterate over all the code locations that
 134 // are available to the application from -Xbootclasspath, -classpath and --module-path.
 135 // When creating an AOT cache, we store the contents from AllClassLocationStreams
 136 // into an array of AOTClassLocations. See AOTClassLocationConfig::dumptime_init_helper().
 137 // When loading the AOT cache in a production run, we compare the contents of the
 138 // stored AOTClassLocations against the current AllClassLocationStreams to determine whether
 139 // the AOT cache is compatible with the current JVM. See AOTClassLocationConfig::validate().
 140 class AllClassLocationStreams {
 141   BootCpClassLocationStream _boot_cp;          // Specified by -Xbootclasspath/a
 142   AppCpClassLocationStream _app_cp;            // Specified by -classpath
 143   ModulePathClassLocationStream _module_path;  // Specified by --module-path
 144   ClassLocationStream _boot_and_app_cp;        // Convenience for iterating over both _boot and _app
 145 public:
 146   BootCpClassLocationStream& boot_cp()             { return _boot_cp; }
 147   AppCpClassLocationStream& app_cp()               { return _app_cp; }
 148   ModulePathClassLocationStream& module_path()     { return _module_path; }
 149   ClassLocationStream& boot_and_app_cp()           { return _boot_and_app_cp; }
 150 
 151   AllClassLocationStreams() : _boot_cp(), _app_cp(), _module_path(), _boot_and_app_cp() {
 152     _boot_and_app_cp.add(_boot_cp);
 153     _boot_and_app_cp.add(_app_cp);
 154   }
 155 };
 156 
 157 static bool has_jar_suffix(const char* filename) {
 158   // In jdk.internal.module.ModulePath.readModule(), it checks for the ".jar" suffix.
 159   // Performing the same check here.
 160   const char* dot = strrchr(filename, '.');
 161   if (dot != nullptr && strcmp(dot + 1, "jar") == 0) {
 162     return true;
 163   }
 164   return false;
 165 }
 166 
 167 static int compare_module_path_by_name(const char** p1, const char** p2) {
 168   return strcmp(*p1, *p2);
 169 }
 170 
 171 ModulePathClassLocationStream::ModulePathClassLocationStream() : ClassLocationStream(), _has_non_jar_modules(false) {
 172   // Note: for handling of --module-path, see
 173   //   https://openjdk.org/jeps/261#Module-paths
 174   //   https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/module/ModuleFinder.html#of(java.nio.file.Path...)
 175 
 176   const char* jdk_module_path = Arguments::get_property("jdk.module.path");
 177   if (jdk_module_path == nullptr) {
 178     return;
 179   }
 180 
 181   ClasspathStream cp_stream(jdk_module_path);
 182   while (cp_stream.has_next()) {
 183     const char* path = cp_stream.get_next();
 184     DIR* dirp = os::opendir(path);
 185     if (dirp == nullptr && errno == ENOTDIR && has_jar_suffix(path)) {
 186       add_one_path(path);
 187     } else if (dirp != nullptr) {
 188       struct dirent* dentry;
 189       bool found_jar = false;
 190       while ((dentry = os::readdir(dirp)) != nullptr) {
 191         const char* file_name = dentry->d_name;
 192         if (has_jar_suffix(file_name)) {
 193           size_t full_name_len = strlen(path) + strlen(file_name) + strlen(os::file_separator()) + 1;
 194           char* full_name = NEW_RESOURCE_ARRAY(char, full_name_len);
 195           int n = os::snprintf(full_name, full_name_len, "%s%s%s", path, os::file_separator(), file_name);
 196           assert((size_t)n == full_name_len - 1, "Unexpected number of characters in string");
 197           add_one_path(full_name);
 198           found_jar = true;
 199         } else if (strcmp(file_name, ".") != 0 && strcmp(file_name, "..") != 0) {
 200           // Found some non jar entries
 201           _has_non_jar_modules = true;
 202           log_info(class, path)("Found non-jar path: '%s%s%s'", path, os::file_separator(), file_name);
 203         }
 204       }
 205       if (!found_jar) {
 206         log_info(class, path)("Found exploded module path: '%s'", path);
 207         _has_non_jar_modules = true;
 208       }
 209       os::closedir(dirp);
 210     } else {
 211       _has_non_jar_modules = true;
 212     }
 213   }
 214 
 215   _array.sort(compare_module_path_by_name);
 216 }
 217 
 218 AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* path, int index,
 219                                              Group group, bool from_cpattr, bool is_jrt) {
 220   size_t path_length = 0;
 221   size_t manifest_length = 0;
 222   bool check_time = false;
 223   time_t timestamp = 0;
 224   int64_t filesize = 0;
 225   FileType type = FileType::NORMAL;
 226   // Do not record the actual path of the jrt, as the entire JDK can be moved to a different
 227   // directory.
 228   const char* recorded_path = is_jrt ? "" : path;
 229   path_length = strlen(recorded_path);
 230 
 231   struct stat st;
 232   if (os::stat(path, &st) == 0) {
 233     if ((st.st_mode & S_IFMT) == S_IFDIR) {
 234       type = FileType::DIR;
 235     } else {
 236       timestamp = st.st_mtime;
 237       filesize = st.st_size;
 238 
 239       // The timestamp of $JAVA_HOME/lib/modules is not checked at runtime.
 240       check_time = !is_jrt;
 241     }
 242 #ifdef _WINDOWS
 243   } else if (errno == ERROR_FILE_NOT_FOUND || errno == ERROR_PATH_NOT_FOUND) {
 244     // On Windows, the errno could be ERROR_PATH_NOT_FOUND (3) in case the directory
 245     // path doesn't exist.
 246     type = FileType::NOT_EXIST;
 247 #endif
 248   } else if (errno == ENOENT) {
 249     // We allow the file to not exist, as long as it also doesn't exist during runtime.
 250     type = FileType::NOT_EXIST;
 251   } else {
 252     log_error(cds)("Unable to open file %s.", path);
 253     MetaspaceShared::unrecoverable_loading_error();
 254   }
 255 
 256   ResourceMark rm(current);
 257   char* manifest = nullptr;
 258 
 259   if (!is_jrt && type == FileType::NORMAL) {
 260     manifest = read_manifest(current, path, manifest_length); // resource allocated
 261   }
 262 
 263   size_t cs_size = header_size() +
 264     + path_length + 1 /* nul-terminated */
 265     + manifest_length + 1; /* nul-terminated */
 266 
 267   AOTClassLocation* cs = (AOTClassLocation*)os::malloc(cs_size, mtClassShared);
 268   memset(cs, 0, cs_size);
 269   cs->_path_length = path_length;
 270   cs->_manifest_length = manifest_length;
 271   cs->_check_time = check_time;
 272   cs->_from_cpattr = from_cpattr;
 273   cs->_timestamp = check_time ? timestamp : 0;
 274   cs->_filesize = filesize;
 275   cs->_file_type = type;
 276   cs->_group = group;
 277   cs->_index = index;
 278 
 279   strcpy(((char*)cs) + cs->path_offset(), recorded_path);
 280   if (manifest_length > 0) {
 281     memcpy(((char*)cs) + cs->manifest_offset(), manifest, manifest_length);
 282   }
 283   assert(*(cs->manifest() + cs->manifest_length()) == '\0', "should be nul-terminated");
 284 
 285   if (strstr(cs->manifest(), "Multi-Release: true") != nullptr) {
 286     cs->_is_multi_release_jar = true;
 287   }
 288 
 289   if (strstr(cs->manifest(), "Extension-List:") != nullptr) {
 290     vm_exit_during_cds_dumping(err_msg("-Xshare:dump does not support Extension-List in JAR manifest: %s", path));
 291   }
 292 
 293   return cs;
 294 }
 295 
 296 char* AOTClassLocation::read_manifest(JavaThread* current, const char* path, size_t& manifest_length) {
 297   manifest_length = 0;
 298 
 299   struct stat st;
 300   if (os::stat(path, &st) != 0) {
 301     return nullptr;
 302   }
 303 
 304   ClassPathEntry* cpe = ClassLoader::create_class_path_entry(current, path, &st);
 305   if (cpe == nullptr) {
 306     // <path> is a file, but not a JAR file
 307     return nullptr;
 308   }
 309   assert(cpe->is_jar_file(), "should not be called with a directory");
 310 
 311   const char* name = "META-INF/MANIFEST.MF";
 312   char* manifest;
 313   jint size;
 314   manifest = (char*) ((ClassPathZipEntry*)cpe)->open_entry(current, name, &size, true);
 315 
 316   if (manifest == nullptr || size <= 0) { // No Manifest
 317     manifest_length = 0;
 318   } else {
 319     manifest_length = (size_t)size;
 320   }
 321 
 322   delete cpe;
 323   return manifest;
 324 }
 325 
 326 // The result is resource allocated.
 327 char* AOTClassLocation::get_cpattr() const {
 328   if (_manifest_length == 0) {
 329     return nullptr;
 330   }
 331 
 332   size_t buf_size = _manifest_length + 1;
 333   char* buf = NEW_RESOURCE_ARRAY(char, buf_size);
 334   memcpy(buf, manifest(), _manifest_length);
 335   buf[_manifest_length] = 0; // make sure it's 0-terminated
 336 
 337   // See http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#JAR%20Manifest
 338   // Replace all CR/LF and CR with LF
 339   StringUtils::replace_no_expand(buf, "\r\n", "\n");
 340   // Remove all new-line continuation (remove all "\n " substrings)
 341   StringUtils::replace_no_expand(buf, "\n ", "");
 342 
 343   const char* tag = "Class-Path: ";
 344   size_t tag_len = strlen(tag);
 345   char* found = nullptr;
 346   char* line_start = buf;
 347   char* end = buf + _manifest_length;
 348 
 349   assert(*end == 0, "must be nul-terminated");
 350 
 351   while (line_start < end) {
 352     char* line_end = strchr(line_start, '\n');
 353     if (line_end == nullptr) {
 354       // JAR spec require the manifest file to be terminated by a new line.
 355       break;
 356     }
 357     if (strncmp(tag, line_start, tag_len) == 0) {
 358       if (found != nullptr) {
 359         // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java
 360         // If duplicated entries are found, the last one is used.
 361         log_warning(cds)("Warning: Duplicate name in Manifest: %s.\n"
 362                          "Ensure that the manifest does not have duplicate entries, and\n"
 363                          "that blank lines separate individual sections in both your\n"
 364                          "manifest and in the META-INF/MANIFEST.MF entry in the jar file:\n%s\n", tag, path());
 365       }
 366       found = line_start + tag_len;
 367       assert(found <= line_end, "sanity");
 368       *line_end = '\0';
 369     }
 370     line_start = line_end + 1;
 371   }
 372 
 373   return found;
 374 }
 375 
 376 AOTClassLocation* AOTClassLocation::write_to_archive() const {
 377   AOTClassLocation* archived_copy = (AOTClassLocation*)ArchiveBuilder::ro_region_alloc(total_size());
 378   memcpy((char*)archived_copy, (char*)this, total_size());
 379   return archived_copy;
 380 }
 381 
 382 const char* AOTClassLocation::file_type_string() const {
 383   switch (_file_type) {
 384   case FileType::NORMAL: return "file";
 385   case FileType::DIR: return "dir";
 386   case FileType::NOT_EXIST: default: return "not-exist";
 387   }
 388 }
 389 
 390 bool AOTClassLocation::check(const char* runtime_path, bool has_aot_linked_classes) const {
 391   struct stat st;
 392   if (os::stat(runtime_path, &st) != 0) {
 393     if (_file_type != FileType::NOT_EXIST) {
 394       log_warning(cds)("Required classpath entry does not exist: %s", runtime_path);
 395       return false;
 396     }
 397   } else if ((st.st_mode & S_IFMT) == S_IFDIR) {
 398     if (_file_type == FileType::NOT_EXIST) {
 399       log_warning(cds)("'%s' must not exist", runtime_path);
 400       return false;
 401     }
 402     if (_file_type == FileType::NORMAL) {
 403       log_warning(cds)("'%s' must be a file", runtime_path);
 404       return false;
 405     }
 406     if (!os::dir_is_empty(runtime_path)) {
 407       log_warning(cds)("directory is not empty: '%s'", runtime_path);
 408       return false;
 409     }
 410   } else {
 411     if (_file_type == FileType::NOT_EXIST) {
 412       log_warning(cds)("'%s' must not exist", runtime_path);
 413       if (has_aot_linked_classes) {
 414         log_error(cds)("CDS archive has aot-linked classes. It cannot be used because the "
 415                        "file %s exists", runtime_path);
 416         return false;
 417       } else {
 418         log_warning(cds)("Archived non-system classes are disabled because the "
 419                          "file %s exists", runtime_path);
 420         FileMapInfo::current_info()->set_has_platform_or_app_classes(false);
 421         if (DynamicArchive::is_mapped()) {
 422           FileMapInfo::dynamic_info()->set_has_platform_or_app_classes(false);
 423         }
 424       }
 425     }
 426     if (_file_type == FileType::DIR) {
 427       log_warning(cds)("'%s' must be a directory", runtime_path);
 428       return false;
 429     }
 430     bool size_differs = _filesize != st.st_size;
 431     bool time_differs = _check_time && (_timestamp != st.st_mtime);
 432     if (size_differs || time_differs) {
 433       log_warning(cds)("This file is not the one used while building the shared archive file: '%s'%s%s",
 434                        runtime_path,
 435                        time_differs ? ", timestamp has changed" : "",
 436                        size_differs ? ", size has changed" : "");
 437       return false;
 438     }
 439   }
 440 
 441   log_info(class, path)("ok");
 442   return true;
 443 }
 444 
 445 void AOTClassLocationConfig::dumptime_init(JavaThread* current) {
 446   assert(CDSConfig::is_dumping_archive(), "");
 447   _dumptime_instance = NEW_C_HEAP_OBJ(AOTClassLocationConfig, mtClassShared);
 448   _dumptime_instance->dumptime_init_helper(current);
 449   if (current->has_pending_exception()) {
 450     // we can get an exception only when we run out of metaspace, but that
 451     // shouldn't happen this early in bootstrap.
 452     java_lang_Throwable::print(current->pending_exception(), tty);
 453     vm_exit_during_initialization("AOTClassLocationConfig::dumptime_init_helper() failed unexpectedly");
 454   }
 455 }
 456 
 457 void AOTClassLocationConfig::dumptime_init_helper(TRAPS) {
 458   ResourceMark rm;
 459   GrowableClassLocationArray tmp_array;
 460   AllClassLocationStreams all_css;
 461 
 462   AOTClassLocation* jrt = AOTClassLocation::allocate(THREAD, ClassLoader::get_jrt_entry()->name(),
 463                                                0, Group::MODULES_IMAGE,
 464                                                /*from_cpattr*/false, /*is_jrt*/true);
 465   tmp_array.append(jrt);
 466 
 467   parse(THREAD, tmp_array, all_css.boot_cp(), Group::BOOT_CLASSPATH, /*parse_manifest*/true);
 468   _boot_classpath_end = tmp_array.length();
 469 
 470   parse(THREAD, tmp_array, all_css.app_cp(), Group::APP_CLASSPATH, /*parse_manifest*/true);
 471   _app_classpath_end = tmp_array.length();
 472 
 473   parse(THREAD, tmp_array, all_css.module_path(), Group::MODULE_PATH, /*parse_manifest*/false);
 474   _module_end = tmp_array.length();
 475 
 476   _class_locations =  MetadataFactory::new_array<AOTClassLocation*>(ClassLoaderData::the_null_class_loader_data(),
 477                                                                tmp_array.length(), CHECK);
 478   for (int i = 0; i < tmp_array.length(); i++) {
 479     _class_locations->at_put(i, tmp_array.at(i));
 480   }
 481 
 482   const char* lcp = find_lcp(all_css.boot_and_app_cp(), _dumptime_lcp_len);
 483   if (_dumptime_lcp_len > 0) {
 484     os::free((void*)lcp);
 485     log_info(class, path)("Longest common prefix = %s (%zu chars)", lcp, _dumptime_lcp_len);
 486   } else {
 487     assert(_dumptime_lcp_len == 0, "sanity");
 488     log_info(class, path)("Longest common prefix = <none> (0 chars)");
 489   }
 490 
 491   _has_non_jar_modules = all_css.module_path().has_non_jar_modules();
 492   _has_platform_classes = false;
 493   _has_app_classes = false;
 494   _max_used_index = 0;
 495 }
 496 
 497 // Find the longest common prefix of two paths, up to max_lcp_len.
 498 // E.g.   p1 = "/a/b/foo"
 499 //        p2 = "/a/b/bar"
 500 //        max_lcp_len = 3
 501 // -> returns 3
 502 static size_t find_lcp_of_two_paths(const char* p1, const char* p2, size_t max_lcp_len) {
 503   size_t lcp_len = 0;
 504   char sep = os::file_separator()[0];
 505   for (size_t i = 0; ; i++) {
 506     char c1 = *p1++;
 507     char c2 = *p2++;
 508     if (c1 == 0 || c2 == 0 || c1 != c2) {
 509       break;
 510     }
 511     if (c1 == sep) {
 512       lcp_len = i + 1;
 513       assert(lcp_len <= max_lcp_len, "sanity");
 514       if (lcp_len == max_lcp_len) {
 515         break;
 516       }
 517     }
 518   }
 519   return lcp_len;
 520 }
 521 
 522 // cheap-allocated if lcp_len > 0
 523 const char* AOTClassLocationConfig::find_lcp(ClassLocationStream& css, size_t& lcp_len) {
 524   const char* first_path = nullptr;
 525   char sep = os::file_separator()[0];
 526 
 527   for (css.start(); css.has_next(); ) {
 528     const char* path = css.get_next();
 529     if (first_path == nullptr) {
 530       first_path = path;
 531       const char* p = strrchr(first_path, sep);
 532       if (p == nullptr) {
 533         lcp_len = 0;
 534         return "";
 535       } else {
 536         lcp_len = p - first_path + 1;
 537       }
 538     } else {
 539       lcp_len = find_lcp_of_two_paths(first_path, path, lcp_len);
 540       if (lcp_len == 0) {
 541         return "";
 542       }
 543     }
 544   }
 545 
 546   if (first_path != nullptr && lcp_len > 0) {
 547     char* lcp = NEW_C_HEAP_ARRAY(char, lcp_len + 1, mtClassShared);
 548     lcp[0] = 0;
 549     strncat(lcp, first_path, lcp_len);
 550     return lcp;
 551   } else {
 552     lcp_len = 0;
 553     return "";
 554   }
 555 }
 556 
 557 void AOTClassLocationConfig::parse(JavaThread* current, GrowableClassLocationArray& tmp_array,
 558                                    ClassLocationStream& css, Group group, bool parse_manifest) {
 559   for (css.start(); css.has_next(); ) {
 560     add_class_location(current, tmp_array, css.get_next(), group, parse_manifest, /*from_cpattr*/false);
 561   }
 562 }
 563 
 564 void AOTClassLocationConfig::add_class_location(JavaThread* current, GrowableClassLocationArray& tmp_array,
 565                                                 const char* path, Group group, bool parse_manifest, bool from_cpattr) {
 566   AOTClassLocation* cs = AOTClassLocation::allocate(current, path, tmp_array.length(), group, from_cpattr);
 567   tmp_array.append(cs);
 568 
 569   if (!parse_manifest) {
 570     // parse_manifest is true for -classpath and -Xbootclasspath/a, and false for --module-path.
 571     return;
 572   }
 573 
 574   ResourceMark rm;
 575   char* cp_attr = cs->get_cpattr(); // resource allocated
 576   if (cp_attr != nullptr && strlen(cp_attr) > 0) {
 577     //trace_class_path("found Class-Path: ", cp_attr); FIXME
 578 
 579     char sep = os::file_separator()[0];
 580     const char* dir_name = cs->path();
 581     const char* dir_tail = strrchr(dir_name, sep);
 582 #ifdef _WINDOWS
 583     // On Windows, we also support forward slash as the file separator when locating entries in the classpath entry.
 584     const char* dir_tail2 = strrchr(dir_name, '/');
 585     if (dir_tail == nullptr) {
 586       dir_tail = dir_tail2;
 587     } else if (dir_tail2 != nullptr && dir_tail2 > dir_tail) {
 588       dir_tail = dir_tail2;
 589     }
 590 #endif
 591     int dir_len;
 592     if (dir_tail == nullptr) {
 593       dir_len = 0;
 594     } else {
 595       dir_len = pointer_delta_as_int(dir_tail, dir_name) + 1;
 596     }
 597 
 598     // Split the cp_attr by spaces, and add each file
 599     char* file_start = cp_attr;
 600     char* end = file_start + strlen(file_start);
 601 
 602     while (file_start < end) {
 603       char* file_end = strchr(file_start, ' ');
 604       if (file_end != nullptr) {
 605         *file_end = 0;
 606         file_end += 1;
 607       } else {
 608         file_end = end;
 609       }
 610 
 611       size_t name_len = strlen(file_start);
 612       if (name_len > 0) {
 613         ResourceMark rm(current);
 614         size_t libname_len = dir_len + name_len;
 615         char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1);
 616         int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start);
 617         assert((size_t)n == libname_len, "Unexpected number of characters in string");
 618 
 619         // Avoid infinite recursion when two JAR files refer to each
 620         // other via cpattr.
 621         bool found_duplicate = false;
 622         for (int i = boot_cp_start_index(); i < tmp_array.length(); i++) {
 623           if (strcmp(tmp_array.at(i)->path(), libname) == 0) {
 624             found_duplicate = true;
 625             break;
 626           }
 627         }
 628         if (!found_duplicate) {
 629           add_class_location(current, tmp_array, libname, group, parse_manifest, /*from_cpattr*/true);
 630         }
 631       }
 632 
 633       file_start = file_end;
 634     }
 635   }
 636 }
 637 
 638 AOTClassLocation const* AOTClassLocationConfig::class_location_at(int index) const {
 639   return _class_locations->at(index);
 640 }
 641 
 642 int AOTClassLocationConfig::get_module_shared_path_index(Symbol* location) const {
 643   if (location->starts_with("jrt:", 4)) {
 644     assert(class_location_at(0)->is_modules_image(), "sanity");
 645     return 0;
 646   }
 647 
 648   if (num_module_paths() == 0) {
 649     // The archive(s) were created without --module-path option
 650     return -1;
 651   }
 652 
 653   if (!location->starts_with("file:", 5)) {
 654     return -1;
 655   }
 656 
 657   // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table()
 658   ResourceMark rm;
 659   const char* file = ClassLoader::uri_to_path(location->as_C_string());
 660   for (int i = module_path_start_index(); i < module_path_end_index(); i++) {
 661     const AOTClassLocation* cs = class_location_at(i);
 662     assert(!cs->has_unnamed_module(), "must be");
 663     bool same = os::same_files(file, cs->path());
 664     log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i,
 665                            location->as_C_string(), cs->path(), same ? "same" : "different");
 666     if (same) {
 667       return i;
 668     }
 669   }
 670   return -1;
 671 }
 672 
 673 // We allow non-empty dirs as long as no classes have been loaded from them.
 674 void AOTClassLocationConfig::check_nonempty_dirs() const {
 675   assert(CDSConfig::is_dumping_archive(), "sanity");
 676 
 677   bool has_nonempty_dir = false;
 678   dumptime_iterate([&](AOTClassLocation* cs) {
 679     if (cs->index() > _max_used_index) {
 680       return false; // stop iterating
 681     }
 682     if (cs->is_dir()) {
 683       if (!os::dir_is_empty(cs->path())) {
 684         log_error(cds)("Error: non-empty directory '%s'", cs->path());
 685         has_nonempty_dir = true;
 686       }
 687     }
 688     return true; // keep iterating
 689   });
 690 
 691   if (has_nonempty_dir) {
 692     vm_exit_during_cds_dumping("Cannot have non-empty directory in paths", nullptr);
 693   }
 694 }
 695 
 696 AOTClassLocationConfig* AOTClassLocationConfig::write_to_archive() const {
 697   Array<AOTClassLocation*>* archived_copy = ArchiveBuilder::new_ro_array<AOTClassLocation*>(_class_locations->length());
 698   for (int i = 0; i < _class_locations->length(); i++) {
 699     archived_copy->at_put(i, _class_locations->at(i)->write_to_archive());
 700     ArchivePtrMarker::mark_pointer((address*)archived_copy->adr_at(i));
 701   }
 702 
 703   AOTClassLocationConfig* dumped = (AOTClassLocationConfig*)ArchiveBuilder::ro_region_alloc(sizeof(AOTClassLocationConfig));
 704   memcpy(dumped, this, sizeof(AOTClassLocationConfig));
 705   dumped->_class_locations = archived_copy;
 706   ArchivePtrMarker::mark_pointer(&dumped->_class_locations);
 707 
 708   return dumped;
 709 }
 710 
 711 bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_aot_linked_classes,
 712                                               int index_start, int index_end,
 713                                               ClassLocationStream& runtime_css,
 714                                               bool use_lcp_match, const char* runtime_lcp,
 715                                               size_t runtime_lcp_len) const {
 716   if (index_start >= index_end && runtime_css.is_empty()) { // nothing to check
 717     return true;
 718   }
 719 
 720   ResourceMark rm;
 721   const char* which = is_boot_classpath ? "boot" : "app";
 722   LogTarget(Info, class, path) lt;
 723   if (lt.is_enabled()) {
 724     LogStream ls(lt);
 725     ls.print("Checking %s classpath", which);
 726     ls.print_cr("%s", use_lcp_match ? " (with longest common prefix substitution)" : "");
 727     ls.print("- expected : '");
 728     print_dumptime_classpath(ls, index_start, index_end, use_lcp_match, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len);
 729     ls.print_cr("'");
 730     ls.print("- actual   : '");
 731     runtime_css.print(&ls);
 732     ls.print_cr("'");
 733   }
 734 
 735   runtime_css.start();
 736   for (int i = index_start; i < index_end; i++) {
 737     ResourceMark rm;
 738     const AOTClassLocation* cs = class_location_at(i);
 739     const char* effective_dumptime_path = cs->path();
 740     if (use_lcp_match && _dumptime_lcp_len > 0) {
 741       effective_dumptime_path = substitute(effective_dumptime_path, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len);
 742     }
 743 
 744     log_info(class, path)("Checking '%s' %s%s", effective_dumptime_path, cs->file_type_string(),
 745                           cs->from_cpattr() ? " (from JAR manifest ClassPath attribute)" : "");
 746     if (!cs->from_cpattr() && file_exists(effective_dumptime_path)) {
 747       if (!runtime_css.has_next()) {
 748         log_warning(cds)("%s classpath has fewer elements than expected", which);
 749         return false;
 750       }
 751       const char* runtime_path = runtime_css.get_next();
 752       while (!file_exists(runtime_path) && runtime_css.has_next()) {
 753         runtime_path = runtime_css.get_next();
 754       }
 755       if (!os::same_files(effective_dumptime_path, runtime_path)) {
 756         log_warning(cds)("The name of %s classpath [%d] does not match: expected '%s', got '%s'",
 757                          which, runtime_css.current(), effective_dumptime_path, runtime_path);
 758         return false;
 759       }
 760     }
 761 
 762     if (!cs->check(effective_dumptime_path, has_aot_linked_classes)) {
 763       return false;
 764     }
 765   }
 766 
 767   // Check if the runtime boot classpath has more entries than the one stored in the archive and if the app classpath
 768   // or the module path requires validation.
 769   if (is_boot_classpath && runtime_css.has_next() && (need_to_check_app_classpath() || num_module_paths() > 0)) {
 770     // the check passes if all the extra runtime boot classpath entries are non-existent
 771     if (check_paths_existence(runtime_css)) {
 772       log_warning(cds)("boot classpath is longer than expected");
 773       return false;
 774     }
 775   }
 776 
 777   return true;
 778 }
 779 
 780 bool AOTClassLocationConfig::file_exists(const char* filename) const{
 781   struct stat st;
 782   return (os::stat(filename, &st) == 0 && st.st_size > 0);
 783 }
 784 
 785 bool AOTClassLocationConfig::check_paths_existence(ClassLocationStream& runtime_css) const {
 786   bool exist = false;
 787   while (runtime_css.has_next()) {
 788     const char* path = runtime_css.get_next();
 789     if (file_exists(path)) {
 790       exist = true;
 791       break;
 792     }
 793   }
 794   return exist;
 795 }
 796 
 797 bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, int index_start, int index_end,
 798                                                 ClassLocationStream& runtime_css,
 799                                                 bool* has_extra_module_paths) const {
 800   if (index_start >= index_end && runtime_css.is_empty()) { // nothing to check
 801     return true;
 802   }
 803 
 804   ResourceMark rm;
 805 
 806   LogTarget(Info, class, path) lt;
 807   if (lt.is_enabled()) {
 808     LogStream ls(lt);
 809     ls.print_cr("Checking module paths");
 810     ls.print("- expected : '");
 811     print_dumptime_classpath(ls, index_start, index_end, false, 0, nullptr, 0);
 812     ls.print_cr("'");
 813     ls.print("- actual   : '");
 814     runtime_css.print(&ls);
 815     ls.print_cr("'");
 816   }
 817 
 818   // Make sure all the dumptime module paths exist and are unchanged
 819   for (int i = index_start; i < index_end; i++) {
 820     const AOTClassLocation* cs = class_location_at(i);
 821     const char* dumptime_path = cs->path();
 822 
 823     assert(!cs->from_cpattr(), "not applicable for module path");
 824     log_info(class, path)("Checking '%s' %s", dumptime_path, cs->file_type_string());
 825 
 826     if (!cs->check(dumptime_path, has_aot_linked_classes)) {
 827       return false;
 828     }
 829   }
 830 
 831   // We allow runtime_css to be a superset of the module paths specified in dumptime. E.g.,
 832   // Dumptime:    A:C
 833   // Runtime:     A:B:C
 834   runtime_css.start();
 835   for (int i = index_start; i < index_end; i++) {
 836     const AOTClassLocation* cs = class_location_at(i);
 837     const char* dumptime_path = cs->path();
 838 
 839     while (true) {
 840       if (!runtime_css.has_next()) {
 841         log_warning(cds)("module path has fewer elements than expected");
 842         *has_extra_module_paths = true;
 843         return true;
 844       }
 845       // Both this->class_locations() and runtime_css are alphabetically sorted. Skip
 846       // items in runtime_css until we see dumptime_path.
 847       const char* runtime_path = runtime_css.get_next();
 848       if (!os::same_files(dumptime_path, runtime_path)) {
 849         *has_extra_module_paths = true;
 850         return true;
 851       } else {
 852         break;
 853       }
 854     }
 855   }
 856 
 857   if (runtime_css.has_next()) {
 858     *has_extra_module_paths = true;
 859   }
 860 
 861   return true;
 862 }
 863 
 864 void AOTClassLocationConfig::print_dumptime_classpath(LogStream& ls, int index_start, int index_end,
 865                                                       bool do_substitute, size_t remove_prefix_len,
 866                                                       const char* prepend, size_t prepend_len) const {
 867   const char* sep = "";
 868   for (int i = index_start; i < index_end; i++) {
 869     ResourceMark rm;
 870     const AOTClassLocation* cs = class_location_at(i);
 871     const char* path = cs->path();
 872     if (!cs->from_cpattr()) {
 873       ls.print("%s", sep);
 874       if (do_substitute) {
 875         path = substitute(path, remove_prefix_len, prepend, prepend_len);
 876       }
 877       ls.print("%s", path);
 878       sep = os::path_separator();
 879     }
 880   }
 881 }
 882 
 883 // Returned path is resource-allocated
 884 const char* AOTClassLocationConfig::substitute(const char* path,         // start with this path (which was recorded from dump time)
 885                                                size_t remove_prefix_len, // remove this number of chars from the beginning
 886                                                const char* prepend,      // prepend this string
 887                                                size_t prepend_len) {     // length of the prepended string
 888   size_t len = strlen(path);
 889   assert(len > remove_prefix_len, "sanity");
 890   assert(prepend_len == strlen(prepend), "sanity");
 891   len -= remove_prefix_len;
 892   len += prepend_len;
 893 
 894   char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
 895   int n = os::snprintf(buf, len + 1, "%s%s", prepend, path + remove_prefix_len);
 896   assert(size_t(n) == len, "sanity");
 897 
 898   return buf;
 899 }
 900 
 901 // For performance, we avoid using LCP match if there's at least one
 902 // AOTClassLocation can be matched exactly: this means all other AOTClassLocations must be
 903 // matched exactly.
 904 bool AOTClassLocationConfig::need_lcp_match(AllClassLocationStreams& all_css) const {
 905   if (app_cp_end_index() == boot_cp_start_index()) {
 906     // No need to use lcp-match when there are no boot/app paths.
 907     // TODO: LCP-match not yet supported for modules.
 908     return false;
 909   }
 910 
 911   if (need_lcp_match_helper(boot_cp_start_index(), boot_cp_end_index(), all_css.boot_cp()) &&
 912       need_lcp_match_helper(app_cp_start_index(), app_cp_end_index(), all_css.app_cp())) {
 913     return true;
 914   } else {
 915     return false;
 916   }
 917 }
 918 
 919 bool AOTClassLocationConfig::need_lcp_match_helper(int start, int end, ClassLocationStream& css) const {
 920   int i = start;
 921   for (css.start(); i < end && css.has_next(); ) {
 922     const AOTClassLocation* cs = class_location_at(i++);
 923     const char* runtime_path = css.get_next();
 924     if (cs->must_exist() && os::same_files(cs->path(), runtime_path)) {
 925       // Most likely, we will come to here at the first iteration.
 926       return false;
 927     }
 928   }
 929   return true;
 930 }
 931 
 932 bool AOTClassLocationConfig::validate(bool has_aot_linked_classes, bool* has_extra_module_paths) const {
 933   ResourceMark rm;
 934   AllClassLocationStreams all_css;
 935 
 936   const char* jrt = ClassLoader::get_jrt_entry()->name();
 937   bool success = class_location_at(0)->check(jrt, has_aot_linked_classes);
 938   log_info(class, path)("Modules image %s validation: %s", jrt, success ? "passed" : "failed");
 939   if (!success) {
 940     return false;
 941   }
 942   if (class_locations()->length() == 1) {
 943     if ((module_path_start_index() >= module_path_end_index()) && Arguments::get_property("jdk.module.path") != nullptr) {
 944       *has_extra_module_paths = true;
 945     } else {
 946       *has_extra_module_paths = false;
 947     }
 948   } else {
 949     bool use_lcp_match = need_lcp_match(all_css);
 950     const char* runtime_lcp;
 951     size_t runtime_lcp_len;
 952 
 953     log_info(class, path)("Longest common prefix substitution in boot/app classpath matching: %s",
 954                           use_lcp_match ? "yes" : "no");
 955     if (use_lcp_match) {
 956       runtime_lcp = find_lcp(all_css.boot_and_app_cp(), runtime_lcp_len);
 957       log_info(class, path)("Longest common prefix: %s (%zu chars)", runtime_lcp, runtime_lcp_len);
 958     } else {
 959       runtime_lcp = nullptr;
 960       runtime_lcp_len = 0;
 961     }
 962 
 963     success = check_classpaths(true, has_aot_linked_classes, boot_cp_start_index(), boot_cp_end_index(), all_css.boot_cp(),
 964                                use_lcp_match, runtime_lcp, runtime_lcp_len);
 965     log_info(class, path)("Archived boot classpath validation: %s", success ? "passed" : "failed");
 966 
 967     if (success && need_to_check_app_classpath()) {
 968       success = check_classpaths(false, has_aot_linked_classes, app_cp_start_index(), app_cp_end_index(), all_css.app_cp(),
 969                                  use_lcp_match, runtime_lcp, runtime_lcp_len);
 970       log_info(class, path)("Archived app classpath validation: %s", success ? "passed" : "failed");
 971     }
 972 
 973     if (success) {
 974       success = check_module_paths(has_aot_linked_classes, module_path_start_index(), module_path_end_index(),
 975                                    all_css.module_path(), has_extra_module_paths);
 976       log_info(class, path)("Archived module path validation: %s%s", success ? "passed" : "failed",
 977                             (*has_extra_module_paths) ? " (extra module paths found)" : "");
 978     }
 979 
 980     if (runtime_lcp_len > 0) {
 981       os::free((void*)runtime_lcp);
 982     }
 983   }
 984 
 985   if (success) {
 986     _runtime_instance = this;
 987   } else {
 988     const char* mismatch_msg = "shared class paths mismatch";
 989     const char* hint_msg = log_is_enabled(Info, class, path) ?
 990         "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)";
 991     if (RequireSharedSpaces && !PrintSharedArchiveAndExit) {
 992       if (CDSConfig::is_dumping_final_static_archive()) {
 993         log_error(cds)("class path and/or module path are not compatible with the "
 994                        "ones specified when the AOTConfiguration file was recorded%s", hint_msg);
 995         vm_exit_during_initialization("Unable to use create AOT cache.", nullptr);
 996       } else {
 997         log_error(cds)("%s%s", mismatch_msg, hint_msg);
 998         MetaspaceShared::unrecoverable_loading_error();
 999       }
1000     } else {
1001       log_warning(cds)("%s%s", mismatch_msg, hint_msg);
1002     }
1003   }
1004   return success;
1005 }