8342089: Require --enable-native-access to be the same between CDS dump time and run time

Reviewed-by: ccheung, dholmes
This commit is contained in:
Matias Saavedra Silva 2024-12-03 16:18:38 +00:00
parent 2be27e1545
commit 60bd73a595
10 changed files with 265 additions and 96 deletions

View File

@ -250,9 +250,7 @@ void CDSConfig::init_shared_archive_paths() {
}
void CDSConfig::check_internal_module_property(const char* key, const char* value) {
if (Arguments::is_internal_module_property(key) &&
!Arguments::is_module_path_property(key) &&
!Arguments::is_add_modules_property(key)) {
if (Arguments::is_incompatible_cds_internal_module_property(key)) {
stop_using_optimized_module_handling();
log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
}

View File

@ -423,8 +423,7 @@ void MetaspaceShared::write_method_handle_intrinsics() {
void MetaspaceShared::early_serialize(SerializeClosure* soc) {
int tag = 0;
soc->do_tag(--tag);
CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);)
CDS_JAVA_HEAP_ONLY(Modules::serialize_addmods_names(soc);)
CDS_JAVA_HEAP_ONLY(Modules::serialize_archived_module_info(soc);)
soc->do_tag(666);
}
@ -567,10 +566,7 @@ public:
char* VM_PopulateDumpSharedSpace::dump_early_read_only_tables() {
ArchiveBuilder::OtherROAllocMark mark;
// Write module name into archive
CDS_JAVA_HEAP_ONLY(Modules::dump_main_module_name();)
// Write module names from --add-modules into archive
CDS_JAVA_HEAP_ONLY(Modules::dump_addmods_names();)
CDS_JAVA_HEAP_ONLY(Modules::dump_archived_module_info());
DumpRegion* ro_region = ArchiveBuilder::current()->ro_region();
char* start = ro_region->top();

View File

@ -562,13 +562,55 @@ void Modules::verify_archived_modules() {
char* Modules::_archived_main_module_name = nullptr;
char* Modules::_archived_addmods_names = nullptr;
char* Modules::_archived_native_access_flags = nullptr;
void Modules::dump_main_module_name() {
const char* module_name = Arguments::get_property("jdk.module.main");
if (module_name != nullptr) {
_archived_main_module_name = ArchiveBuilder::current()->ro_strdup(module_name);
}
ArchivePtrMarker::mark_pointer(&_archived_main_module_name);
}
void Modules::check_archived_flag_consistency(char* archived_flag, const char* runtime_flag, const char* property) {
log_info(cds)("%s %s", property,
archived_flag != nullptr ? archived_flag : "(null)");
bool disable = false;
if (runtime_flag == nullptr) {
if (archived_flag != nullptr) {
log_info(cds)("Mismatched values for property %s: %s specified during dump time but not during runtime", property, archived_flag);
disable = true;
}
} else {
if (archived_flag == nullptr) {
log_info(cds)("Mismatched values for property %s: %s specified during runtime but not during dump time", property, runtime_flag);
disable = true;
} else if (strcmp(runtime_flag, archived_flag) != 0) {
log_info(cds)("Mismatched values for property %s: runtime %s dump time %s", property, runtime_flag, archived_flag);
disable = true;
}
}
if (disable) {
log_info(cds)("Disabling optimized module handling");
CDSConfig::stop_using_optimized_module_handling();
}
log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
}
void Modules::dump_archived_module_info() {
// Write module name into archive
CDS_JAVA_HEAP_ONLY(Modules::dump_main_module_name();)
// Write module names from --add-modules into archive
CDS_JAVA_HEAP_ONLY(Modules::dump_addmods_names();)
// Write native enable-native-access flag into archive
CDS_JAVA_HEAP_ONLY(Modules::dump_native_access_flag());
}
void Modules::serialize_archived_module_info(SerializeClosure* soc) {
CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);)
CDS_JAVA_HEAP_ONLY(Modules::serialize_addmods_names(soc);)
CDS_JAVA_HEAP_ONLY(Modules::serialize_native_access_flags(soc);)
}
void Modules::serialize(SerializeClosure* soc) {
@ -577,89 +619,71 @@ void Modules::serialize(SerializeClosure* soc) {
const char* runtime_main_module = Arguments::get_property("jdk.module.main");
log_info(cds)("_archived_main_module_name %s",
_archived_main_module_name != nullptr ? _archived_main_module_name : "(null)");
bool disable = false;
if (runtime_main_module == nullptr) {
if (_archived_main_module_name != nullptr) {
log_info(cds)("Module %s specified during dump time but not during runtime", _archived_main_module_name);
disable = true;
}
} else {
if (_archived_main_module_name == nullptr) {
log_info(cds)("Module %s specified during runtime but not during dump time", runtime_main_module);
disable = true;
} else if (strcmp(runtime_main_module, _archived_main_module_name) != 0) {
log_info(cds)("Mismatched modules: runtime %s dump time %s", runtime_main_module, _archived_main_module_name);
disable = true;
}
}
if (disable) {
log_info(cds)("Disabling optimized module handling");
CDSConfig::stop_using_optimized_module_handling();
}
log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
check_archived_flag_consistency(_archived_main_module_name, runtime_main_module, "jdk.module.main");
// Don't hold onto the pointer, in case we might decide to unmap the archive.
_archived_main_module_name = nullptr;
}
}
void Modules::dump_native_access_flag() {
const char* native_access_names = get_native_access_flags_as_sorted_string();
if (native_access_names != nullptr) {
_archived_native_access_flags = ArchiveBuilder::current()->ro_strdup(native_access_names);
}
}
const char* Modules::get_native_access_flags_as_sorted_string() {
return get_numbered_property_as_sorted_string("jdk.module.enable.native.access");
}
void Modules::serialize_native_access_flags(SerializeClosure* soc) {
soc->do_ptr(&_archived_native_access_flags);
if (soc->reading()) {
check_archived_flag_consistency(_archived_native_access_flags, get_native_access_flags_as_sorted_string(), "jdk.module.enable.native.access");
// Don't hold onto the pointer, in case we might decide to unmap the archive.
_archived_native_access_flags = nullptr;
}
}
void Modules::dump_addmods_names() {
unsigned int count = Arguments::addmods_count();
const char* addmods_names = get_addmods_names_as_sorted_string();
if (addmods_names != nullptr) {
_archived_addmods_names = ArchiveBuilder::current()->ro_strdup(addmods_names);
}
ArchivePtrMarker::mark_pointer(&_archived_addmods_names);
}
const char* Modules::get_addmods_names_as_sorted_string() {
return get_numbered_property_as_sorted_string("jdk.module.addmods");
}
void Modules::serialize_addmods_names(SerializeClosure* soc) {
soc->do_ptr(&_archived_addmods_names);
if (soc->reading()) {
bool disable = false;
if (_archived_addmods_names[0] != '\0') {
if (Arguments::addmods_count() == 0) {
log_info(cds)("--add-modules module name(s) found in archive but not specified during runtime: %s",
_archived_addmods_names);
disable = true;
} else {
const char* addmods_names = get_addmods_names_as_sorted_string();
if (strcmp((const char*)_archived_addmods_names, addmods_names) != 0) {
log_info(cds)("Mismatched --add-modules module name(s).");
log_info(cds)(" dump time: %s runtime: %s", _archived_addmods_names, addmods_names);
disable = true;
}
}
} else {
if (Arguments::addmods_count() > 0) {
log_info(cds)("--add-modules module name(s) specified during runtime but not found in archive: %s",
get_addmods_names_as_sorted_string());
disable = true;
}
}
if (disable) {
log_info(cds)("Disabling optimized module handling");
CDSConfig::stop_using_optimized_module_handling();
}
log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
check_archived_flag_consistency(_archived_addmods_names, get_addmods_names_as_sorted_string(), "jdk.module.addmods");
// Don't hold onto the pointer, in case we might decide to unmap the archive.
_archived_addmods_names = nullptr;
}
}
const char* Modules::get_addmods_names_as_sorted_string() {
const char* Modules::get_numbered_property_as_sorted_string(const char* property) {
ResourceMark rm;
const int max_digits = 3;
// theoretical string size limit for decimal int, but the following loop will end much sooner due to
// OS command-line size limit.
const int max_digits = 10;
const int extra_symbols_count = 2; // includes '.', '\0'
size_t prop_len = strlen("jdk.module.addmods") + max_digits + extra_symbols_count;
size_t prop_len = strlen(property) + max_digits + extra_symbols_count;
char* prop_name = resource_allocate_bytes(prop_len);
GrowableArray<const char*> list;
for (unsigned int i = 0; i < Arguments::addmods_count(); i++) {
jio_snprintf(prop_name, prop_len, "jdk.module.addmods.%d", i);
for (unsigned int i = 0;; i++) {
jio_snprintf(prop_name, prop_len, "%s.%d", property, i);
const char* prop_value = Arguments::get_property(prop_name);
if (prop_value == nullptr) {
break;
}
char* p = resource_allocate_bytes(strlen(prop_value) + 1);
strcpy(p, prop_value);
while (*p == ',') p++; // skip leading commas
@ -695,11 +719,12 @@ const char* Modules::get_addmods_names_as_sorted_string() {
if (strcmp(m, last_string) != 0) { // filter out duplicates
st.print("%s%s", prefix, m);
last_string = m;
prefix = "\n";
prefix = ",";
}
}
return (const char*)os::strdup(st.as_string()); // Example: "java.base,java.compiler"
const char* result = (const char*)os::strdup(st.as_string()); // Example: "java.base,java.compiler"
return strcmp(result, "") != 0 ? result : nullptr;
}
void Modules::define_archived_modules(Handle h_platform_loader, Handle h_system_loader, TRAPS) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, 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
@ -59,15 +59,25 @@ public:
static void define_archived_modules(Handle h_platform_loader, Handle h_system_loader,
TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void verify_archived_modules() NOT_CDS_JAVA_HEAP_RETURN;
static void dump_archived_module_info() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_archived_module_info(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
static void dump_main_module_name() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
static void dump_addmods_names() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_addmods_names(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
static const char* get_addmods_names_as_sorted_string() NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
static void check_archived_flag_consistency(char* archived_flag, const char* runtime_flag, const char* property) NOT_CDS_JAVA_HEAP_RETURN;
static void dump_native_access_flag() NOT_CDS_JAVA_HEAP_RETURN;
static const char* get_native_access_flags_as_sorted_string() NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
static void serialize_native_access_flags(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
static void dump_addmods_names() NOT_CDS_JAVA_HEAP_RETURN;
static const char* get_addmods_names_as_sorted_string() NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
static void serialize_addmods_names(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
static const char* get_numbered_property_as_sorted_string(const char* property) NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
#if INCLUDE_CDS_JAVA_HEAP
static char* _archived_main_module_name;
static char* _archived_addmods_names;
static char* _archived_native_access_flags;
#endif
// Provides the java.lang.Module for the unnamed module defined

View File

@ -320,33 +320,40 @@ static bool matches_property_suffix(const char* option, const char* property, si
// any of the reserved module properties.
// property should be passed without the leading "-D".
bool Arguments::is_internal_module_property(const char* property) {
if (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) {
return internal_module_property_helper(property, false);
}
// Returns true if property is one of those recognized by is_internal_module_property() but
// is not supported by CDS archived full module graph.
bool Arguments::is_incompatible_cds_internal_module_property(const char* property) {
return internal_module_property_helper(property, true);
}
bool Arguments::internal_module_property_helper(const char* property, bool check_for_cds) {
if (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) {
const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN;
if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) ||
matches_property_suffix(property_suffix, ADDREADS, ADDREADS_LEN) ||
matches_property_suffix(property_suffix, ADDOPENS, ADDOPENS_LEN) ||
matches_property_suffix(property_suffix, PATCH, PATCH_LEN) ||
matches_property_suffix(property_suffix, ADDMODS, ADDMODS_LEN) ||
matches_property_suffix(property_suffix, LIMITMODS, LIMITMODS_LEN) ||
matches_property_suffix(property_suffix, PATH, PATH_LEN) ||
matches_property_suffix(property_suffix, UPGRADE_PATH, UPGRADE_PATH_LEN) ||
matches_property_suffix(property_suffix, ILLEGAL_NATIVE_ACCESS, ILLEGAL_NATIVE_ACCESS_LEN) ||
matches_property_suffix(property_suffix, ENABLE_NATIVE_ACCESS, ENABLE_NATIVE_ACCESS_LEN)) {
matches_property_suffix(property_suffix, ILLEGAL_NATIVE_ACCESS, ILLEGAL_NATIVE_ACCESS_LEN)) {
return true;
}
if (!check_for_cds) {
// CDS notes: these properties are supported by CDS archived full module graph.
if (matches_property_suffix(property_suffix, PATH, PATH_LEN) ||
matches_property_suffix(property_suffix, ADDMODS, ADDMODS_LEN) ||
matches_property_suffix(property_suffix, ENABLE_NATIVE_ACCESS, ENABLE_NATIVE_ACCESS_LEN)) {
return true;
}
}
}
return false;
}
bool Arguments::is_add_modules_property(const char* key) {
return (strcmp(key, MODULE_PROPERTY_PREFIX ADDMODS) == 0);
}
// Return true if the key matches the --module-path property name ("jdk.module.path").
bool Arguments::is_module_path_property(const char* key) {
return (strcmp(key, MODULE_PROPERTY_PREFIX PATH) == 0);
}
// Process java launcher properties.
void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) {
// See if sun.java.launcher or sun.java.launcher.is_altjvm is defined.

View File

@ -365,6 +365,8 @@ class Arguments : AllStatic {
static const char* handle_aliases_and_deprecation(const char* arg);
static size_t _default_SharedBaseAddress; // The default value specified in globals.hpp
static bool internal_module_property_helper(const char* property, bool check_for_cds);
public:
// Parses the arguments, first phase
static jint parse(const JavaVMInitArgs* args);
@ -463,9 +465,7 @@ class Arguments : AllStatic {
static int PropertyList_readable_count(SystemProperty* pl);
static bool is_internal_module_property(const char* option);
static bool is_add_modules_property(const char* key);
static unsigned int addmods_count() { return _addmods_count; }
static bool is_module_path_property(const char* key);
static bool is_incompatible_cds_internal_module_property(const char* property);
// Miscellaneous System property value getter and setters.
static void set_dll_dir(const char *value) { _sun_boot_library_path->set_value(value); }

View File

@ -125,7 +125,7 @@ public class AOTClassLinkingVMOptions {
"--module-path", goodModulePath + "/bad",
"--add-modules", CDSModulePathUtils.TEST_MODULE,
CDSModulePathUtils.MAIN_CLASS)
.assertAbnormalExit("Mismatched --add-modules module name(s)",
.assertAbnormalExit("Mismatched values for property jdk.module.addmods",
"CDS archive has aot-linked classes. It cannot be used when archived full module graph is not used.");
}
}

View File

@ -80,8 +80,8 @@ public class AddmodsOption {
"-m", moduleOption,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Mismatched --add-modules module name(s).")
.shouldContain("dump time: jdk.jconsole runtime: jdk.incubator.vector")
.shouldContain("Mismatched values for property jdk.module.addmods")
.shouldContain("runtime jdk.incubator.vector dump time jdk.jconsole")
.shouldContain(subgraphCannotBeUsed);
// no module specified during runtime
@ -89,7 +89,7 @@ public class AddmodsOption {
loggingOption,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Module jdk.httpserver specified during dump time but not during runtime")
.shouldContain("jdk.httpserver specified during dump time but not during runtime")
.shouldContain(subgraphCannotBeUsed);
// dump an archive without the --add-modules option
@ -109,7 +109,7 @@ public class AddmodsOption {
"-m", moduleOption,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("--add-modules module name(s) specified during runtime but not found in archive: jdk.jconsole")
.shouldContain("jdk.jconsole specified during runtime but not during dump time")
// version of the jdk.httpserver module, e.g. java 22-ea
.shouldMatch(versionPattern)
.shouldContain(subgraphCannotBeUsed);

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2024, 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
* @bug 8342089
* @summary Test consistency of --enable-native-access option for CDS dump time and runtime
* @requires vm.cds.write.archived.java.heap
* @requires vm.flagless
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver EnableNativeAccessCDS
*/
import jdk.test.lib.process.OutputAnalyzer;
public class EnableNativeAccessCDS {
public static void main(String[] args) throws Exception {
final String module0 = "java.base";
final String module1 = "jdk.httpserver";
final String disabledOptimizedModule = "Disabling optimized module handling";
final String loggingOption = "-Xlog:cds=debug";
String archiveName = TestCommon.getNewArchiveName("native-access");
TestCommon.setCurrentArchiveName(archiveName);
// dump a base archive with --enable-native-access=java.base
OutputAnalyzer oa = TestCommon.dumpBaseArchive(
archiveName,
loggingOption,
"--enable-native-access", module0,
"-version");
oa.shouldHaveExitValue(0);
// same module specified during runtime
oa = TestCommon.execCommon(
loggingOption,
"--enable-native-access", module0,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("use_full_module_graph = true");
// different module specified during runtime
oa = TestCommon.execCommon(
loggingOption,
"--enable-native-access", module1,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Mismatched values for property jdk.module.enable.native.access: runtime jdk.httpserver dump time java.base")
.shouldContain(disabledOptimizedModule);
// no module specified during runtime
oa = TestCommon.execCommon(
loggingOption,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Mismatched values for property jdk.module.enable.native.access: java.base specified during dump time but not during runtime")
.shouldContain(disabledOptimizedModule);
// dump an archive without --enable-native-access option
archiveName = TestCommon.getNewArchiveName("no-native-access-modules");
TestCommon.setCurrentArchiveName(archiveName);
oa = TestCommon.dumpBaseArchive(
archiveName,
loggingOption,
"-version");
oa.shouldHaveExitValue(0);
// run with --enable-native-access
oa = TestCommon.execCommon(
loggingOption,
"--enable-native-access", module0,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Mismatched values for property jdk.module.enable.native.access: java.base specified during runtime but not during dump time")
.shouldContain(disabledOptimizedModule);
// dump an archive with multiple modules with native access
archiveName = TestCommon.getNewArchiveName("multiple-native-access-modules");
TestCommon.setCurrentArchiveName(archiveName);
oa = TestCommon.dumpBaseArchive(
archiveName,
loggingOption,
"--enable-native-access", module0 + "," + module1,
"-version");
oa.shouldHaveExitValue(0);
// same module specified during runtime but in a different order
oa = TestCommon.execCommon(
loggingOption,
"--enable-native-access", module1 + "," + module0,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("use_full_module_graph = true");
// same module specified during runtime but specifying --enable-native-access twice
oa = TestCommon.execCommon(
loggingOption,
"--enable-native-access", module0,
"--enable-native-access", module1,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("use_full_module_graph = true");
// run with only one same module
oa = TestCommon.execCommon(
loggingOption,
"--enable-native-access", module0,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Mismatched values for property jdk.module.enable.native.access: runtime java.base dump time java.base,jdk.httpserver")
.shouldContain(disabledOptimizedModule);
}
}

View File

@ -70,7 +70,7 @@ public class ModuleOption {
"-m", "jdk.compiler/com.sun.tools.javac.Main",
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Mismatched modules: runtime jdk.compiler dump time jdk.httpserver")
.shouldContain("Mismatched values for property jdk.module.main: runtime jdk.compiler dump time jdk.httpserver")
.shouldContain(subgraphCannotBeUsed);
// no module specified during runtime
@ -78,7 +78,7 @@ public class ModuleOption {
loggingOption,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Module jdk.httpserver specified during dump time but not during runtime")
.shouldContain("Mismatched values for property jdk.module.main: jdk.httpserver specified during dump time but not during runtime")
.shouldContain(subgraphCannotBeUsed);
// dump an archive without the module option
@ -96,7 +96,7 @@ public class ModuleOption {
"-m", moduleOption,
"-version");
oa.shouldHaveExitValue(0)
.shouldContain("Module jdk.httpserver specified during runtime but not during dump time")
.shouldContain("Mismatched values for property jdk.module.main: jdk.httpserver specified during runtime but not during dump time")
// version of the jdk.httpserver module, e.g. java 22-ea
.shouldMatch(versionPattern)
.shouldContain(subgraphCannotBeUsed);