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