diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 02f55aa15c99..6b8cca4ef309 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -6,6 +6,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-58668) Enabled [Whole-Program Sparse Conditional Constant Propagation (WP-SCCP)](https://github.com/oracle/graal/pull/9821) by default, improving the precision of points-to analysis in Native Image. This optimization enhances static analysis accuracy and scalability, potentially reducing the size of the final native binary. * (GR-59313) Deprecated class-level metadata extraction using `native-image-inspect` and removed option `DumpMethodsData`. Use class-level SBOMs instead by passing `--enable-sbom=class-level,export` to the `native-image` builder. The default value of option `IncludeMethodData` was changed to `false`. * (GR-52400) The build process now uses 85% of system memory in containers and CI environments. Otherwise, it tries to only use available memory. If less than 8GB of memory are available, it falls back to 85% of system memory. The reason for the selected memory limit is now also shown in the build resources section of the build output. +* (GR-59864) Added JVM version check to the Native Image agent. The agent will abort execution if the JVM major version does not match the version it was built with, and warn if the full JVM version is different. ## GraalVM for JDK 24 (Internal Version 24.2.0) * (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning. diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java index d99a8f1062bc..e51247884648 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java @@ -224,6 +224,10 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c } } + if (!checkJVMVersion(jvmti)) { + return USAGE_ERROR; + } + if (traceOutputFile == null && configOutputDir == null) { configOutputDir = transformPath(AGENT_NAME + "_config-pid{pid}-{datetime}/"); inform("no output options provided, tracking dynamic accesses and writing configuration to directory: " + configOutputDir); @@ -420,6 +424,34 @@ private static int usage(String message) { return USAGE_ERROR; } + private static boolean checkJVMVersion(JvmtiEnv jvmti) { + String agentVersion = System.getProperty("java.vm.version"); + int agentMajorVersion = Runtime.version().feature(); + + String vmVersion = Support.getSystemProperty(jvmti, "java.vm.version"); + if (vmVersion == null) { + warn(String.format("Unable to determine the \"java.vm.version\" of the running JVM. Note that the JVM should have major version %d, otherwise metadata may be incorrect.", + agentMajorVersion)); + return true; + } + + // Fail if the major versions differ. + String[] parts = vmVersion.split("\\D"); + if (parts.length == 0 || Integer.parseInt(parts[0]) != agentMajorVersion) { + return error(false, String.format( + "The current VM (%s) is incompatible with the agent, which was built for a JVM with major version %d. To resolve this issue, run the agent using a JVM with major version %d.", + vmVersion, agentMajorVersion, agentMajorVersion)); + } + + // Warn if the VM is different. + if (!vmVersion.startsWith(agentVersion)) { + warn(String.format( + "The running JVM (%s) is different from the JVM used to build the agent (%s). If the generated metadata is incorrect or incomplete, consider running the agent using the same JVM that built it.", + vmVersion, agentVersion)); + } + return true; + } + private static AccessAdvisor createAccessAdvisor(boolean builtinHeuristicFilter, ConfigurationFilter callerFilter, ConfigurationFilter accessFilter) { AccessAdvisor advisor = new AccessAdvisor(); advisor.setHeuristicsEnabled(builtinHeuristicFilter);