250 // the following 2 fields will be set in write_header for dynamic archive header |
250 // the following 2 fields will be set in write_header for dynamic archive header |
251 _base_archive_name_size = 0; |
251 _base_archive_name_size = 0; |
252 _base_archive_is_default = false; |
252 _base_archive_is_default = false; |
253 } |
253 } |
254 |
254 |
255 void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) { |
255 void SharedClassPathEntry::init(bool is_modules_image, |
|
256 ClassPathEntry* cpe, TRAPS) { |
256 assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only"); |
257 assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only"); |
257 _timestamp = 0; |
258 _timestamp = 0; |
258 _filesize = 0; |
259 _filesize = 0; |
|
260 _from_class_path_attr = false; |
259 |
261 |
260 struct stat st; |
262 struct stat st; |
261 if (os::stat(name, &st) == 0) { |
263 if (os::stat(cpe->name(), &st) == 0) { |
262 if ((st.st_mode & S_IFMT) == S_IFDIR) { |
264 if ((st.st_mode & S_IFMT) == S_IFDIR) { |
263 _type = dir_entry; |
265 _type = dir_entry; |
264 } else { |
266 } else { |
265 // The timestamp of the modules_image is not checked at runtime. |
267 // The timestamp of the modules_image is not checked at runtime. |
266 if (is_modules_image) { |
268 if (is_modules_image) { |
267 _type = modules_image_entry; |
269 _type = modules_image_entry; |
268 } else { |
270 } else { |
269 _type = jar_entry; |
271 _type = jar_entry; |
270 _timestamp = st.st_mtime; |
272 _timestamp = st.st_mtime; |
|
273 _from_class_path_attr = cpe->from_class_path_attr(); |
271 } |
274 } |
272 _filesize = st.st_size; |
275 _filesize = st.st_size; |
273 } |
276 } |
274 } else { |
277 } else { |
275 // The file/dir must exist, or it would not have been added |
278 // The file/dir must exist, or it would not have been added |
276 // into ClassLoader::classpath_entry(). |
279 // into ClassLoader::classpath_entry(). |
277 // |
280 // |
278 // If we can't access a jar file in the boot path, then we can't |
281 // If we can't access a jar file in the boot path, then we can't |
279 // make assumptions about where classes get loaded from. |
282 // make assumptions about where classes get loaded from. |
280 FileMapInfo::fail_stop("Unable to open file %s.", name); |
283 FileMapInfo::fail_stop("Unable to open file %s.", cpe->name()); |
281 } |
284 } |
282 |
285 |
283 size_t len = strlen(name) + 1; |
286 size_t len = strlen(cpe->name()) + 1; |
284 _name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD); |
287 _name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD); |
285 strcpy(_name->data(), name); |
288 strcpy(_name->data(), cpe->name()); |
286 } |
289 } |
287 |
290 |
288 bool SharedClassPathEntry::validate(bool is_class_path) { |
291 bool SharedClassPathEntry::validate(bool is_class_path) { |
289 assert(UseSharedSpaces, "runtime only"); |
292 assert(UseSharedSpaces, "runtime only"); |
290 |
293 |
379 while (cpe != NULL) { |
382 while (cpe != NULL) { |
380 bool is_jrt = (cpe == jrt); |
383 bool is_jrt = (cpe == jrt); |
381 const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir")); |
384 const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir")); |
382 log_info(class, path)("add main shared path (%s) %s", type, cpe->name()); |
385 log_info(class, path)("add main shared path (%s) %s", type, cpe->name()); |
383 SharedClassPathEntry* ent = shared_path(i); |
386 SharedClassPathEntry* ent = shared_path(i); |
384 ent->init(cpe->name(), is_jrt, THREAD); |
387 ent->init(is_jrt, cpe, THREAD); |
385 if (!is_jrt) { // No need to do the modules image. |
388 if (!is_jrt) { // No need to do the modules image. |
386 EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. |
389 EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. |
387 update_shared_classpath(cpe, ent, THREAD); |
390 update_shared_classpath(cpe, ent, THREAD); |
388 } |
391 } |
389 cpe = ClassLoader::get_next_boot_classpath_entry(cpe); |
392 cpe = ClassLoader::get_next_boot_classpath_entry(cpe); |
518 } |
521 } |
519 } |
522 } |
520 } |
523 } |
521 } |
524 } |
522 |
525 |
|
526 char* FileMapInfo::skip_first_path_entry(const char* path) { |
|
527 size_t path_sep_len = strlen(os::path_separator()); |
|
528 char* p = strstr((char*)path, os::path_separator()); |
|
529 if (p != NULL) { |
|
530 debug_only( { |
|
531 size_t image_name_len = strlen(MODULES_IMAGE_NAME); |
|
532 assert(strncmp(p - image_name_len, MODULES_IMAGE_NAME, image_name_len) == 0, |
|
533 "first entry must be the modules image"); |
|
534 } ); |
|
535 p += path_sep_len; |
|
536 } else { |
|
537 debug_only( { |
|
538 assert(ClassLoader::string_ends_with(path, MODULES_IMAGE_NAME), |
|
539 "first entry must be the modules image"); |
|
540 } ); |
|
541 } |
|
542 return p; |
|
543 } |
|
544 |
|
545 int FileMapInfo::num_paths(const char* path) { |
|
546 if (path == NULL) { |
|
547 return 0; |
|
548 } |
|
549 int npaths = 1; |
|
550 char* p = (char*)path; |
|
551 while (p != NULL) { |
|
552 char* prev = p; |
|
553 p = strstr((char*)p, os::path_separator()); |
|
554 if (p != NULL) { |
|
555 p++; |
|
556 // don't count empty path |
|
557 if ((p - prev) > 1) { |
|
558 npaths++; |
|
559 } |
|
560 } |
|
561 } |
|
562 return npaths; |
|
563 } |
|
564 |
|
565 GrowableArray<char*>* FileMapInfo::create_path_array(const char* path) { |
|
566 GrowableArray<char*>* path_array = new(ResourceObj::RESOURCE_AREA, mtInternal) |
|
567 GrowableArray<char*>(10); |
|
568 char* begin_ptr = (char*)path; |
|
569 char* end_ptr = strchr((char*)path, os::path_separator()[0]); |
|
570 if (end_ptr == NULL) { |
|
571 end_ptr = strchr((char*)path, '\0'); |
|
572 } |
|
573 while (end_ptr != NULL) { |
|
574 if ((end_ptr - begin_ptr) > 1) { |
|
575 struct stat st; |
|
576 char* temp_name = NEW_RESOURCE_ARRAY(char, (size_t)(end_ptr - begin_ptr + 1)); |
|
577 strncpy(temp_name, begin_ptr, end_ptr - begin_ptr); |
|
578 temp_name[end_ptr - begin_ptr] = '\0'; |
|
579 if (os::stat(temp_name, &st) == 0) { |
|
580 path_array->append(temp_name); |
|
581 } |
|
582 } |
|
583 if (end_ptr < (path + strlen(path))) { |
|
584 begin_ptr = ++end_ptr; |
|
585 end_ptr = strchr(begin_ptr, os::path_separator()[0]); |
|
586 if (end_ptr == NULL) { |
|
587 end_ptr = strchr(begin_ptr, '\0'); |
|
588 } |
|
589 } else { |
|
590 break; |
|
591 } |
|
592 } |
|
593 return path_array; |
|
594 } |
|
595 |
|
596 bool FileMapInfo::fail(const char* msg, const char* name) { |
|
597 ClassLoader::trace_class_path(msg, name); |
|
598 MetaspaceShared::set_archive_loading_failed(); |
|
599 return false; |
|
600 } |
|
601 |
|
602 bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, GrowableArray<char*>* rp_array) { |
|
603 int i = 0; |
|
604 int j = shared_path_start_idx; |
|
605 bool mismatch = false; |
|
606 while (i < num_paths && !mismatch) { |
|
607 while (shared_path(j)->from_class_path_attr()) { |
|
608 // shared_path(j) was expanded from the JAR file attribute "Class-Path:" |
|
609 // during dump time. It's not included in the -classpath VM argument. |
|
610 j++; |
|
611 } |
|
612 if (!os::same_files(shared_path(j)->name(), rp_array->at(i))) { |
|
613 mismatch = true; |
|
614 } |
|
615 i++; |
|
616 j++; |
|
617 } |
|
618 return mismatch; |
|
619 } |
|
620 |
|
621 bool FileMapInfo::validate_boot_class_paths() { |
|
622 // |
|
623 // - Archive contains boot classes only - relaxed boot path check: |
|
624 // Extra path elements appended to the boot path at runtime are allowed. |
|
625 // |
|
626 // - Archive contains application or platform classes - strict boot path check: |
|
627 // Validate the entire runtime boot path, which must be compatible |
|
628 // with the dump time boot path. Appending boot path at runtime is not |
|
629 // allowed. |
|
630 // |
|
631 |
|
632 // The first entry in boot path is the modules_image (guaranteed by |
|
633 // ClassLoader::setup_boot_search_path()). Skip the first entry. The |
|
634 // path of the runtime modules_image may be different from the dump |
|
635 // time path (e.g. the JDK image is copied to a different location |
|
636 // after generating the shared archive), which is acceptable. For most |
|
637 // common cases, the dump time boot path might contain modules_image only. |
|
638 char* runtime_boot_path = Arguments::get_sysclasspath(); |
|
639 char* rp = skip_first_path_entry(runtime_boot_path); |
|
640 assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); |
|
641 int dp_len = _header->_app_class_paths_start_index - 1; // ignore the first path to the module image |
|
642 bool mismatch = false; |
|
643 |
|
644 bool relaxed_check = !header()->has_platform_or_app_classes(); |
|
645 if (dp_len == 0 && rp == NULL) { |
|
646 return true; // ok, both runtime and dump time boot paths have modules_images only |
|
647 } else if (dp_len == 0 && rp != NULL) { |
|
648 if (relaxed_check) { |
|
649 return true; // ok, relaxed check, runtime has extra boot append path entries |
|
650 } else { |
|
651 mismatch = true; |
|
652 } |
|
653 } else if (dp_len > 0 && rp != NULL) { |
|
654 int num; |
|
655 ResourceMark rm; |
|
656 GrowableArray<char*>* rp_array = create_path_array(rp); |
|
657 int rp_len = rp_array->length(); |
|
658 if (rp_len >= dp_len) { |
|
659 if (relaxed_check) { |
|
660 // only check the leading entries in the runtime boot path, up to |
|
661 // the length of the dump time boot path |
|
662 num = dp_len; |
|
663 } else { |
|
664 // check the full runtime boot path, must match with dump time |
|
665 num = rp_len; |
|
666 } |
|
667 mismatch = check_paths(1, num, rp_array); |
|
668 } |
|
669 } |
|
670 |
|
671 if (mismatch) { |
|
672 // The paths are different |
|
673 return fail("[BOOT classpath mismatch, actual =", runtime_boot_path); |
|
674 } |
|
675 return true; |
|
676 } |
|
677 |
|
678 bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { |
|
679 const char *appcp = Arguments::get_appclasspath(); |
|
680 assert(appcp != NULL, "NULL app classpath"); |
|
681 int rp_len = num_paths(appcp); |
|
682 bool mismatch = false; |
|
683 if (rp_len < shared_app_paths_len) { |
|
684 return fail("Run time APP classpath is shorter than the one at dump time: ", appcp); |
|
685 } |
|
686 if (shared_app_paths_len != 0 && rp_len != 0) { |
|
687 // Prefix is OK: E.g., dump with -cp foo.jar, but run with -cp foo.jar:bar.jar. |
|
688 ResourceMark rm; |
|
689 GrowableArray<char*>* rp_array = create_path_array(appcp); |
|
690 if (rp_array->length() == 0) { |
|
691 // None of the jar file specified in the runtime -cp exists. |
|
692 return fail("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp); |
|
693 } |
|
694 int j = _header->_app_class_paths_start_index; |
|
695 mismatch = check_paths(j, shared_app_paths_len, rp_array); |
|
696 if (mismatch) { |
|
697 return fail("[APP classpath mismatch, actual: -Djava.class.path=", appcp); |
|
698 } |
|
699 } |
|
700 return true; |
|
701 } |
523 |
702 |
524 bool FileMapInfo::validate_shared_path_table() { |
703 bool FileMapInfo::validate_shared_path_table() { |
525 assert(UseSharedSpaces, "runtime only"); |
704 assert(UseSharedSpaces, "runtime only"); |
526 |
705 |
527 _validating_shared_path_table = true; |
706 _validating_shared_path_table = true; |
548 "Dynamic archiving is disabled because base layer archive has module path"); |
727 "Dynamic archiving is disabled because base layer archive has module path"); |
549 } |
728 } |
550 } |
729 } |
551 |
730 |
552 int module_paths_start_index = _header->_app_module_paths_start_index; |
731 int module_paths_start_index = _header->_app_module_paths_start_index; |
|
732 int shared_app_paths_len = 0; |
553 |
733 |
554 // validate the path entries up to the _max_used_path_index |
734 // validate the path entries up to the _max_used_path_index |
555 for (int i=0; i < _header->_max_used_path_index + 1; i++) { |
735 for (int i=0; i < _header->_max_used_path_index + 1; i++) { |
556 if (i < module_paths_start_index) { |
736 if (i < module_paths_start_index) { |
557 if (shared_path(i)->validate()) { |
737 if (shared_path(i)->validate()) { |
|
738 // Only count the app class paths not from the "Class-path" attribute of a jar manifest. |
|
739 if (!shared_path(i)->from_class_path_attr() && i >= _header->_app_class_paths_start_index) { |
|
740 shared_app_paths_len++; |
|
741 } |
558 log_info(class, path)("ok"); |
742 log_info(class, path)("ok"); |
559 } else { |
743 } else { |
560 if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) { |
744 if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) { |
561 assert(!UseSharedSpaces, "UseSharedSpaces should be disabled"); |
745 assert(!UseSharedSpaces, "UseSharedSpaces should be disabled"); |
562 } |
746 } |
584 _classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass); |
778 _classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass); |
585 memset((void*)_classpath_entries_for_jvmti, 0, sz); |
779 memset((void*)_classpath_entries_for_jvmti, 0, sz); |
586 #endif |
780 #endif |
587 |
781 |
588 return true; |
782 return true; |
589 } |
|
590 |
|
591 bool FileMapInfo::same_files(const char* file1, const char* file2) { |
|
592 if (strcmp(file1, file2) == 0) { |
|
593 return true; |
|
594 } |
|
595 |
|
596 bool is_same = false; |
|
597 // if the two paths diff only in case |
|
598 struct stat st1; |
|
599 struct stat st2; |
|
600 int ret1; |
|
601 int ret2; |
|
602 ret1 = os::stat(file1, &st1); |
|
603 ret2 = os::stat(file2, &st2); |
|
604 if (ret1 < 0 || ret2 < 0) { |
|
605 // one of the files is invalid. So they are not the same. |
|
606 is_same = false; |
|
607 } else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { |
|
608 // different files |
|
609 is_same = false; |
|
610 #ifndef _WINDOWS |
|
611 } else if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) { |
|
612 // same files |
|
613 is_same = true; |
|
614 #else |
|
615 } else if ((st1.st_size == st2.st_size) && (st1.st_ctime == st2.st_ctime) && |
|
616 (st1.st_mtime == st2.st_mtime)) { |
|
617 // same files |
|
618 is_same = true; |
|
619 #endif |
|
620 } |
|
621 return is_same; |
|
622 } |
783 } |
623 |
784 |
624 bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { |
785 bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { |
625 int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); |
786 int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); |
626 if (fd < 0) { |
787 if (fd < 0) { |
1747 if (os::stat(path, &st) != 0) { |
1908 if (os::stat(path, &st) != 0) { |
1748 char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); ; |
1909 char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); ; |
1749 jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); |
1910 jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); |
1750 THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); |
1911 THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); |
1751 } else { |
1912 } else { |
1752 ent = ClassLoader::create_class_path_entry(path, &st, /*throw_exception=*/true, false, CHECK_NULL); |
1913 ent = ClassLoader::create_class_path_entry(path, &st, /*throw_exception=*/true, false, false, CHECK_NULL); |
1753 } |
1914 } |
1754 } |
1915 } |
1755 |
1916 |
1756 MutexLocker mu(CDSClassFileStream_lock, THREAD); |
1917 MutexLocker mu(CDSClassFileStream_lock, THREAD); |
1757 if (_classpath_entries_for_jvmti[i] == NULL) { |
1918 if (_classpath_entries_for_jvmti[i] == NULL) { |