8276769: -Xshare:auto should tolerate problems in the CDS archive

Reviewed-by: iklam, ccheung
This commit is contained in:
Yumin Qi 2021-12-08 16:20:39 +00:00
parent 79165b738d
commit 3e93e0b809
7 changed files with 257 additions and 133 deletions

View File

@ -121,7 +121,6 @@ void FileMapInfo::fail_continue(const char *msg, ...) {
fail_exit(msg, ap);
} else {
if (log_is_enabled(Info, cds)) {
ResourceMark rm;
LogStream ls(Log(cds)::info());
ls.print("UseSharedSpaces: ");
ls.vprint_cr(msg, ap);
@ -1042,15 +1041,20 @@ void FileMapInfo::validate_non_existent_class_paths() {
}
}
// a utility class for checking file header
// A utility class for reading/validating the GenericCDSFileMapHeader portion of
// a CDS archive's header. The file header of all CDS archives with versions from
// CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12) are guaranteed to always start
// with GenericCDSFileMapHeader. This makes it possible to read important information
// from a CDS archive created by a different version of HotSpot, so that we can
// automatically regenerate the archive as necessary (JDK-8261455).
class FileHeaderHelper {
int _fd;
GenericCDSFileMapHeader _header;
bool _is_valid;
GenericCDSFileMapHeader* _header;
const char* _base_archive_name;
public:
FileHeaderHelper() {
_fd = -1;
}
FileHeaderHelper() : _fd(-1), _is_valid(false), _header(nullptr), _base_archive_name(nullptr) {}
~FileHeaderHelper() {
if (_fd != -1) {
@ -1059,8 +1063,10 @@ public:
}
bool initialize(const char* archive_name) {
log_info(cds)("Opening shared archive: %s", archive_name);
_fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
if (_fd < 0) {
FileMapInfo::fail_continue("Specified shared archive not found (%s)", archive_name);
return false;
}
return initialize(_fd);
@ -1069,117 +1075,185 @@ public:
// for an already opened file, do not set _fd
bool initialize(int fd) {
assert(fd != -1, "Archive should be opened");
// First read the generic header so we know the exact size of the actual header.
GenericCDSFileMapHeader gen_header;
size_t size = sizeof(GenericCDSFileMapHeader);
lseek(fd, 0, SEEK_SET);
size_t n = os::read(fd, (void*)&_header, (unsigned int)size);
size_t n = os::read(fd, (void*)&gen_header, (unsigned int)size);
if (n != size) {
vm_exit_during_initialization("Unable to read generic CDS file map header from shared archive");
FileMapInfo::fail_continue("Unable to read generic CDS file map header from shared archive");
return false;
}
if (gen_header._magic != CDS_ARCHIVE_MAGIC &&
gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
FileMapInfo::fail_continue("The shared archive file has a bad magic number: %#x", gen_header._magic);
return false;
}
if (gen_header._version < CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) {
FileMapInfo::fail_continue("Cannot handle shared archive file version %d. Must be at least %d",
gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION);
return false;
}
size_t filelen = os::lseek(fd, 0, SEEK_END);
if (gen_header._header_size >= filelen) {
FileMapInfo::fail_continue("Archive file header larger than archive file");
return false;
}
// Read the actual header and perform more checks
size = gen_header._header_size;
_header = (GenericCDSFileMapHeader*)NEW_C_HEAP_ARRAY(char, size, mtInternal);
lseek(fd, 0, SEEK_SET);
n = os::read(fd, (void*)_header, (unsigned int)size);
if (n != size) {
FileMapInfo::fail_continue("Unable to read actual CDS file map header from shared archive");
return false;
}
if (!check_crc()) {
return false;
}
if (!check_and_init_base_archive_name()) {
return false;
}
// All fields in the GenericCDSFileMapHeader has been validated.
_is_valid = true;
return true;
}
GenericCDSFileMapHeader* get_generic_file_header() {
return &_header;
assert(_header != nullptr && _is_valid, "must be a valid archive file");
return _header;
}
char* read_base_archive_name() {
assert(_fd != -1, "Archive should be open");
size_t name_size = _header._base_archive_name_size;
assert(name_size != 0, "For non-default base archive, name size should be non-zero!");
char* base_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal);
lseek(_fd, _header._base_archive_name_offset, SEEK_SET); // position to correct offset.
size_t n = os::read(_fd, base_name, (unsigned int)name_size);
if (n != name_size) {
log_info(cds)("Unable to read base archive name from archive");
FREE_C_HEAP_ARRAY(char, base_name);
return nullptr;
const char* base_archive_name() {
assert(_header != nullptr && _is_valid, "must be a valid archive file");
return _base_archive_name;
}
private:
bool check_crc() {
if (VerifySharedSpaces) {
FileMapHeader* header = (FileMapHeader*)_header;
int actual_crc = header->compute_crc();
if (actual_crc != header->crc()) {
log_info(cds)("_crc expected: %d", header->crc());
log_info(cds)(" actual: %d", actual_crc);
FileMapInfo::fail_continue("Header checksum verification failed.");
return false;
}
}
if (base_name[name_size - 1] != '\0' || strlen(base_name) != name_size - 1) {
log_info(cds)("Base archive name is damaged");
FREE_C_HEAP_ARRAY(char, base_name);
return nullptr;
return true;
}
bool check_and_init_base_archive_name() {
unsigned int name_offset = _header->_base_archive_name_offset;
unsigned int name_size = _header->_base_archive_name_size;
unsigned int header_size = _header->_header_size;
if (name_offset + name_size < name_offset) {
FileMapInfo::fail_continue("base_archive_name offset/size overflow: " UINT32_FORMAT "/" UINT32_FORMAT,
name_offset, name_size);
return false;
}
if (!os::file_exists(base_name)) {
log_info(cds)("Base archive %s does not exist", base_name);
FREE_C_HEAP_ARRAY(char, base_name);
return nullptr;
if (_header->_magic == CDS_ARCHIVE_MAGIC) {
if (name_offset != 0) {
FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_offset");
return false;
}
if (name_size != 0) {
FileMapInfo::fail_continue("static shared archive must have zero _base_archive_name_size");
return false;
}
} else {
assert(_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC, "must be");
if ((name_size == 0 && name_offset != 0) ||
(name_size != 0 && name_offset == 0)) {
// If either is zero, both must be zero. This indicates that we are using the default base archive.
FileMapInfo::fail_continue("Invalid base_archive_name offset/size: " UINT32_FORMAT "/" UINT32_FORMAT,
name_offset, name_size);
return false;
}
if (name_size > 0) {
if (name_offset + name_size > header_size) {
FileMapInfo::fail_continue("Invalid base_archive_name offset/size (out of range): "
UINT32_FORMAT " + " UINT32_FORMAT " > " UINT32_FORMAT ,
name_offset, name_size, header_size);
return false;
}
const char* name = ((const char*)_header) + _header->_base_archive_name_offset;
if (name[name_size - 1] != '\0' || strlen(name) != name_size - 1) {
FileMapInfo::fail_continue("Base archive name is damaged");
return false;
}
if (!os::file_exists(name)) {
FileMapInfo::fail_continue("Base archive %s does not exist", name);
return false;
}
_base_archive_name = name;
}
}
return base_name;
return true;
}
};
bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
FileHeaderHelper file_helper;
if (!file_helper.initialize(archive_name)) {
// do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths()
// requires a shared archive name. The open_for_read() function will log a message regarding
// failure in opening a shared archive.
// Any errors are reported by fail_continue().
return false;
}
GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
if (is_static) {
if (header->_magic != CDS_ARCHIVE_MAGIC) {
vm_exit_during_initialization("Not a base shared archive", archive_name);
return false;
}
if (header->_base_archive_name_offset != 0) {
log_info(cds)("_base_archive_name_offset should be 0");
log_info(cds)("_base_archive_name_offset = " UINT32_FORMAT, header->_base_archive_name_offset);
fail_continue("Not a base shared archive: %s", archive_name);
return false;
}
} else {
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
vm_exit_during_initialization("Not a top shared archive", archive_name);
fail_continue("Not a top shared archive: %s", archive_name);
return false;
}
unsigned int name_size = header->_base_archive_name_size;
unsigned int name_offset = header->_base_archive_name_offset;
unsigned int header_size = header->_header_size;
if (name_offset + name_size != header_size) {
log_info(cds)("_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size");
log_info(cds)(" _base_archive_name_size = " UINT32_FORMAT, name_size);
log_info(cds)(" _base_archive_name_offset = " UINT32_FORMAT, name_offset);
log_info(cds)(" _header_size = " UINT32_FORMAT, header_size);
return false;
}
char* base_name = file_helper.read_base_archive_name();
if (base_name == nullptr) {
return false;
}
FREE_C_HEAP_ARRAY(char, base_name);
}
return true;
}
// Return value:
// false:
// <archive_name> is not a valid archive. *base_archive_name is set to null.
// true && (*base_archive_name) == NULL:
// <archive_name> is a valid static archive.
// true && (*base_archive_name) != NULL:
// <archive_name> is a valid dynamic archive.
bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
char** base_archive_name) {
FileHeaderHelper file_helper;
*base_archive_name = NULL;
if (!file_helper.initialize(archive_name)) {
return false;
}
GenericCDSFileMapHeader* header = file_helper.get_generic_file_header();
if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
// Not a dynamic header, no need to proceed further.
return false;
assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be");
return true;
}
if ((header->_base_archive_name_size == 0 && header->_base_archive_name_offset != 0) ||
(header->_base_archive_name_size != 0 && header->_base_archive_name_offset == 0)) {
fail_continue("Default base archive not set correct");
return false;
}
if (header->_base_archive_name_size == 0 &&
header->_base_archive_name_offset == 0) {
const char* base = file_helper.base_archive_name();
if (base == nullptr) {
*base_archive_name = Arguments::get_default_shared_archive_path();
} else {
// read the base archive name
*base_archive_name = file_helper.read_base_archive_name();
if (*base_archive_name == nullptr) {
return false;
}
*base_archive_name = os::strdup_check_oom(base);
}
return true;
}
@ -1247,16 +1321,6 @@ bool FileMapInfo::init_from_file(int fd) {
return false;
}
if (VerifySharedSpaces) {
int expected_crc = header()->compute_crc();
if (expected_crc != header()->crc()) {
log_info(cds)("_crc expected: %d", expected_crc);
log_info(cds)(" actual: %d", header()->crc());
FileMapInfo::fail_continue("Header checksum verification failed.");
return false;
}
}
_file_offset = header()->header_size(); // accounts for the size of _base_archive_name
if (is_static()) {
@ -1294,9 +1358,9 @@ bool FileMapInfo::open_for_read() {
int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
if (fd < 0) {
if (errno == ENOENT) {
fail_continue("Specified shared archive not found (%s).", _full_path);
fail_continue("Specified shared archive not found (%s)", _full_path);
} else {
fail_continue("Failed to open shared archive file (%s).",
fail_continue("Failed to open shared archive file (%s)",
os::strerror(errno));
}
return false;

View File

@ -38,6 +38,7 @@
#define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions
#define CDS_ARCHIVE_MAGIC 0xf00baba2
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 12
#define CURRENT_CDS_ARCHIVE_VERSION 12
typedef struct CDSFileMapRegion {
@ -59,7 +60,8 @@ typedef struct CDSFileMapRegion {
char* _mapped_base; // Actually mapped address (NULL if this region is not mapped).
} CDSFileMapRegion;
// This portion of the archive file header must remain unchanged for _version >= 12.
// This portion of the archive file header must remain unchanged for
// _version >= CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12).
// This makes it possible to read important information from a CDS archive created by
// a different version of HotSpot, so that we can automatically regenerate the archive as necessary.
typedef struct GenericCDSFileMapHeader {

View File

@ -3449,7 +3449,7 @@ jint Arguments::parse_options_buffer(const char* name, char* buffer, const size_
return vm_args->set_args(&options);
}
jint Arguments::set_shared_spaces_flags_and_archive_paths() {
void Arguments::set_shared_spaces_flags_and_archive_paths() {
if (DumpSharedSpaces) {
if (RequireSharedSpaces) {
warning("Cannot dump shared archive while using shared archive");
@ -3459,9 +3459,12 @@ jint Arguments::set_shared_spaces_flags_and_archive_paths() {
#if INCLUDE_CDS
// Initialize shared archive paths which could include both base and dynamic archive paths
// This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly.
init_shared_archive_paths();
//
// UseSharedSpaces may be disabled if -XX:SharedArchiveFile is invalid.
if (DumpSharedSpaces || UseSharedSpaces) {
init_shared_archive_paths();
}
#endif // INCLUDE_CDS
return JNI_OK;
}
#if INCLUDE_CDS
@ -3510,7 +3513,9 @@ void Arguments::extract_shared_archive_paths(const char* archive_path,
char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(cur_path, begin_ptr, len);
cur_path[len] = '\0';
FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/);
if (!FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/)) {
return;
}
*base_archive_path = cur_path;
begin_ptr = ++end_ptr;
@ -3522,7 +3527,9 @@ void Arguments::extract_shared_archive_paths(const char* archive_path,
len = end_ptr - begin_ptr;
cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(cur_path, begin_ptr, len + 1);
FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/);
if (!FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/)) {
return;
}
*top_archive_path = cur_path;
}
@ -3566,17 +3573,26 @@ void Arguments::init_shared_archive_paths() {
"Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
}
if (archives == 1) {
char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
char* base_archive_path = NULL;
bool success =
FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &SharedArchivePath);
FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path);
if (!success) {
SharedArchivePath = temp_archive_path;
no_shared_spaces("invalid archive");
} else if (base_archive_path == NULL) {
// User has specified a single archive, which is a static archive.
SharedArchivePath = const_cast<char *>(SharedArchiveFile);
} else {
SharedDynamicArchivePath = temp_archive_path;
// User has specified a single archive, which is a dynamic archive.
SharedDynamicArchivePath = const_cast<char *>(SharedArchiveFile);
SharedArchivePath = base_archive_path; // has been c-heap allocated.
}
} else {
extract_shared_archive_paths((const char*)SharedArchiveFile,
&SharedArchivePath, &SharedDynamicArchivePath);
if (SharedArchivePath == NULL) {
assert(SharedDynamicArchivePath == NULL, "must be");
no_shared_spaces("invalid archive");
}
}
if (SharedDynamicArchivePath != nullptr) {
@ -4049,8 +4065,7 @@ jint Arguments::apply_ergo() {
GCConfig::arguments()->initialize();
result = set_shared_spaces_flags_and_archive_paths();
if (result != JNI_OK) return result;
set_shared_spaces_flags_and_archive_paths();
// Initialize Metaspace flags and alignments
Metaspace::ergo_initialize();

View File

@ -366,7 +366,7 @@ class Arguments : AllStatic {
static void set_use_compressed_oops();
static void set_use_compressed_klass_ptrs();
static jint set_ergonomics_flags();
static jint set_shared_spaces_flags_and_archive_paths();
static void set_shared_spaces_flags_and_archive_paths();
// Limits the given heap size by the maximum amount of virtual
// memory this process is currently allowed to use. It also takes
// the virtual-to-physical ratio of the current GC into account.

View File

@ -112,7 +112,8 @@ public class SharedArchiveConsistency {
// test, should pass
System.out.println("1. Normal, should pass but may fail\n");
String[] execArgs = {"-Xlog:cds=debug", "-cp", jarFile, "Hello"};
// disable VerifySharedSpaces, it may be turned on by jtreg args
String[] execArgs = {"-Xlog:cds=debug", "-XX:-VerifySharedSpaces", "-cp", jarFile, "Hello"};
// tests that corrupt contents of the archive need to run with
// VerifySharedSpaces enabled to detect inconsistencies
String[] verifyExecArgs = {"-Xlog:cds", "-XX:+VerifySharedSpaces", "-cp", jarFile, "Hello"};
@ -172,7 +173,7 @@ public class SharedArchiveConsistency {
System.out.println("\n2d. Corrupt _version, should fail\n");
String modVersion = startNewArchive("modify-version");
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion);
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000);
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x3FFFFFFF);
output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs);
output.shouldContain("The shared archive file has the wrong version");
output.shouldNotContain("Checksum verification failed");
@ -180,6 +181,17 @@ public class SharedArchiveConsistency {
output.shouldContain(HELLO_WORLD);
}
System.out.println("\n2e. Corrupt _version, should fail\n");
String modVersion2 = startNewArchive("modify-version2");
copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion2);
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000);
output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs);
output.shouldContain("Cannot handle shared archive file version 0. Must be at least 12");
output.shouldNotContain("Checksum verification failed");
if (shareAuto) {
output.shouldContain(HELLO_WORLD);
}
// modify content inside regions
System.out.println("\n3. Corrupt Content, should fail\n");
for (int i=0; i<num_regions; i++) {

View File

@ -30,7 +30,8 @@
* @build Hello sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency on
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency auto
*/
import java.io.File;
@ -40,8 +41,15 @@ import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.helpers.ClassFileInstaller;
public class ArchiveConsistency extends DynamicArchiveTestBase {
private static final String HELLO_WORLD = "Hello World";
private static boolean isAuto;
public static void main(String[] args) throws Exception {
if (args.length != 1 || (!args[0].equals("on") && !args[0].equals("auto"))) {
throw new RuntimeException("Must have one arg either of \"on\" or \"auto\"");
}
isAuto = args[0].equals("auto");
setAutoMode(isAuto);
runTest(ArchiveConsistency::testCustomBase);
}
@ -53,31 +61,39 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
doTest(baseArchiveName, topArchiveName);
}
static boolean VERIFY_CRC = false;
static void runTwo(String base, String top,
String jarName, String mainClassName, int exitValue,
String jarName, String mainClassName, int expectedExitValue,
String ... checkMessages) throws Exception {
CDSTestUtils.Result result = run2(base, top,
"-Xlog:cds",
"-Xlog:cds+dynamic=debug",
"-XX:+VerifySharedSpaces",
VERIFY_CRC ? "-XX:+VerifySharedSpaces" : "-XX:-VerifySharedSpaces",
"-cp",
jarName,
mainClassName);
if (exitValue == 0) {
if (expectedExitValue == 0) {
result.assertNormalExit( output -> {
for (String s : checkMessages) {
output.shouldContain(s);
}
output.shouldContain(HELLO_WORLD);
});
} else {
result.assertAbnormalExit( output -> {
for (String s : checkMessages) {
output.shouldContain(s);
}
output.shouldContain("Unable to use shared archive");
});
}
}
private static void startTest(String str) {
System.out.println("\n" + str);
}
private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
String appJar = ClassFileInstaller.getJarPath("hello.jar");
String mainClass = "Hello";
@ -94,42 +110,36 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
throw new IOException(jsa + " does not exist!");
}
// 1. Modify the CRC values in the header of the top archive.
System.out.println("\n1. Modify the CRC values in the header of the top archive");
startTest("1. Modify the CRC values in the header of the top archive");
String modTop = getNewArchiveName("modTopRegionsCrc");
File copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, modTop);
CDSArchiveUtils.modifyAllRegionsCrc(copiedJsa);
VERIFY_CRC = true;
runTwo(baseArchiveName, modTop,
appJar, mainClass, 1,
new String[] {"Header checksum verification failed",
"Unable to use shared archive"});
appJar, mainClass, isAuto ? 0 : 1,
"Header checksum verification failed");
VERIFY_CRC = false;
// 2. Make header size larger than the archive size
System.out.println("\n2. Make header size larger than the archive size");
startTest("2. Make header size larger than the archive size");
String largerHeaderSize = getNewArchiveName("largerHeaderSize");
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, largerHeaderSize);
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetHeaderSize(), (int)copiedJsa.length() + 1024);
runTwo(baseArchiveName, largerHeaderSize,
appJar, mainClass, 1,
new String[] {"_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size",
"Unable to use shared archive"});
appJar, mainClass, isAuto ? 0 : 1,
"Archive file header larger than archive file");
// 3. Make base archive path offset beyond of header size
System.out.println("\n3. Make base archive path offset beyond of header size.");
startTest("3. Make base archive name offset beyond of header size.");
String wrongBaseArchiveNameOffset = getNewArchiveName("wrongBaseArchiveNameOffset");
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseArchiveNameOffset);
int fileHeaderSize = (int)CDSArchiveUtils.fileHeaderSize(copiedJsa);
int baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa);
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetBaseArchiveNameOffset(), baseArchiveNameOffset + 1024);
runTwo(baseArchiveName, wrongBaseArchiveNameOffset,
appJar, mainClass, 1,
new String[] {"_header_size should be equal to _base_archive_name_offset plus _base_archive_name_size",
"The shared archive file has an incorrect header size",
"Unable to use shared archive"});
appJar, mainClass, isAuto ? 0 : 1,
"Invalid base_archive_name offset/size (out of range)");
// 4. Make base archive path offset points to middle of name size
System.out.println("\n4. Make base archive path offset points to middle of name size");
startTest("4. Make base archive name offset points to middle of the base archive name");
String wrongBaseNameOffset = getNewArchiveName("wrongBaseNameOffset");
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseNameOffset);
int baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa);
@ -137,13 +147,10 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
CDSArchiveUtils.modifyHeaderIntField(copiedJsa, baseArchiveNameOffset,
baseArchiveNameOffset + baseArchiveNameSize/2);
runTwo(baseArchiveName, wrongBaseNameOffset,
appJar, mainClass, 1,
new String[] {"An error has occurred while processing the shared archive file.",
"Header checksum verification failed",
"Unable to use shared archive"});
appJar, mainClass, isAuto ? 0 : 1,
"Base archive name is damaged");
// 5. Make base archive name not terminated with '\0'
System.out.println("\n5. Make base archive name not terminated with '\0'");
startTest("5. Make base archive name not terminated with '\0'");
String wrongBaseName = getNewArchiveName("wrongBaseName");
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName);
baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa);
@ -152,12 +159,10 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
CDSArchiveUtils.writeData(copiedJsa, offset, new byte[] {(byte)'X'});
runTwo(baseArchiveName, wrongBaseName,
appJar, mainClass, 1,
new String[] {"Base archive name is damaged",
"Header checksum verification failed"});
appJar, mainClass, isAuto ? 0 : 1,
"Base archive name is damaged");
// 6. Modify base archive name to a file that doesn't exist.
System.out.println("\n6. Modify base archive name to a file that doesn't exist");
startTest("6. Modify base archive name to a file that doesn't exist");
String wrongBaseName2 = getNewArchiveName("wrongBaseName2");
copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName2);
baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa);
@ -170,8 +175,32 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
(new File(badName)).delete();
runTwo(baseArchiveName, wrongBaseName2,
appJar, mainClass, 1,
new String[] {"Base archive " + badName + " does not exist",
"Header checksum verification failed"});
appJar, mainClass, isAuto ? 0 : 1,
"Base archive " + badName + " does not exist");
// Following three tests:
// -XX:SharedArchiveFile=non-exist-base.jsa:top.jsa
// -XX:SharedArchiveFile=base.jsa:non-exist-top.jsa
// -XX:SharedArchiveFile=non-exist-base.jsa:non-exist-top.jsa
startTest("7. Non-exist base archive");
String nonExistBase = "non-exist-base.jsa";
File nonExistBaseFile = new File(nonExistBase);
nonExistBaseFile.delete();
runTwo(nonExistBase, topArchiveName,
appJar, mainClass, isAuto ? 0 : 1,
"Specified shared archive not found (" + nonExistBase + ")");
startTest("8. Non-exist top archive");
String nonExistTop = "non-exist-top.jsa";
File nonExistTopFile = new File(nonExistTop);
nonExistTopFile.delete();
runTwo(baseArchiveName, nonExistTop,
appJar, mainClass, isAuto ? 0 : 1,
"Specified shared archive not found (" + nonExistTop + ")");
startTest("9. nost-exist-base and non-exist-top");
runTwo(nonExistBase, nonExistTop,
appJar, mainClass, isAuto ? 0 : 1,
"Specified shared archive not found (" + nonExistBase + ")");
}
}

