8230302: GenerateJLIClassesPlugin can generate invalid DirectMethodHandle methods

Reviewed-by: mchung
This commit is contained in:
Claes Redestad 2019-08-29 15:59:00 +02:00
parent e2287af876
commit b4c63048bb
3 changed files with 69 additions and 19 deletions

View file

@ -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 sun.invoke.util.Wrapper;
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 @@ class GenerateJLIClassesHelper {
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);
}

View file

@ -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 @@ public final class GenerateJLIClassesPlugin implements Plugin {
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 @@ public final class GenerateJLIClassesPlugin implements Plugin {
);
}
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 @@ public final class GenerateJLIClassesPlugin implements Plugin {
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++;
}
}

View file

@ -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 @@ public class GenerateJLIClassesPluginTest {
helper.generateDefaultModules();
// Test that generate-jli is enabled by default
Result result = JImageGenerator.getJLinkTask()
.modulePath(helper.defaultModulePath())
@ -71,8 +71,7 @@ public class GenerateJLIClassesPluginTest {
Path image = result.assertSuccess();
JImageValidator.validate(
image.resolve("lib").resolve("modules"),
JImageValidator.validate(image.resolve("lib").resolve("modules"),
classFilesForSpecies(GenerateJLIClassesPlugin.defaultSpecies()),
List.of());
@ -90,10 +89,32 @@ public class GenerateJLIClassesPluginTest {
image = result.assertSuccess();
JImageValidator.validate(
image.resolve("lib").resolve("modules"),
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) {