8227370: Remove SharedPathsMiscInfo

Reviewed-by: ccheung, jiangli
This commit is contained in:
Ioi Lam 2019-08-27 22:14:52 -07:00
parent 11ca73d744
commit 87eefe2e00
16 changed files with 407 additions and 618 deletions

View File

@ -73,9 +73,6 @@
#include "utilities/events.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_CDS
#include "classfile/sharedPathsMiscInfo.hpp"
#endif
// Entry points in zip.dll for loading zip/jar file entries
@ -147,7 +144,6 @@ ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
ClassPathEntry* ClassLoader::_module_path_entries = NULL;
ClassPathEntry* ClassLoader::_last_module_path_entry = NULL;
SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
#endif
// helper routines
@ -250,13 +246,12 @@ PackageEntry* ClassLoader::get_package_entry(const char* class_name, ClassLoader
return pkgEntryTable->lookup_only(pkg_symbol);
}
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
strcpy(copy, dir);
_dir = copy;
const char* ClassPathEntry::copy_path(const char* path) {
char* copy = NEW_C_HEAP_ARRAY(char, strlen(path)+1, mtClass);
strcpy(copy, path);
return copy;
}
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
// construct full path name
assert((_dir != NULL) && (name != NULL), "sanity");
@ -296,9 +291,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name,
bool is_boot_append, bool from_class_path_attr) : ClassPathEntry() {
_zip = zip;
char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
strcpy(copy, zip_name);
_zip_name = copy;
_zip_name = copy_path(zip_name);
_from_class_path_attr = from_class_path_attr;
}
@ -383,8 +376,7 @@ ClassPathImageEntry::ClassPathImageEntry(JImageFile* jimage, const char* name) :
assert(_singleton == NULL, "VM supports only one jimage");
DEBUG_ONLY(_singleton = this);
size_t len = strlen(name) + 1;
_name = NEW_C_HEAP_ARRAY(const char, len, mtClass);
strncpy((char *)_name, name, len);
_name = copy_path(name);
}
ClassPathImageEntry::~ClassPathImageEntry() {
@ -537,30 +529,10 @@ void ClassLoader::setup_bootstrap_search_path() {
} else {
trace_class_path("bootstrap loader class path=", sys_class_path);
}
#if INCLUDE_CDS
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
_shared_paths_misc_info->add_boot_classpath(sys_class_path);
}
#endif
setup_boot_search_path(sys_class_path);
}
#if INCLUDE_CDS
int ClassLoader::get_shared_paths_misc_info_size() {
return _shared_paths_misc_info->get_used_bytes();
}
void* ClassLoader::get_shared_paths_misc_info() {
return _shared_paths_misc_info->buffer();
}
bool ClassLoader::check_shared_paths_misc_info(void *buf, int size, bool is_static) {
SharedPathsMiscInfo* checker = new SharedPathsMiscInfo((char*)buf, size);
bool result = checker->check(is_static);
delete checker;
return result;
}
void ClassLoader::setup_app_search_path(const char *class_path) {
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
@ -943,11 +915,6 @@ bool ClassLoader::update_class_path_entry_list(const char *path,
}
return true;
} else {
#if INCLUDE_CDS
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
_shared_paths_misc_info->add_nonexist_path(path);
}
#endif
return false;
}
}
@ -1567,12 +1534,6 @@ void ClassLoader::initialize() {
load_zip_library();
// lookup jimage library entry points
load_jimage_library();
#if INCLUDE_CDS
// initialize search path
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
_shared_paths_misc_info = new SharedPathsMiscInfo();
}
#endif
setup_bootstrap_search_path();
}
@ -1580,7 +1541,6 @@ void ClassLoader::initialize() {
void ClassLoader::initialize_shared_path() {
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
ClassLoaderExt::setup_search_paths();
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
}
}

View File

