src/hotspot/share/memory/filemap.cpp
changeset 57898 5ddb746d45e0
parent 57897 e2e315f1aa63
child 58015 dd84de796f2c
--- a/src/hotspot/share/memory/filemap.cpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/memory/filemap.cpp	Tue Aug 27 22:14:52 2019 -0700
@@ -241,7 +241,6 @@
   // JVM version string ... changes on each build.
   get_header_version(_jvm_ident);
 
-  ClassLoaderExt::finalize_shared_paths_misc_info();
   _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
   _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
   _num_module_paths = ClassLoader::num_module_path_entries();
@@ -257,6 +256,11 @@
   _base_archive_is_default = false;
 }
 
+void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
+  _type = non_existent_entry;
+  set_name(path, THREAD);
+}
+
 void SharedClassPathEntry::init(bool is_modules_image,
                                 ClassPathEntry* cpe, TRAPS) {
   assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
@@ -288,26 +292,35 @@
     FileMapInfo::fail_stop("Unable to open file %s.", cpe->name());
   }
 
-  size_t len = strlen(cpe->name()) + 1;
+  // No need to save the name of the module file, as it will be computed at run time
+  // to allow relocation of the JDK directory.
+  const char* name = is_modules_image  ? "" : cpe->name();
+  set_name(name, THREAD);
+}
+
+void SharedClassPathEntry::set_name(const char* name, TRAPS) {
+  size_t len = strlen(name) + 1;
   _name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD);
-  strcpy(_name->data(), cpe->name());
+  strcpy(_name->data(), name);
 }
 
