mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8230302: GenerateJLIClassesPlugin can generate invalid DirectMethodHandle methods
Reviewed-by: mchung
This commit is contained in:
parent
e2287af876
commit
b4c63048bb
3 changed files with 69 additions and 19 deletions
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
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
|
* Helper class to assist the GenerateJLIClassesPlugin to get access to
|
||||||
* generate classes ahead of time.
|
* generate classes ahead of time.
|
||||||
|
@ -71,8 +73,19 @@ class GenerateJLIClassesHelper {
|
||||||
ArrayList<LambdaForm> forms = new ArrayList<>();
|
ArrayList<LambdaForm> forms = new ArrayList<>();
|
||||||
ArrayList<String> names = new ArrayList<>();
|
ArrayList<String> names = new ArrayList<>();
|
||||||
for (int i = 0; i < methodTypes.length; i++) {
|
for (int i = 0; i < methodTypes.length; i++) {
|
||||||
LambdaForm form = DirectMethodHandle
|
// invokeVirtual and invokeInterface must have a leading Object
|
||||||
.makePreparedLambdaForm(methodTypes[i], types[i]);
|
// 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);
|
forms.add(form);
|
||||||
names.add(form.kind.defaultLambdaName);
|
names.add(form.kind.defaultLambdaName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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() {
|
private static Map<String, Set<String>> defaultDMHMethods() {
|
||||||
return Map.of(
|
return Map.of(
|
||||||
DMH_INVOKE_INTERFACE, Set.of("LL_L", "L3_I", "L3_V"),
|
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",
|
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",
|
"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",
|
"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
|
// Map from DirectMethodHandle method type to internal ID, matching values
|
||||||
// of the corresponding constants in java.lang.invoke.MethodTypeForm
|
// of the corresponding constants in java.lang.invoke.MethodTypeForm
|
||||||
private static final Map<String, Integer> DMH_METHOD_TYPE_MAP =
|
private static final Map<String, Integer> DMH_METHOD_TYPE_MAP =
|
||||||
Map.of(
|
Map.of(
|
||||||
DMH_INVOKE_VIRTUAL, 0,
|
DMH_INVOKE_VIRTUAL, DMH_INVOKE_VIRTUAL_TYPE,
|
||||||
DMH_INVOKE_STATIC, 1,
|
DMH_INVOKE_STATIC, 1,
|
||||||
DMH_INVOKE_SPECIAL, 2,
|
DMH_INVOKE_SPECIAL, 2,
|
||||||
DMH_NEW_INVOKE_SPECIAL, 3,
|
DMH_NEW_INVOKE_SPECIAL, 3,
|
||||||
DMH_INVOKE_INTERFACE, 4,
|
DMH_INVOKE_INTERFACE, DMH_INVOKE_INTERFACE_TYPE,
|
||||||
DMH_INVOKE_STATIC_INIT, 5,
|
DMH_INVOKE_STATIC_INIT, 5,
|
||||||
DMH_INVOKE_SPECIAL_IFC, 20
|
DMH_INVOKE_SPECIAL_IFC, 20
|
||||||
);
|
);
|
||||||
|
@ -380,10 +383,23 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||||
if (mt.parameterCount() < 1 ||
|
if (mt.parameterCount() < 1 ||
|
||||||
mt.parameterType(0) != Object.class) {
|
mt.parameterType(0) != Object.class) {
|
||||||
throw new PluginException(
|
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);
|
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);
|
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++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -61,7 +62,6 @@ public class GenerateJLIClassesPluginTest {
|
||||||
|
|
||||||
helper.generateDefaultModules();
|
helper.generateDefaultModules();
|
||||||
|
|
||||||
|
|
||||||
// Test that generate-jli is enabled by default
|
// Test that generate-jli is enabled by default
|
||||||
Result result = JImageGenerator.getJLinkTask()
|
Result result = JImageGenerator.getJLinkTask()
|
||||||
.modulePath(helper.defaultModulePath())
|
.modulePath(helper.defaultModulePath())
|
||||||
|
@ -71,10 +71,9 @@ public class GenerateJLIClassesPluginTest {
|
||||||
|
|
||||||
Path image = result.assertSuccess();
|
Path image = result.assertSuccess();
|
||||||
|
|
||||||
JImageValidator.validate(
|
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
||||||
image.resolve("lib").resolve("modules"),
|
classFilesForSpecies(GenerateJLIClassesPlugin.defaultSpecies()),
|
||||||
classFilesForSpecies(GenerateJLIClassesPlugin.defaultSpecies()),
|
List.of());
|
||||||
List.of());
|
|
||||||
|
|
||||||
// Check that --generate-jli-classes=@file works as intended
|
// Check that --generate-jli-classes=@file works as intended
|
||||||
Path baseFile = Files.createTempFile("base", "trace");
|
Path baseFile = Files.createTempFile("base", "trace");
|
||||||
|
@ -90,10 +89,32 @@ public class GenerateJLIClassesPluginTest {
|
||||||
|
|
||||||
image = result.assertSuccess();
|
image = result.assertSuccess();
|
||||||
|
|
||||||
JImageValidator.validate(
|
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
||||||
image.resolve("lib").resolve("modules"),
|
classFilesForSpecies(List.of(species)), // species should be in the image
|
||||||
classFilesForSpecies(List.of(species)), // species should be in the image
|
classFilesForSpecies(List.of(species.substring(1)))); // but not it's immediate parent
|
||||||
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) {
|
private static List<String> classFilesForSpecies(Collection<String> species) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue