8314621: ClassNotFoundException due to lambda reference to elided anonymous inner class

Reviewed-by: jlahoda
This commit is contained in:
Vicente Romero 2023-11-16 16:49:26 +00:00
parent 52e2878cff
commit d6aa7c8ba0
5 changed files with 74 additions and 148 deletions

View File

@ -1196,6 +1196,18 @@ public class Lower extends TreeTranslator {
}
}
private boolean noClassDefIn(JCTree tree) {
var scanner = new TreeScanner() {
boolean noClassDef = true;
@Override
public void visitClassDef(JCClassDecl tree) {
noClassDef = false;
}
};
scanner.scan(tree);
return scanner.noClassDef;
}
private void addPrunedInfo(JCTree tree) {
List<JCTree> infoList = prunedTree.get(currentClass);
infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
@ -3030,10 +3042,10 @@ public class Lower extends TreeTranslator {
@Override
public void visitConditional(JCConditional tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (isTrue(cond)) {
if (isTrue(cond) && noClassDefIn(tree.falsepart)) {
result = convert(translate(tree.truepart, tree.type), tree.type);
addPrunedInfo(cond);
} else if (isFalse(cond)) {
} else if (isFalse(cond) && noClassDefIn(tree.truepart)) {
result = convert(translate(tree.falsepart, tree.type), tree.type);
addPrunedInfo(cond);
} else {
@ -3057,10 +3069,10 @@ public class Lower extends TreeTranslator {
*/
public void visitIf(JCIf tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (isTrue(cond)) {
if (isTrue(cond) && noClassDefIn(tree.elsepart)) {
result = translate(tree.thenpart);
addPrunedInfo(cond);
} else if (isFalse(cond)) {
} else if (isFalse(cond) && noClassDefIn(tree.thenpart)) {
if (tree.elsepart != null) {
result = translate(tree.elsepart);
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2023, 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
@ -47,6 +47,7 @@ public class GraphicalInstallerTest {
}
check(classes,
"GraphicalInstaller$1.class",
"GraphicalInstaller$1X$1.class",
"GraphicalInstaller$1X.class",
"GraphicalInstaller$BackgroundInstaller.class",

View File

@ -70,12 +70,15 @@ public class T6917288 {
}
switch (k) {
case NONE:
check(classesDir, "Test.class", "Test$Inner.class");
break;
case ALWAYS:
case TRUE:
check(classesDir, "Test.class", "Test$Inner.class", "Test$1.class");
break;
default:
check(classesDir, "Test.class", "Test$Inner.class");
check(classesDir, "Test.class", "Test$Inner.class", "Test$1.class");
}
}

View File

@ -1,142 +0,0 @@
/*
* Copyright (c) 2012, 2018, 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 7199823
* @summary javac generates inner class that can't be verified
* @modules java.base/jdk.internal.classfile
* java.base/jdk.internal.classfile.attribute
* java.base/jdk.internal.classfile.constantpool
* java.base/jdk.internal.classfile.instruction
* java.base/jdk.internal.classfile.components
* java.base/jdk.internal.classfile.impl
* @run main InnerClassCannotBeVerified
*/
import java.nio.file.NoSuchFileException;
import java.util.Arrays;
import javax.tools.JavaFileObject;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler;
import com.sun.source.util.JavacTask;
import jdk.internal.classfile.*;
import java.io.File;
import java.io.IOException;
public class InnerClassCannotBeVerified {
enum CompilationKind {
PRE_NESTMATES("-source", "10", "-target", "10"),
POST_NESTMATES();
String[] opts;
CompilationKind(String... opts) {
this.opts = opts;
}
}
private static final String errorMessage =
"Compile error while compiling the following source:\n";
public static void main(String... args) throws Exception {
new InnerClassCannotBeVerified().run();
}
void run() throws Exception {
for (CompilationKind ck : CompilationKind.values()) {
File file = new File("Test$1.class");
if (file.exists()) {
file.delete();
}
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
JavaSource source = new JavaSource();
JavacTask ct = (JavacTask)comp.getTask(null, null, null,
Arrays.asList(ck.opts), null, Arrays.asList(source));
try {
if (!ct.call()) {
throw new AssertionError(errorMessage +
source.getCharContent(true));
}
} catch (Throwable ex) {
throw new AssertionError(errorMessage +
source.getCharContent(true));
}
check(ck);
}
}
private void check(CompilationKind ck) throws IOException {
try {
File file = new File("Test$1.class");
ClassModel classFile = Classfile.of().parse(file.toPath());
if (ck == CompilationKind.POST_NESTMATES) {
throw new AssertionError("Unexpected constructor tag class!");
}
boolean inheritsFromObject =
classFile.superclass().orElseThrow().asInternalName().equals("java/lang/Object");
boolean implementsNoInterface = classFile.interfaces().size() == 0;
boolean noMethods = classFile.methods().size() == 0;
if (!(inheritsFromObject &&
implementsNoInterface &&
noMethods)) {
throw new AssertionError("The inner classes reused as " +
"access constructor tag for this code must be empty");
}
} catch (NoSuchFileException ex) {
if (ck == CompilationKind.PRE_NESTMATES) {
throw new AssertionError("Constructor tag class missing!");
}
}
}
class JavaSource extends SimpleJavaFileObject {
String internalSource =
"public class Test {\n" +
" private static class Foo {}\n" +
" public static void main(String[] args){ \n" +
" new Foo();\n" +
" if(false) {\n" +
" new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println();\n" +
" }\n" +
" }.run();\n" +
" }\n" +
" }\n" +
"}";
public JavaSource() {
super(URI.create("Test.java"), JavaFileObject.Kind.SOURCE);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return internalSource;
}
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2023, 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 8314621
* @summary ClassNotFoundException due to lambda reference to elided anonymous inner class
*/
public class ClassNotFoundExceptionDueToPrunedCodeTest {
public static void main(String... args) {
var o1 = false ? new Object() {} : null;
Runnable r = () -> {
System.out.println(o1 == o1);
};
r.run();
var o2 = true ? null : new Object() {};
r = () -> {
System.out.println(o2 == o2);
};
r.run();
var o3 = switch (0) { default -> { if (false) yield new Object() { }; else yield null; } };
r = () -> System.out.println(o3);
r.run();
var o4 = switch (0) { default -> { if (true) yield null; else yield new Object() { }; } };
r = () -> System.out.println(o4);
r.run();
}
}