@ -47,17 +47,19 @@ template <typename T> class GrowableArray;
class ClassPathEntry : public CHeapObj<mtClass> {
private:
ClassPathEntry* volatile _next;
protected:
const char* copy_path(const char*path);
public:
ClassPathEntry* next() const;
virtual ~ClassPathEntry() {}
void set_next(ClassPathEntry* next);
virtual bool is_modules_image() const = 0;
virtual bool is_jar_file() const = 0;
virtual bool is_modules_image() const { return false; }
virtual bool is_jar_file() const { return false; }
// Is this entry created from the "Class-path" attribute from a JAR Manifest?
virtual bool from_class_path_attr() const = 0;
virtual bool from_class_path_attr() const { return false; }
virtual const char* name() const = 0;
virtual JImageFile* jimage() const = 0;
virtual void close_jimage() = 0;
virtual JImageFile* jimage() const { return NULL; }
virtual void close_jimage() {}
// Constructor
ClassPathEntry() : _next(NULL) {}
// Attempt to locate file_name through this class path entry.
@ -73,18 +75,14 @@ class ClassPathDirEntry: public ClassPathEntry {
private:
const char* _dir; // Name of directory
public:
bool is_modules_image() const { return false; }
bool is_jar_file() const { return false; }
bool from_class_path_attr() const { return false; }
const char* name() const { return _dir; }
JImageFile* jimage() const { return NULL; }
void close_jimage() {}
ClassPathDirEntry(const char* dir);
ClassPathDirEntry(const char* dir) {
_dir = copy_path(dir);
}
virtual ~ClassPathDirEntry() {}
ClassFileStream* open_stream(const char* name, TRAPS);
};
// Type definitions for zip file and zip file entry
typedef void* jzfile;
typedef struct {
@ -104,12 +102,9 @@ class ClassPathZipEntry: public ClassPathEntry {
const char* _zip_name; // Name of zip archive
bool _from_class_path_attr; // From the "Class-path" attribute of a jar file
public:
bool is_modules_image() const { return false; }
bool is_jar_file() const { return true; }
bool from_class_path_attr() const { return _from_class_path_attr; }
const char* name() const { return _zip_name; }
JImageFile* jimage() const { return NULL; }
void close_jimage() {}
ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append, bool from_class_path_attr);
virtual ~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@ -126,8 +121,6 @@ private:
DEBUG_ONLY(static ClassPathImageEntry* _singleton;)
public:
bool is_modules_image() const;
bool is_jar_file() const { return false; }
bool from_class_path_attr() const { return false; }
bool is_open() const { return _jimage != NULL; }
const char* name() const { return _name == NULL ? "" : _name; }
JImageFile* jimage() const { return _jimage; }
@ -156,8 +149,6 @@ public:
void add_to_list(ClassPathEntry* new_entry);
};
class SharedPathsMiscInfo;
class ClassLoader: AllStatic {
public:
enum ClassLoaderType {
@ -230,8 +221,6 @@ class ClassLoader: AllStatic {
static ClassPathEntry* _last_append_entry;
// Info used by CDS
CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
CDS_ONLY(static ClassPathEntry* _app_classpath_entries;)
CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;)
CDS_ONLY(static ClassPathEntry* _module_path_entries;)
@ -416,10 +405,6 @@ class ClassLoader: AllStatic {
}
return num_entries;
}
static void finalize_shared_paths_misc_info();
static int get_shared_paths_misc_info_size();
static void* get_shared_paths_misc_info();
static bool check_shared_paths_misc_info(void* info, int size, bool is_static);
static void exit_with_path_failure(const char* error, const char* message);
static char* skip_uri_protocol(char* source);
static void record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);

View File

@ -30,7 +30,6 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/klassFactory.hpp"
#include "classfile/modules.hpp"
#include "classfile/sharedPathsMiscInfo.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.inline.hpp"
@ -74,7 +73,6 @@ void ClassLoaderExt::setup_app_search_path() {
trace_class_path("app loader class path (skipped)=", app_class_path);
} else {
trace_class_path("app loader class path=", app_class_path);
shared_paths_misc_info()->add_app_classpath(app_class_path);
ClassLoader::setup_app_search_path(app_class_path);
}
}
@ -212,8 +210,12 @@ void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry,
char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1);
int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start);
assert((size_t)n == libname_len, "Unexpected number of characters in string");
trace_class_path("library = ", libname);
ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */);
if (ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */)) {
trace_class_path("library = ", libname);
} else {
trace_class_path("library (non-existent) = ", libname);
FileMapInfo::record_non_existent_class_path_entry(libname);
}
}
file_start = file_end;
@ -222,7 +224,6 @@ void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry,
}
void ClassLoaderExt::setup_search_paths() {
shared_paths_misc_info()->record_app_offset();
ClassLoaderExt::setup_app_search_path();
}
@ -248,12 +249,6 @@ void ClassLoaderExt::record_result(const s2 classpath_index,
result->set_class_loader_type(classloader_type);
}
void ClassLoaderExt::finalize_shared_paths_misc_info() {
if (!_has_app_classes) {
shared_paths_misc_info()->pop_app();
}
}
// Load the class of the given name from the location given by path. The path is specified by
// the "source:" in the class list file (see classListParser.cpp), and can be a directory or
// a JAR file.

