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