-bool SharedClassPathEntry::validate(bool is_class_path) {
+const char* SharedClassPathEntry::name() const {
+  if (UseSharedSpaces && is_modules_image()) {
+    // In order to validate the runtime modules image file size against the archived
+    // size information, we need to obtain the runtime modules image path. The recorded
+    // dump time modules image path in the archive may be different from the runtime path
+    // if the JDK image has beed moved after generating the archive.
+    return ClassLoader::get_jrt_entry()->name();
+  } else {
+    return _name->data();
+  }
+}
+
+bool SharedClassPathEntry::validate(bool is_class_path) const {
   assert(UseSharedSpaces, "runtime only");
 
   struct stat st;
-  const char* name;
-
-  // In order to validate the runtime modules image file size against the archived
-  // size information, we need to obtain the runtime modules image path. The recorded
-  // dump time modules image path in the archive may be different from the runtime path
-  // if the JDK image has beed moved after generating the archive.
-  if (is_modules_image()) {
-    name = ClassLoader::get_jrt_entry()->name();
-  } else {
-    name = this->name();
-  }
+  const char* name = this->name();
 
   bool ok = true;
   log_info(class, path)("checking shared classpath entry: %s", name);
@@ -345,6 +358,19 @@
   return ok;
 }
 
+bool SharedClassPathEntry::check_non_existent() const {
+  assert(_type == non_existent_entry, "must be");
+  log_info(class, path)("should be non-existent: %s", name());
+  struct stat st;
+  if (os::stat(name(), &st) != 0) {
+    log_info(class, path)("ok");
+    return true; // file doesn't exist
+  } else {
+    return false;
+  }
+}
+
+
 void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
   it->push(&_name);
   it->push(&_manifest);
@@ -359,10 +385,11 @@
 
 void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD) {
   size_t entry_size = sizeof(SharedClassPathEntry);
-  int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
-  int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
-  int num_module_path_entries = ClassLoader::num_module_path_entries();
-  int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
+  int num_entries = 0;
+  num_entries += ClassLoader::num_boot_classpath_entries();
+  num_entries += ClassLoader::num_app_classpath_entries();
+  num_entries += ClassLoader::num_module_path_entries();
+  num_entries += FileMapInfo::num_non_existent_class_paths();
   size_t bytes = entry_size * num_entries;
 
   _table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
@@ -372,7 +399,7 @@
 void FileMapInfo::allocate_shared_path_table() {
   assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
 
-  Thread* THREAD = Thread::current();
+  EXCEPTION_MARK; // The following calls should never throw, but would exit VM on error.
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
   ClassPathEntry* jrt = ClassLoader::get_jrt_entry();
 
@@ -383,47 +410,37 @@
 
   // 1. boot class path
   int i = 0;
-  ClassPathEntry* cpe = jrt;
+  i = add_shared_classpaths(i, "boot",   jrt, THREAD);
+  i = add_shared_classpaths(i, "app",    ClassLoader::app_classpath_entries(), THREAD);
+  i = add_shared_classpaths(i, "module", ClassLoader::module_path_entries(), THREAD);
+
+  for (int x = 0; x < num_non_existent_class_paths(); x++, i++) {
+    const char* path = _non_existent_class_paths->at(x);
+    shared_path(i)->init_as_non_existent(path, THREAD);
+  }
+
+  assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
+}
+
+int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) {
   while (cpe != NULL) {
-    bool is_jrt = (cpe == jrt);
+    bool is_jrt = (cpe == ClassLoader::get_jrt_entry());
     const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
-    log_info(class, path)("add main shared path (%s) %s", type, cpe->name());
+    log_info(class, path)("add %s shared path (%s) %s", which, type, cpe->name());
     SharedClassPathEntry* ent = shared_path(i);
     ent->init(is_jrt, cpe, THREAD);
-    if (!is_jrt) {    // No need to do the modules image.
-      EXCEPTION_MARK; // The following call should never throw, but would exit VM on error.
-      update_shared_classpath(cpe, ent, THREAD);
+    if (cpe->is_jar_file()) {
+      update_jar_manifest(cpe, ent, THREAD);
     }
-    cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
-    i++;
-  }
-  assert(i == ClassLoader::num_boot_classpath_entries(),
-         "number of boot class path entry mismatch");
-
-  // 2. app class path
-  ClassPathEntry *acpe = ClassLoader::app_classpath_entries();
-  while (acpe != NULL) {
-    log_info(class, path)("add app shared path %s", acpe->name());
-    SharedClassPathEntry* ent = shared_path(i);
-    ent->init(false, acpe, THREAD);
-    EXCEPTION_MARK;
-    update_shared_classpath(acpe, ent, THREAD);
-    acpe = acpe->next();
+    if (is_jrt) {
+      cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
+    } else {
+      cpe = cpe->next();
+    }
     i++;
   }
 
-  // 3. module path
-  ClassPathEntry *mpe = ClassLoader::module_path_entries();
-  while (mpe != NULL) {
-    log_info(class, path)("add module path %s",mpe->name());
-    SharedClassPathEntry* ent = shared_path(i);
-    ent->init(false, mpe, THREAD);
-    EXCEPTION_MARK;
-    update_shared_classpath(mpe, ent, THREAD);
-    mpe = mpe->next();
-    i++;
-  }
-  assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
+  return i;
 }
 
 void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
@@ -453,6 +470,24 @@
   }
 }
 
+void FileMapInfo::record_non_existent_class_path_entry(const char* path) {
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
+  log_info(class, path)("non-existent Class-Path entry %s", path);
+  if (_non_existent_class_paths == NULL) {
+    _non_existent_class_paths = new (ResourceObj::C_HEAP, mtInternal)GrowableArray<const char*>(10, true);
+  }
+  _non_existent_class_paths->append(os::strdup(path));
+}
+
+int FileMapInfo::num_non_existent_class_paths() {
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
+  if (_non_existent_class_paths != NULL) {
+    return _non_existent_class_paths->length();
+  } else {
+    return 0;
+  }
+}
+
 class ManifestStream: public ResourceObj {
   private:
   u1*   _buffer_start; // Buffer bottom
@@ -501,29 +536,27 @@
   }
 };
 
-void FileMapInfo::update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
+void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
   ResourceMark rm(THREAD);
   jint manifest_size;
 