View File

@ -47,9 +47,6 @@ private:
static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size);
static void setup_app_search_path(); // Only when -Xshare:dump
static void process_module_table(ModuleEntryTable* met, TRAPS);
static SharedPathsMiscInfo* shared_paths_misc_info() {
return (SharedPathsMiscInfo*)_shared_paths_misc_info;
}
// index of first app JAR in shared classpath entry table
static jshort _app_class_paths_start_index;
// index of first modular JAR in shared modulepath entry table
@ -84,8 +81,6 @@ public:
return read_manifest(entry, manifest_size, false, THREAD);
}
static void finalize_shared_paths_misc_info();
static jshort app_class_paths_start_index() { return _app_class_paths_start_index; }
static jshort app_module_paths_start_index() { return _app_module_paths_start_index; }

View File

@ -1,178 +0,0 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/sharedPathsMiscInfo.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/arguments.hpp"
#include "runtime/os.inline.hpp"
#include "utilities/ostream.hpp"
SharedPathsMiscInfo::SharedPathsMiscInfo() {
_app_offset = 0;
_buf_size = INITIAL_BUF_SIZE;
_cur_ptr = _buf_start = NEW_C_HEAP_ARRAY(char, _buf_size, mtClass);
_allocated = true;
}
SharedPathsMiscInfo::~SharedPathsMiscInfo() {
if (_allocated) {
FREE_C_HEAP_ARRAY(char, _buf_start);
}
}
void SharedPathsMiscInfo::add_path(const char* path, int type) {
log_info(class, path)("type=%s ", type_name(type));
ClassLoader::trace_class_path("add misc shared path ", path);
write(path, strlen(path) + 1);
write_jint(jint(type));
}
void SharedPathsMiscInfo::ensure_size(size_t needed_bytes) {
assert(_allocated, "cannot modify buffer during validation.");
int used = get_used_bytes();
int target = used + int(needed_bytes);
if (target > _buf_size) {
_buf_size = _buf_size * 2 + (int)needed_bytes;
_buf_start = REALLOC_C_HEAP_ARRAY(char, _buf_start, _buf_size, mtClass);
_cur_ptr = _buf_start + used;
_end_ptr = _buf_start + _buf_size;
}
}
void SharedPathsMiscInfo::write(const void* ptr, size_t size) {
ensure_size(size);
memcpy(_cur_ptr, ptr, size);
_cur_ptr += size;
}
bool SharedPathsMiscInfo::read(void* ptr, size_t size) {
if (_cur_ptr + size <= _end_ptr) {
memcpy(ptr, _cur_ptr, size);
_cur_ptr += size;
return true;
}
return false;
}
bool SharedPathsMiscInfo::fail(const char* msg, const char* name) {
ClassLoader::trace_class_path(msg, name);
MetaspaceShared::set_archive_loading_failed();
return false;
}
void SharedPathsMiscInfo::print_path(outputStream* out, int type, const char* path) {
switch (type) {
case BOOT_PATH:
out->print("Expecting BOOT path=%s", path);
break;
case NON_EXIST:
out->print("Expecting that %s does not exist", path);
break;
case APP_PATH:
ClassLoader::trace_class_path("Expecting -Djava.class.path=", path);
break;
default:
ShouldNotReachHere();
}
}
bool SharedPathsMiscInfo::check(bool is_static) {
// The whole buffer must be 0 terminated so that we can use strlen and strcmp
// without fear.
_end_ptr -= sizeof(jint);
if (_cur_ptr >= _end_ptr) {
return fail("Truncated archive file header");
}
if (*_end_ptr != 0) {
return fail("Corrupted archive file header");
}
jshort cur_index = 0;
FileMapHeader* header = is_static ? FileMapInfo::current_info()->header() :
FileMapInfo::dynamic_info()->header();
jshort max_cp_index = header->max_used_path_index();
jshort module_paths_start_index = header->app_module_paths_start_index();
while (_cur_ptr < _end_ptr) {
jint type;
const char* path = _cur_ptr;
_cur_ptr += strlen(path) + 1;
if (!read_jint(&type)) {
return fail("Corrupted archive file header");
}
LogTarget(Info, class, path) lt;
if (lt.is_enabled()) {
lt.print("type=%s ", type_name(type));
LogStream ls(lt);
print_path(&ls, type, path);
ls.cr();
}
// skip checking the class path(s) which was not referenced during CDS dump
if ((cur_index <= max_cp_index) || (cur_index >= module_paths_start_index)) {
if (!check(type, path, is_static)) {
if (!PrintSharedArchiveAndExit) {
return false;
}
} else {
ClassLoader::trace_class_path("ok");
}
} else {
ClassLoader::trace_class_path("skipped check");
}
cur_index++;
}
return true;
}
bool SharedPathsMiscInfo::check(jint type, const char* path, bool is_static) {
assert(UseSharedSpaces, "runtime only");
switch (type) {
case BOOT_PATH:
break;
case NON_EXIST:
{
struct stat st;
if (os::stat(path, &st) == 0) {
// The file actually exists
// But we want it to not exist -> fail
return fail("File must not exist");
}
}
break;
case APP_PATH:
break;
default:
return fail("Corrupted archive file header");
}
return true;
}

