8230302: GenerateJLIClassesPlugin can generate invalid DirectMethodHandle methods
Reviewed-by: mchung
--- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Thu Aug 29 08:52:22 2019 -0400
+++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Thu Aug 29 15:59:00 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -31,9 +31,11 @@
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
+import static java.lang.invoke.MethodTypeForm.LF_INVINTERFACE;
+import static java.lang.invoke.MethodTypeForm.LF_INVVIRTUAL;
+
/**
* Helper class to assist the GenerateJLIClassesPlugin to get access to
* generate classes ahead of time.
@@ -71,8 +73,19 @@
ArrayList<LambdaForm> forms = new ArrayList<>();
ArrayList<String> names = new ArrayList<>();
for (int i = 0; i < methodTypes.length; i++) {
- LambdaForm form = DirectMethodHandle
- .makePreparedLambdaForm(methodTypes[i], types[i]);
+ // invokeVirtual and invokeInterface must have a leading Object
+ // parameter, i.e., the receiver
+ if (types[i] == LF_INVVIRTUAL || types[i] == LF_INVINTERFACE) {
+ if (methodTypes[i].parameterCount() < 1 ||
+ methodTypes[i].parameterType(0) != Object.class) {
+ throw new InternalError("Invalid method type for " +
+ (types[i] == LF_INVVIRTUAL ? "invokeVirtual" : "invokeInterface") +
+ " DMH, needs at least two leading reference arguments: " +
+ methodTypes[i]);
+ }
+ }
+
+ LambdaForm form = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i], types[i]);
forms.add(form);
names.add(form.kind.defaultLambdaName);
}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Thu Aug 29 08:52:22 2019 -0400
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Thu Aug 29 15:59:00 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -148,7 +148,7 @@
private static Map<String, Set<String>> defaultDMHMethods() {
return Map.of(
DMH_INVOKE_INTERFACE, Set.of("LL_L", "L3_I", "L3_V"),
- DMH_INVOKE_VIRTUAL, Set.of("L_L", "LL_L", "LLI_I", "L3_V"),
+ DMH_INVOKE_VIRTUAL, Set.of("LL_L", "LLI_I", "L3_V"),
DMH_INVOKE_SPECIAL, Set.of("LL_I", "LL_L", "LLF_L", "LLD_L",
"L3_I", "L3_L", "L4_L", "L5_L", "L6_L", "L7_L", "L8_L",
"LLI_I", "LLI_L", "LLIL_I", "LLIL_L", "LLII_I", "LLII_L",
@@ -166,15 +166,18 @@
);
}
+ private static int DMH_INVOKE_VIRTUAL_TYPE = 0;
+ private static int DMH_INVOKE_INTERFACE_TYPE = 4;
+
// Map from DirectMethodHandle method type to internal ID, matching values
// of the corresponding constants in java.lang.invoke.MethodTypeForm
private static final Map<String, Integer> DMH_METHOD_TYPE_MAP =
Map.of(
- DMH_INVOKE_VIRTUAL, 0,
+ DMH_INVOKE_VIRTUAL, DMH_INVOKE_VIRTUAL_TYPE,
DMH_INVOKE_STATIC, 1,
DMH_INVOKE_SPECIAL, 2,
DMH_NEW_INVOKE_SPECIAL, 3,
- DMH_INVOKE_INTERFACE, 4,
+ DMH_INVOKE_INTERFACE, DMH_INVOKE_INTERFACE_TYPE,
DMH_INVOKE_STATIC_INIT, 5,
DMH_INVOKE_SPECIAL_IFC, 20
);
@@ -380,10 +383,23 @@
if (mt.parameterCount() < 1 ||
mt.parameterType(0) != Object.class) {
throw new PluginException(
- "DMH type parameter must start with L");
+ "DMH type parameter must start with L: " + dmhType + " " + type);
}
+
+ // Adapt the method type of the LF to retrieve
directMethodTypes[index] = mt.dropParameterTypes(0, 1);
+
+ // invokeVirtual and invokeInterface must have a leading Object
+ // parameter, i.e., the receiver
dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
+ if (dmhTypes[index] == DMH_INVOKE_INTERFACE_TYPE ||
+ dmhTypes[index] == DMH_INVOKE_VIRTUAL_TYPE) {
+ if (mt.parameterCount() < 2 ||
+ mt.parameterType(1) != Object.class) {
+ throw new PluginException(
+ "DMH type parameter must start with LL: " + dmhType + " " + type);
+ }
+ }
index++;
}
}
--- a/test/jdk/tools/jlink/plugins/GenerateJLIClassesPluginTest.java Thu Aug 29 08:52:22 2019 -0400
+++ b/test/jdk/tools/jlink/plugins/GenerateJLIClassesPluginTest.java Thu Aug 29 15:59:00 2019 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -21,6 +21,7 @@
* questions.
*/
+import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -61,7 +62,6 @@
helper.generateDefaultModules();
-
// Test that generate-jli is enabled by default
Result result = JImageGenerator.getJLinkTask()
.modulePath(helper.defaultModulePath())
@@ -71,10 +71,9 @@
Path image = result.assertSuccess();
- JImageValidator.validate(
- image.resolve("lib").resolve("modules"),
- classFilesForSpecies(GenerateJLIClassesPlugin.defaultSpecies()),
- List.of());
+ JImageValidator.validate(image.resolve("lib").resolve("modules"),
+ classFilesForSpecies(GenerateJLIClassesPlugin.defaultSpecies()),
+ List.of());
// Check that --generate-jli-classes=@file works as intended
Path baseFile = Files.createTempFile("base", "trace");
@@ -90,10 +89,32 @@
image = result.assertSuccess();
- JImageValidator.validate(
- image.resolve("lib").resolve("modules"),
- classFilesForSpecies(List.of(species)), // species should be in the image
- classFilesForSpecies(List.of(species.substring(1)))); // but not it's immediate parent
+ JImageValidator.validate(image.resolve("lib").resolve("modules"),
+ classFilesForSpecies(List.of(species)), // species should be in the image
+ classFilesForSpecies(List.of(species.substring(1)))); // but not it's immediate parent
+
+ // Check that --generate-jli-classes=@file fails as intended on shapes that can't be generated
+ ensureInvalidSignaturesFail(
+ "[LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeVirtual L_L (success)\n",
+ "[LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeInterface L_L (success)\n",
+ "[LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic I_L (success)\n"
+ );
+ }
+
+ private static void ensureInvalidSignaturesFail(String ... args) throws IOException {
+ for (String fileString : args) {
+ Path failFile = Files.createTempFile("fail", "trace");
+ fileString = "[LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeVirtual L_L (success)\n";
+ Files.write(failFile, fileString.getBytes(Charset.defaultCharset()));
+ Result result = JImageGenerator.getJLinkTask()
+ .modulePath(helper.defaultModulePath())
+ .output(helper.createNewImageDir("generate-jli-file"))
+ .option("--generate-jli-classes=@" + failFile.toString())
+ .addMods("java.base")
+ .call();
+
+ result.assertFailure();
+ }
}
private static List<String> classFilesForSpecies(Collection<String> species) {