-  if (cpe->is_jar_file()) {
-    assert(ent->is_jar(), "the shared class path entry is not a JAR file");
-    char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK);
-    if (manifest != NULL) {
-      ManifestStream* stream = new ManifestStream((u1*)manifest,
-                                                  manifest_size);
-      if (stream->check_is_signed()) {
-        ent->set_is_signed();
-      } else {
-        // Copy the manifest into the shared archive
-        manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK);
-        Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
-                                                        manifest_size,
-                                                        THREAD);
-        char* p = (char*)(buf->data());
-        memcpy(p, manifest, manifest_size);
-        ent->set_manifest(buf);
-      }
+  assert(cpe->is_jar_file() && ent->is_jar(), "the shared class path entry is not a JAR file");
+  char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK);
+  if (manifest != NULL) {
+    ManifestStream* stream = new ManifestStream((u1*)manifest,
+                                                manifest_size);
+    if (stream->check_is_signed()) {
+      ent->set_is_signed();
+    } else {
+      // Copy the manifest into the shared archive
+      manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK);
+      Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
+                                                      manifest_size,
+                                                      THREAD);
+      char* p = (char*)(buf->data());
+      memcpy(p, manifest, manifest_size);
+      ent->set_manifest(buf);
     }
   }
 }
@@ -680,6 +713,16 @@
       // None of the jar file specified in the runtime -cp exists.
       return fail("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp);
     }
+
+    // Handling of non-existent entries in the classpath: we eliminate all the non-existent
+    // entries from both the dump time classpath (ClassLoader::update_class_path_entry_list)
+    // and the runtime classpath (FileMapInfo::create_path_array), and check the remaining
+    // entries. E.g.:
+    //
+    // dump : -cp a.jar:NE1:NE2:b.jar  -> a.jar:b.jar -> recorded in archive.
+    // run 1: -cp NE3:a.jar:NE4:b.jar  -> a.jar:b.jar -> matched
+    // run 2: -cp x.jar:NE4:b.jar      -> x.jar:b.jar -> mismatched
+
     int j = _header->_app_class_paths_start_index;
     mismatch = check_paths(j, shared_app_paths_len, rp_array);
     if (mismatch) {
@@ -689,6 +732,20 @@
   return true;
 }
 
+void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) {
+  LogTarget(Info, class, path) lt;
+  if (lt.is_enabled()) {
+    LogStream ls(lt);
+    ls.print("%s", msg);
+    const char* prefix = "";
+    for (int i = start_idx; i < end_idx; i++) {
+      ls.print("%s%s", prefix, shared_path(i)->name());
+      prefix = os::path_separator();
+    }
+    ls.cr();
+  }
+}
+
 bool FileMapInfo::validate_shared_path_table() {
   assert(UseSharedSpaces, "runtime only");
 
@@ -717,6 +774,9 @@
     }
   }
 
+  log_paths("Expecting BOOT path=", 0, _header->_app_class_paths_start_index);
+  log_paths("Expecting -Djava.class.path=", _header->_app_class_paths_start_index, _header->_app_module_paths_start_index);
+
   int module_paths_start_index = _header->_app_module_paths_start_index;
   int shared_app_paths_len = 0;
 
@@ -757,6 +817,8 @@
     }
   }
 
+  validate_non_existent_class_paths();
+
   _validating_shared_path_table = false;
 
 #if INCLUDE_JVMTI
@@ -771,6 +833,26 @@
   return true;
 }
 