View File

@ -1,168 +0,0 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
#define SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
#include "classfile/classLoader.hpp"
#include "runtime/os.hpp"
class outputStream;
// During dumping time, when processing class paths, we build up the dump-time
// classpath. The JAR files that exist are stored in the list ClassLoader::_first_append_entry.
// However, we need to store other "misc" information for run-time checking, such as
//
// + The values of Arguments::get_sysclasspath() used during dumping.
//
// + The class path elements specified during dumping but did not exist --
// these elements must also be specified at run time, and they also must not
// exist at run time.
//
// These misc items are stored in a linear buffer in SharedPathsMiscInfo.
// The storage format is stream oriented to minimize its size.
//
// When writing the information to the archive file, SharedPathsMiscInfo is stored in
// the archive file header. At run-time, this information is used only during initialization
// (accessed using read() instead of mmap()), and is deallocated afterwards to save space.
//
// The SharedPathsMiscInfo class is used for both creating the the information (during
// dumping time) and validation (at run time). Different constructors are used in the
// two situations. See below.
class SharedPathsMiscInfo : public CHeapObj<mtClass> {
private:
int _app_offset;
protected:
char* _buf_start;
char* _cur_ptr;
char* _end_ptr;
int _buf_size;
bool _allocated; // was _buf_start allocated by me?
void ensure_size(size_t needed_bytes);
void add_path(const char* path, int type);
void write(const void* ptr, size_t size);
bool read(void* ptr, size_t size);
protected:
static bool fail(const char* msg, const char* name = NULL);
bool check(jint type, const char* path, bool is_static);
public:
enum {
INITIAL_BUF_SIZE = 128
};
// This constructor is used when creating the misc information (during dump)
SharedPathsMiscInfo();
// This constructor is used when validating the misc info (during run time)
SharedPathsMiscInfo(char *buff, int size) {
_app_offset = 0;
_cur_ptr = _buf_start = buff;
_end_ptr = _buf_start + size;
_buf_size = size;
_allocated = false;
}
~SharedPathsMiscInfo();
int get_used_bytes() {
return _cur_ptr - _buf_start;
}
void* buffer() {
return _buf_start;
}
// writing --
// The path must not exist at run-time
void add_nonexist_path(const char* path) {
add_path(path, NON_EXIST);
}
// The path must exist, and must contain exactly <num_entries> files/dirs
void add_boot_classpath(const char* path) {
add_path(path, BOOT_PATH);
}
void add_app_classpath(const char* path) {
add_path(path, APP_PATH);
}
void record_app_offset() {
_app_offset = get_used_bytes();
}
void pop_app() {
_cur_ptr = _buf_start + _app_offset;
write_jint(0);
}
int write_jint(jint num) {
write(&num, sizeof(num));
return 0;
}
void write_time(time_t t) {
write(&t, sizeof(t));
}
void write_long(long l) {
write(&l, sizeof(l));
}
bool dump_to_file(int fd) {
int n = get_used_bytes();
return (os::write(fd, _buf_start, n) == (size_t)n);
}
// reading --
private:
enum {
BOOT_PATH = 1,
APP_PATH = 2,
NON_EXIST = 3
};
const char* type_name(int type) {
switch (type) {
case BOOT_PATH: return "BOOT";
case APP_PATH: return "APP";
case NON_EXIST: return "NON_EXIST";
default: ShouldNotReachHere(); return "?";
}
}
void print_path(outputStream* os, int type, const char* path);
bool read_jint(jint *ptr) {
return read(ptr, sizeof(jint));
}
bool read_long(long *ptr) {
return read(ptr, sizeof(long));
}
bool read_time(time_t *ptr) {
return read(ptr, sizeof(time_t));
}
public:
bool check(bool is_static);
};
#endif // SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP

View File