View File

@ -36,6 +36,7 @@ import sun.hotspot.WhiteBox;
*/
class DynamicArchiveTestBase {
private static boolean executedIn_run = false;
private static boolean autoMode = false; // -Xshare:auto
private static final WhiteBox WB = WhiteBox.getWhiteBox();
@ -47,6 +48,7 @@ class DynamicArchiveTestBase {
public void run(String args[]) throws Exception;
}
public static void setAutoMode(boolean val) { autoMode = val; }
/*
* Tests for dynamic archives should be written using this pattern:
@ -183,7 +185,7 @@ class DynamicArchiveTestBase {
(topArchiveName == null) ? baseArchiveName :
baseArchiveName + File.pathSeparator + topArchiveName;
String[] cmdLine = TestCommon.concat(
"-Xshare:on",
autoMode ? "-Xshare:auto" : "-Xshare:on",
"-XX:SharedArchiveFile=" + archiveFiles);
cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix);
return execProcess("exec", null, cmdLine);
@ -202,7 +204,7 @@ class DynamicArchiveTestBase {
(topArchiveName == null) ? baseArchiveName :
baseArchiveName + File.pathSeparator + topArchiveName;
String[] cmdLine = TestCommon.concat(
"-Xshare:on",
autoMode ? "-Xshare:auto" : "-Xshare:on",
"-XX:SharedArchiveFile=" + archiveFiles);
cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix);
return execProcess("exec", jarDir, cmdLine);