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 }