@ -36,7 +36,7 @@
#define NUM_CDS_REGIONS 8 // this must be the same as MetaspaceShared::n_regions
#define CDS_ARCHIVE_MAGIC 0xf00baba2
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
#define CURRENT_CDS_ARCHIVE_VERSION 6
#define CURRENT_CDS_ARCHIVE_VERSION 7
#define INVALID_CDS_ARCHIVE_VERSION -1
struct CDSFileMapRegion {

View File

@ -241,7 +241,6 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
// 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 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
_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 @@ void SharedClassPathEntry::init(bool is_modules_image,
FileMapInfo::fail_stop("Unable to open file %s.", cpe->name());
}
size_t len = strlen(cpe->name()) + 1;
_name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD);
strcpy(_name->data(), cpe->name());
// 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);
}
bool SharedClassPathEntry::validate(bool is_class_path) {
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(), name);
}
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 @@ bool SharedClassPathEntry::validate(bool is_class_path) {
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::metaspace_pointers_do(MetaspaceClosure* it) {
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 SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD
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 @@ void FileMapInfo::allocate_shared_path_table() {
// 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);
}
if (is_jrt) {
cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
} else {
cpe = cpe->next();
}
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();
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::check_nonempty_dir_in_shared_path_table() {
}
}
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 @@ class ManifestStream: public ResourceObj {
}
};
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 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
// 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 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
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 @@ bool FileMapInfo::validate_shared_path_table() {
}
}
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 @@ bool FileMapInfo::validate_shared_path_table() {
}
}
validate_non_existent_class_paths();
_validating_shared_path_table = false;
#if INCLUDE_JVMTI
@ -771,6 +833,26 @@ bool FileMapInfo::validate_shared_path_table() {
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 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
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 @@ bool FileMapInfo::init_from_file(int fd, bool is_static) {
}
}
_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 @@ void FileMapInfo::open_for_write(const char* path) {
// 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 @@ void FileMapInfo::write_header() {
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 @@ bool FileMapInfo::_heap_pointers_need_patching = false;
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 @@ bool FileMapInfo::_memory_mapping_failed = false;
//
// 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 FileMapHeader::validate() {
}
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* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) {
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);

View File