+void FileMapInfo::validate_non_existent_class_paths() {
+  // All of the recorded non-existent paths came from the Class-Path: attribute from the JAR
+  // files on the app classpath. If any of these are found to exist during runtime,
+  // it will change how classes are loading for the app loader. For safety, disable
+  // loading of archived platform/app classes (currently there's no way to disable just the
+  // app classes).
+
+  assert(UseSharedSpaces, "runtime only");
+  for (int i = _header->_app_module_paths_start_index + _header->_num_module_paths;
+       i < get_number_of_shared_paths();
+       i++) {
+    SharedClassPathEntry* ent = shared_path(i);
+    if (!ent->check_non_existent()) {
+      warning("Archived non-system classes are disabled because the "
+              "file %s exists", ent->name());
+      _header->_has_platform_or_app_classes = false;
+    }
+  }
+}
+
 bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
   int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
   if (fd < 0) {
@@ -840,9 +922,6 @@
   if (dynamic_header->_base_archive_is_default) {
     *base_archive_name = Arguments::get_default_shared_archive_path();
   } else {
-    // skip over the _paths_misc_info
-    sz = dynamic_header->_paths_misc_info_size;
-    lseek(fd, (long)sz, SEEK_CUR);
     // read the base archive name
     size_t name_size = dynamic_header->_base_archive_name_size;
     if (name_size == 0) {
@@ -933,18 +1012,7 @@
     }
   }
 
-  _file_offset = n;
-
-  size_t info_size = _header->_paths_misc_info_size;
-  _paths_misc_info = NEW_C_HEAP_ARRAY(char, info_size, mtClass);
-  n = os::read(fd, _paths_misc_info, (unsigned int)info_size);
-  if (n != info_size) {
-    fail_continue("Unable to read the shared path info header.");
-    FREE_C_HEAP_ARRAY(char, _paths_misc_info);
-    _paths_misc_info = NULL;
-    return false;
-  }
-  _file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
+  _file_offset = n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
 
   if (is_static) {
     // just checking the last region is sufficient since the archive is written
@@ -1026,10 +1094,6 @@
 // Write the header to the file, seek to the next allocation boundary.
 
 void FileMapInfo::write_header() {
-  int info_size = ClassLoader::get_shared_paths_misc_info_size();
-
-  _header->_paths_misc_info_size = info_size;
-
   char* base_archive_name = NULL;
   if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) {
     base_archive_name = (char*)Arguments::GetSharedArchivePath();
@@ -1039,7 +1103,6 @@
 
   assert(is_file_position_aligned(), "must be");
   write_bytes(_header, _header->_header_size);
-  write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size);
   if (base_archive_name != NULL) {
     write_bytes(base_archive_name, (size_t)_header->_base_archive_name_size);
   }
@@ -1728,6 +1791,7 @@
 SharedPathTable FileMapInfo::_shared_path_table;
 bool FileMapInfo::_validating_shared_path_table = false;
 bool FileMapInfo::_memory_mapping_failed = false;
+GrowableArray<const char*>* FileMapInfo::_non_existent_class_paths = NULL;
 
 // Open the shared archive file, read and validate the header
 // information (version, boot classpath, etc.).  If initialization
@@ -1736,7 +1800,7 @@
 //
 // Validation of the archive is done in two steps:
 //
-// [1] validate_header() - done here. This checks the header, including _paths_misc_info.
+// [1] validate_header() - done here.
 // [2] validate_shared_path_table - this is done later, because the table is in the RW
 //     region of the archive, which is not mapped yet.
 bool FileMapInfo::initialize(bool is_static) {
@@ -1840,22 +1904,7 @@
 }
 
 bool FileMapInfo::validate_header(bool is_static) {
-  bool status = _header->validate();
-
-  if (status) {
-    if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size, is_static)) {
-      if (!PrintSharedArchiveAndExit) {
-        fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)");
-        status = false;
-      }
-    }
-  }
-
-  if (_paths_misc_info != NULL) {
-    FREE_C_HEAP_ARRAY(char, _paths_misc_info);
-    _paths_misc_info = NULL;
-  }
-  return status;
+  return _header->validate();
 }
 
 // Check if a given address is within one of the shared regions
@@ -1907,7 +1956,7 @@
   ClassPathEntry* ent = _classpath_entries_for_jvmti[i];
   if (ent == NULL) {
     if (i == 0) {
-      ent = ClassLoader:: get_jrt_entry();
+      ent = ClassLoader::get_jrt_entry();
       assert(ent != NULL, "must be");
     } else {
       SharedClassPathEntry* scpe = shared_path(i);