@ -49,8 +49,12 @@ class SharedClassPathEntry {
jar_entry,
signed_jar_entry,
dir_entry,
non_existent_entry,
unknown_entry
};
void set_name(const char* name, TRAPS);
protected:
u1 _type;
bool _from_class_path_attr;
@ -61,24 +65,25 @@ protected:
public:
void init(bool is_modules_image, ClassPathEntry* cpe, TRAPS);
void init_as_non_existent(const char* path, TRAPS);
void metaspace_pointers_do(MetaspaceClosure* it);
bool validate(bool is_class_path = true);
bool validate(bool is_class_path = true) const;
// The _timestamp only gets set for jar files.
bool has_timestamp() {
bool has_timestamp() const {
return _timestamp != 0;
}
bool is_dir() { return _type == dir_entry; }
bool is_modules_image() { return _type == modules_image_entry; }
bool is_jar() { return _type == jar_entry; }
bool is_signed() { return _type == signed_jar_entry; }
void set_is_signed() {
bool is_dir() const { return _type == dir_entry; }
bool is_modules_image() const { return _type == modules_image_entry; }
bool is_jar() const { return _type == jar_entry; }
bool is_signed() const { return _type == signed_jar_entry; }
void set_is_signed() {
_type = signed_jar_entry;
}
bool from_class_path_attr() { return _from_class_path_attr; }
time_t timestamp() const { return _timestamp; }
long filesize() const { return _filesize; }
const char* name() const { return _name->data(); }
const char* name() const;
const char* manifest() const {
return (_manifest == NULL) ? NULL : (const char*)_manifest->data();
}
@ -88,6 +93,7 @@ public:
void set_manifest(Array<u1>* manifest) {
_manifest = manifest;
}
bool check_non_existent() const;
};
struct ArchiveHeapOopmapInfo {
@ -147,30 +153,12 @@ struct FileMapHeader : public CDSFileMapHeaderBase {
// size of the base archive name including NULL terminator
int _base_archive_name_size;
// The _paths_misc_info is a variable-size structure that records "miscellaneous"
// information during dumping. It is generated and validated by the
// SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for
// detailed description.
//
// The _paths_misc_info data is stored as a byte array in the archive file header,
// immediately after the _header field. This information is used only when
// checking the validity of the archive and is deallocated after the archive is loaded.
//
// Note that the _paths_misc_info does NOT include information for JAR files
// that existed during dump time. Their information is stored in _shared_path_table.
int _paths_misc_info_size;
// The following is a table of all the class path entries that were used
// during dumping. At run time, we require these files to exist and have the same
// size/modification time, or else the archive will refuse to load.
//
// All of these entries must be JAR files. The dumping process would fail if a non-empty
// directory was specified in the classpaths. If an empty directory was specified
// it is checked by the _paths_misc_info as described above.
//
// FIXME -- if JAR files in the tail of the list were specified but not used during dumping,
// they should be removed from this table, to save space and to avoid spurious
// loading failures during runtime.
// The following is a table of all the boot/app/module path entries that were used
// during dumping. At run time, we validate these entries according to their
// SharedClassPathEntry::_type. See:
// check_nonempty_dir_in_shared_path_table()
// validate_shared_path_table()
// validate_non_existent_class_paths()
SharedPathTable _shared_path_table;
jshort _app_class_paths_start_index; // Index of first app classpath entry
@ -232,13 +220,14 @@ public:
FileMapHeader * _header;
const char* _full_path;
char* _paths_misc_info;
char* _base_archive_name;
static FileMapInfo* _current_info;
static FileMapInfo* _dynamic_archive_info;
static bool _heap_pointers_need_patching;
static bool _memory_mapping_failed;
static GrowableArray<const char*>* _non_existent_class_paths;
static bool get_base_archive_name_from_header(const char* archive_name,
int* size, char** base_archive_name);
static bool check_archive(const char* archive_name, bool is_static);
@ -246,6 +235,8 @@ public:
bool init_from_file(int fd, bool is_static);
static void metaspace_pointers_do(MetaspaceClosure* it);
void log_paths(const char* msg, int start_idx, int end_idx);
public:
FileMapInfo(bool is_static);
~FileMapInfo();
@ -353,9 +344,13 @@ public:
static void stop_sharing_and_unmap(const char* msg);
static void allocate_shared_path_table();
static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS);
static void check_nonempty_dir_in_shared_path_table();
bool validate_shared_path_table();
static void update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
void validate_non_existent_class_paths();
static void update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
static int num_non_existent_class_paths();
static void record_non_existent_class_path_entry(const char* path);
#if INCLUDE_JVMTI
static ClassFileStream* open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS);

View File

@ -53,7 +53,6 @@ CDSOffsets* CDSOffsets::_all = NULL;
ADD_NEXT(_all, "FileMapHeader::_space[0]", offset_of(FileMapHeader, _space)); \
ADD_NEXT(_all, "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc)); \
ADD_NEXT(_all, "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used)); \
ADD_NEXT(_all, "FileMapHeader::_paths_misc_info_size", offset_of(FileMapHeader, _paths_misc_info_size)); \
ADD_NEXT(_all, "file_header_size", sizeof(FileMapHeader)); \
ADD_NEXT(_all, "DynamicArchiveHeader::_base_archive_crc", offset_of(DynamicArchiveHeader, _base_archive_crc)); \
ADD_NEXT(_all, "CDSFileMapRegion_size", sizeof(CDSFileMapRegion));

View File

@ -95,19 +95,5 @@ public class AppendClasspath {
"-cp", appJar2 + File.pathSeparator + appJar,
"HelloMore")
.assertAbnormalExit(errorMessage1, errorMessage2);
// FAIL: 4) non-existing jar during dump time but jar exists during runtime
TestCommon.testDump(classPath, TestCommon.list("Hello"));
Files.copy(Paths.get(classDir, "hello.jar"),
Paths.get(classDir, newFile),
StandardCopyOption.REPLACE_EXISTING);
TestCommon.run(
"-cp", classPath,
"-Xlog:class+path=trace",
"Hello")
.assertAbnormalExit(errorMessage1, errorMessage2);
}
}

View File

@ -42,6 +42,11 @@ import java.nio.file.Paths;
public class ClassPathAttr {
public static void main(String[] args) throws Exception {
testNormalOps();
testNonExistentJars();
}
static void testNormalOps() throws Exception {
buildCpAttr("cpattr1", "cpattr1.mf", "CpAttr1", "CpAttr1");
buildCpAttr("cpattr1_long", "cpattr1_long.mf", "CpAttr1", "CpAttr1");
buildCpAttr("cpattr2", "cpattr2.mf", "CpAttr2", "CpAttr2");
@ -93,6 +98,37 @@ public class ClassPathAttr {
}
}
static void testNonExistentJars() throws Exception {
buildCpAttr("cpattr6", "cpattr6.mf", "CpAttr6", "CpAttr6");
String cp = TestCommon.getTestJar("cpattr6.jar");
String nonExistPath = System.getProperty("test.classes") + File.separator + "cpattrX.jar";
(new File(nonExistPath)).delete();
TestCommon.testDump(cp, TestCommon.list("CpAttr6"),
"-Xlog:class+path");
TestCommon.run(
"-Xlog:class+path",
"-cp", cp,
"CpAttr6")
.assertNormalExit(output -> {
output.shouldMatch("should be non-existent: .*cpattrX.jar");
});
// Now make nonExistPath exist. CDS still loads, but archived non-system classes will not be used.
Files.copy(Paths.get(cp), Paths.get(nonExistPath),
StandardCopyOption.REPLACE_EXISTING);
TestCommon.run(
"-Xlog:class+path",
"-cp", cp,
"CpAttr6")
.assertNormalExit(output -> {
output.shouldMatch("Archived non-system classes are disabled because the file .*cpattrX.jar exists");
});
}
private static void buildCpAttr(String jarName, String manifest, String enclosingClassName, String ...testClassNames) throws Exception {
String jarClassesDir = System.getProperty("test.classes") + File.separator + jarName + "_classes";
try { Files.createDirectory(Paths.get(jarClassesDir)); } catch (FileAlreadyExistsException e) { }

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* @test
* @summary Handling of non-existent classpath elements during dump time and run time
* @requires vm.cds
* @library /test/lib
* @modules jdk.jartool/sun.tools.jar
* @compile test-classes/Hello.java
* @compile test-classes/HelloMore.java
* @run driver NonExistClasspath
*/
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import jdk.test.lib.process.OutputAnalyzer;
public class NonExistClasspath {
public static void main(String[] args) throws Exception {
String appJar = JarBuilder.getOrCreateHelloJar();
doTest(appJar, false);
doTest(appJar, true);
}
static void doTest(String appJar, boolean bootcp) throws Exception {
String classDir = System.getProperty("test.classes");
String newFile = "non-exist.jar";
String nonExistPath = classDir + File.separator + newFile;
final String errorMessage1 = "Unable to use shared archive";
final String errorMessage2 = "shared class paths mismatch";
final String errorMessage3 = (bootcp ? "BOOT" : "APP") + " classpath mismatch";
(new File(nonExistPath)).delete();
String classPath = nonExistPath + File.pathSeparator + appJar;
TestCommon.testDump("foobar", TestCommon.list("Hello"), make_args(bootcp, classPath));
// The nonExistPath doesn't exist yet, so we should be able to run without problem
TestCommon.run(make_args(bootcp,
classPath,
"-Xlog:class+path=trace",
"Hello"))
.assertNormalExit();
// Replace nonExistPath with another non-existent file in the CP, it should still work
TestCommon.run(make_args(bootcp,
nonExistPath + ".duh" + File.pathSeparator + appJar,
"-Xlog:class+path=trace",
"Hello"))
.assertNormalExit();
// Add a few more non-existent files in the CP, it should still work
TestCommon.run(make_args(bootcp,
nonExistPath + ".duh" + File.pathSeparator +
nonExistPath + ".daa" + File.pathSeparator +
nonExistPath + ".boo" + File.pathSeparator +
appJar,
"-Xlog:class+path=trace",
"Hello"))
.assertNormalExit();
// Or, remove all non-existent paths from the CP, it should still work
TestCommon.run(make_args(bootcp,
appJar,
"-Xlog:class+path=trace",
"Hello"))
.assertNormalExit();
// Now make nonExistPath exist. CDS will fail to load.
Files.copy(Paths.get(classDir, "hello.jar"),
Paths.get(classDir, newFile),
StandardCopyOption.REPLACE_EXISTING);
TestCommon.run(make_args(bootcp,
classPath,
"-Xlog:class+path=trace",
"Hello"))
.assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3);
}
static String[] make_args(boolean bootcp, String cp, String... suffix) {
String args[];
if (bootcp) {
args = TestCommon.concat("-Xbootclasspath/a:" + cp);
} else {
args = TestCommon.concat("-cp", cp);
}
return TestCommon.concat(args, suffix);
}
}

View File

@ -61,7 +61,6 @@ public class SharedArchiveConsistency {
public static int offset_version; // CDSFileMapHeaderBase::_version
public static int offset_jvm_ident; // FileMapHeader::_jvm_ident
public static int sp_offset_crc; // CDSFileMapRegion::_crc
public static int offset_paths_misc_info_size;
public static int file_header_size = -1;// total size of header, variant, need calculation
public static int CDSFileMapRegion_size; // size of CDSFileMapRegion
public static int sp_offset; // offset of CDSFileMapRegion
@ -117,12 +116,6 @@ public class SharedArchiveConsistency {
// this is not real header size, it is struct size
int_size = wb.getOffsetForName("int_size");
file_header_size = wb.getOffsetForName("file_header_size");
offset_paths_misc_info_size = wb.getOffsetForName("FileMapHeader::_paths_misc_info_size") -
offset_magic;
int path_misc_info_size = (int)readInt(fc, offset_paths_misc_info_size, int_size);
file_header_size += path_misc_info_size;
System.out.println("offset_paths_misc_info_size = " + offset_paths_misc_info_size);
System.out.println("path_misc_info_size = " + path_misc_info_size);
System.out.println("file_header_size = " + file_header_size);
file_header_size = (int)align_up_page(file_header_size);
System.out.println("file_header_size (aligned to page) = " + file_header_size);
@ -405,10 +398,9 @@ public class SharedArchiveConsistency {
output.shouldNotContain("Checksum verification failed");
copyFile(orgJsaFile, jsa);
// modify _jvm_ident and _paths_misc_info_size, test should fail
System.out.println("\n2a. Corrupt _jvm_ident and _paths_misc_info_size, should fail\n");
// modify _jvm_ident, test should fail
System.out.println("\n2a. Corrupt _jvm_ident, should fail\n");
modifyJvmIdent();
modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE);
output = TestCommon.execCommon(execArgs);
output.shouldContain("The shared archive file was created by a different version or build of HotSpot");
output.shouldNotContain("Checksum verification failed");
@ -422,19 +414,17 @@ public class SharedArchiveConsistency {
output.shouldContain("Hello World");
copyFile(orgJsaFile, jsa);
// modify _magic and _paths_misc_info_size, test should fail
System.out.println("\n2c. Corrupt _magic and _paths_misc_info_size, should fail\n");
// modify _magic, test should fail
System.out.println("\n2c. Corrupt _magic, should fail\n");
modifyHeaderIntField(offset_magic, 0x00000000);
modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE);
output = TestCommon.execCommon(execArgs);
output.shouldContain("The shared archive file has a bad magic number");
output.shouldNotContain("Checksum verification failed");
copyFile(orgJsaFile, jsa);
// modify _version and _paths_misc_info_size, test should fail
System.out.println("\n2d. Corrupt _version and _paths_misc_info_size, should fail\n");
// modify _version, test should fail
System.out.println("\n2d. Corrupt _version, should fail\n");
modifyHeaderIntField(offset_version, 0x00000000);
modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE);
output = TestCommon.execCommon(execArgs);
output.shouldContain("The shared archive file has the wrong version");
output.shouldNotContain("Checksum verification failed");

View File

@ -24,7 +24,7 @@
/*
* @test
* @summary ensure -XX:+TraceClassPaths showing entire expecting app classpath
* @summary ensure -Xlog:class+path showing entire expecting app classpath
* @requires vm.cds
* @library /test/lib
* @modules jdk.jartool/sun.tools.jar
@ -85,22 +85,23 @@ public class TraceLongClasspath {
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps +
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar";
String myCP = longClassPath + ps + appJar;
String dumpCP = longClassPath + ps + appJar;
// Dump an archive with a specified JAR file in -classpath
TestCommon.testDump(myCP, TestCommon.list("Hello"));
TestCommon.testDump(dumpCP, TestCommon.list("Hello"));
// Then try to execute the archive with a different classpath and with -XX:+TraceClassPaths.
// The diagnosis "expecting" app classpath trace should show the entire classpath.
// Then try to execute the archive with a different classpath and with -Xlog:class+path.
// The diagnostic "expecting" app classpath trace should show the entire classpath (excluding any non-existent dump-time paths).
String recordedCP = dummyJar + ps + appJar;
TestCommon.run(
"-XX:+TraceClassPaths", "-Xlog:cds",
"-Xlog:class+path", "-Xlog:cds",
"-cp", appJar,
"Hello")
.assertAbnormalExit(output -> {
output.shouldContain("Unable to use shared archive");
output.shouldContain("shared class paths mismatch");
// the "expecting" app classpath from -XX:+TraceClassPaths should not
// the "expecting" app classpath from -Xlog:class+path should not
// be truncated
output.shouldContain(myCP);
output.shouldContain(recordedCP);
});
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
public class CpAttr6 {
public static void main(String args[]) {
System.out.println("Test passed");
}
}