undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2020, 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.
*/
// this_class is modified to CONSTANT_NameAndType_info
class BadClassFile {
0xCAFEBABE;
0; // minor version
58; // version
[] { // Constant Pool
; // first element is empty
Method #2 #3; // #1
class #4; // #2
NameAndType #5 #6; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "()V"; // #6
NameAndType #5 #6; // #7
Utf8 "BadClassFile"; // #8
Utf8 "Code"; // #9
Utf8 "LineNumberTable"; // #10
Utf8 "SourceFile"; // #11
Utf8 "BadClassFile.java"; // #12
} // Constant Pool
0x0021; // access
#7;// this_cpx
#2;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // fields
} // fields
[] { // methods
{ // Member
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[] { // Attributes
Attr(#9) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // LineNumberTable
0 28;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[] { // Attributes
Attr(#11) { // SourceFile
#12;
} // end SourceFile
} // Attributes
} // end class BadClassFile

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2020, 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.
*/
// this_class is modified to CONSTANT_String_info
class BadClassFile2 {
0xCAFEBABE;
0; // minor version
58; // version
[] { // Constant Pool
; // first element is empty
Method #2 #3; // #1
class #4; // #2
NameAndType #5 #6; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "()V"; // #6
String #13; // #7
Utf8 "BadClassFile2"; // #8
Utf8 "Code"; // #9
Utf8 "LineNumberTable"; // #10
Utf8 "SourceFile"; // #11
Utf8 "BadClassFile2.java"; // #12
String "BadClassFile2.java"; // #13
Utf8 "bad/Package/ClassFile"; // #14
} // Constant Pool
0x0021; // access
#7;// this_cpx
#2;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // fields
} // fields
[] { // methods
{ // Member
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[] { // Attributes
Attr(#9) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // LineNumberTable
0 28;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[] { // Attributes
Attr(#11) { // SourceFile
#12;
} // end SourceFile
} // Attributes
} // end class BadClassFile2

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2020, 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.
*/
// major version modified to 100
class BadClassFileVersion {
0xCAFEBABE;
0; // minor version
100; // version
[] { // Constant Pool
; // first element is empty
Method #2 #3; // #1
class #4; // #2
NameAndType #5 #6; // #3
Utf8 "java/lang/Object"; // #4
Utf8 "<init>"; // #5
Utf8 "()V"; // #6
class #8; // #7
Utf8 "BadClassFileVersion"; // #8
Utf8 "Code"; // #9
Utf8 "LineNumberTable"; // #10
Utf8 "SourceFile"; // #11
Utf8 "BadClassFileVersion.java"; // #12
} // Constant Pool
0x0021; // access
#7;// this_cpx
#2;// super_cpx
[] { // Interfaces
} // Interfaces
[] { // fields
} // fields
[] { // methods
{ // Member
0x0001; // access
#5; // name_cpx
#6; // sig_cpx
[] { // Attributes
Attr(#9) { // Code
1; // max_stack
1; // max_locals
Bytes[]{
0x2AB70001B1;
}
[] { // Traps
} // end Traps
[] { // Attributes
Attr(#10) { // LineNumberTable
[] { // LineNumberTable
0 28;
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[] { // Attributes
Attr(#11) { // SourceFile
#12;
} // end SourceFile
} // Attributes
} // end class BadClassFileVersion

View file

@ -0,0 +1,517 @@
/*
* Copyright (c) 2019, 2025, 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 8330467
* @modules jdk.compiler
* @library /test/lib
* @compile BadClassFile.jcod
* BadClassFile2.jcod
* BadClassFileVersion.jcod
* @build jdk.test.lib.Utils
* jdk.test.lib.compiler.CompilerUtils
* @run junit/othervm BasicTest
*/
import java.io.File;
import java.io.IOException;
import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.Utils;
import static java.lang.classfile.ClassFile.*;
import static java.lang.constant.ConstantDescs.CD_Enum;
import static java.lang.constant.ConstantDescs.CD_Object;
import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
interface HiddenTest {
void test();
}
public class BasicTest {
private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src");
private static final Path CLASSES_DIR = Paths.get("classes");
private static final Path CLASSES_10_DIR = Paths.get("classes_10");
private static byte[] hiddenClassBytes;
@BeforeAll
static void setup() throws IOException {
compileSources(SRC_DIR, CLASSES_DIR);
hiddenClassBytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class"));
// compile with --release 10 with no NestHost and NestMembers attribute
compileSources(SRC_DIR.resolve("Outer.java"), CLASSES_10_DIR, "--release", "10");
compileSources(SRC_DIR.resolve("EnclosingClass.java"), CLASSES_10_DIR, "--release", "10");
}
static void compileSources(Path sourceFile, Path dest, String... options) throws IOException {
Stream<String> ops = Stream.of("-cp", Utils.TEST_CLASSES + File.pathSeparator + CLASSES_DIR);
if (options != null && options.length > 0) {
ops = Stream.concat(ops, Arrays.stream(options));
}
if (!CompilerUtils.compile(sourceFile, dest, ops.toArray(String[]::new))) {
throw new RuntimeException("Compilation of the test failed: " + sourceFile);
}
}
static Class<?> defineHiddenClass(String name) throws Exception {
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
assertHiddenClass(hc);
singletonNest(hc);
return hc;
}
// basic test on a hidden class
@Test
public void hiddenClass() throws Throwable {
HiddenTest t = (HiddenTest)defineHiddenClass("HiddenClass").newInstance();
t.test();
// sanity check
Class<?> c = t.getClass();
Class<?>[] intfs = c.getInterfaces();
assertTrue(c.isHidden());
assertFalse(c.isPrimitive());
assertEquals(1, intfs.length);
assertSame(HiddenTest.class, intfs[0]);
assertNull(c.getCanonicalName());
String hcName = "HiddenClass";
String hcSuffix = "0x[0-9a-f]+";
assertTrue(c.getName().matches(hcName + "/" + hcSuffix));
assertTrue(c.descriptorString().matches("L" + hcName + "." + hcSuffix + ";"), c.descriptorString());
// test array of hidden class
testHiddenArray(c);
// test setAccessible
checkSetAccessible(c, "realTest");
checkSetAccessible(c, "test");
}
// primitive class is not a hidden class
@Test
public void primitiveClass() {
assertFalse(int.class.isHidden());
assertFalse(String.class.isHidden());
}
private void testHiddenArray(Class<?> type) throws Exception {
// array of hidden class
Object array = Array.newInstance(type, 2);
Class<?> arrayType = array.getClass();
assertTrue(arrayType.isArray());
assertEquals(2, Array.getLength(array));
assertFalse(arrayType.isHidden());
String hcName = "HiddenClass";
String hcSuffix = "0x[0-9a-f]+";
assertTrue(arrayType.getName().matches("\\[" + "L" + hcName + "/" + hcSuffix + ";"));
assertTrue(arrayType.descriptorString().matches("\\[" + "L" + hcName + "." + hcSuffix + ";"));
assertTrue(arrayType.getComponentType().isHidden());
assertSame(type, arrayType.getComponentType());
Object t = type.newInstance();
Array.set(array, 0, t);
Object o = Array.get(array, 0);
assertSame(t, o);
}
private void checkSetAccessible(Class<?> c, String name, Class<?>... ptypes) throws Exception {
Method m = c.getDeclaredMethod(name, ptypes);
assertTrue(m.trySetAccessible());
m.setAccessible(true);
}
// Define a hidden class that uses lambda
// This verifies LambdaMetaFactory supports the caller which is a hidden class
@Test
public void testLambda() throws Throwable {
HiddenTest t = (HiddenTest)defineHiddenClass("Lambda").newInstance();
var e = assertThrows(Error.class, t::test);
assertEquals("thrown by " + t.getClass().getName(), e.getMessage());
}
// Define a hidden class that uses lambda and contains its implementation
// This verifies LambdaMetaFactory supports the caller which is a hidden class
@Test
public void testHiddenLambda() throws Throwable {
HiddenTest t = (HiddenTest)defineHiddenClass("HiddenLambda").newInstance();
var e = assertThrows(Error.class, t::test);
assertEquals("thrown by " + t.getClass().getName(), e.getMessage());
}
// Verify the nest host and nest members of a hidden class and hidden nestmate class
@Test
public void testHiddenNestHost() throws Throwable {
byte[] hc1 = hiddenClassBytes;
Lookup lookup1 = lookup().defineHiddenClass(hc1, false);
Class<?> host = lookup1.lookupClass();
byte[] hc2 = Files.readAllBytes(CLASSES_DIR.resolve("Lambda.class"));
Lookup lookup2 = lookup1.defineHiddenClass(hc2, false, NESTMATE);
Class<?> member = lookup2.lookupClass();
// test nest membership and reflection API
assertTrue(host.isNestmateOf(member));
assertSame(host, host.getNestHost());
// getNestHost and getNestMembers return the same value when calling
// on a nest member and the nest host
assertSame(host.getNestHost(), member.getNestHost());
assertArrayEquals(member.getNestMembers(), host.getNestMembers());
// getNestMembers includes the nest host that can be a hidden class but
// only includes static nest members
assertEquals(1, host.getNestMembers().length);
assertSame(host, host.getNestMembers()[0]);
}
private static Object[][] hiddenClasses() {
return new Object[][] {
new Object[] { "HiddenInterface", false },
new Object[] { "AbstractClass", false },
// a hidden annotation is useless because it cannot be referenced by any class
new Object[] { "HiddenAnnotation", false },
// class file with bad NestHost, NestMembers and InnerClasses or EnclosingMethod attribute
// define them as nestmate to verify Class::getNestHost and getNestMembers
new Object[] { "Outer", true },
new Object[] { "Outer$Inner", true },
new Object[] { "EnclosingClass", true },
new Object[] { "EnclosingClass$1", true },
};
}
/*
* Test that class file bytes that can be defined as a normal class
* can be successfully created as a hidden class even it might not
* make sense as a hidden class. For example, a hidden annotation
* is not useful as it cannot be referenced and an outer/inner class
* when defined as a hidden effectively becomes a final top-level class.
*/
@ParameterizedTest
@MethodSource("hiddenClasses")
public void defineHiddenClass(String name, boolean nestmate) throws Exception {
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
Class<?> hc;
Class<?> host;
if (nestmate) {
hc = lookup().defineHiddenClass(bytes, false, NESTMATE).lookupClass();
host = lookup().lookupClass().getNestHost();
} else {
hc = lookup().defineHiddenClass(bytes, false).lookupClass();
host = hc;
}
assertSame(host, hc.getNestHost());
assertEquals(1, hc.getNestMembers().length);
assertSame(host, hc.getNestMembers()[0]);
}
private static Object[][] emptyClasses() {
return new Object[][] {
new Object[] { "EmptyHiddenSynthetic", ACC_SYNTHETIC },
new Object[] { "EmptyHiddenEnum", ACC_ENUM },
new Object[] { "EmptyHiddenAbstractClass", ACC_ABSTRACT },
new Object[] { "EmptyHiddenInterface", ACC_ABSTRACT|ACC_INTERFACE },
new Object[] { "EmptyHiddenAnnotation", ACC_ANNOTATION|ACC_ABSTRACT|ACC_INTERFACE },
};
}
/*
* Test if an empty class with valid access flags can be created as a hidden class
* as long as it does not violate the restriction of a hidden class.
*
* A meaningful enum type defines constants of that enum type. So
* enum class containing constants of its type should not be a hidden
* class.
*/
@ParameterizedTest
@MethodSource("emptyClasses")
public void emptyHiddenClass(String name, int accessFlags) throws Exception {
byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, CD_Enum, accessFlags)
: classBytes(name, accessFlags);
Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
switch (accessFlags) {
case ACC_SYNTHETIC:
assertTrue(hc.isSynthetic());
assertFalse(hc.isEnum());
assertFalse(hc.isAnnotation());
assertFalse(hc.isInterface());
break;
case ACC_ENUM:
assertFalse(hc.isSynthetic());
assertTrue(hc.isEnum());
assertFalse(hc.isAnnotation());
assertFalse(hc.isInterface());
break;
case ACC_ABSTRACT:
assertFalse(hc.isSynthetic());
assertFalse(hc.isEnum());
assertFalse(hc.isAnnotation());
assertFalse(hc.isInterface());
break;
case ACC_ABSTRACT|ACC_INTERFACE:
assertFalse(hc.isSynthetic());
assertFalse(hc.isEnum());
assertFalse(hc.isAnnotation());
assertTrue(hc.isInterface());
break;
case ACC_ANNOTATION|ACC_ABSTRACT|ACC_INTERFACE:
assertFalse(hc.isSynthetic());
assertFalse(hc.isEnum());
assertTrue(hc.isAnnotation());
assertTrue(hc.isInterface());
break;
default:
throw new IllegalArgumentException("unexpected access flag: " + accessFlags);
}
assertTrue(hc.isHidden());
assertEquals(hc.getModifiers(), ACC_PUBLIC | accessFlags);
assertFalse(hc.isLocalClass());
assertFalse(hc.isMemberClass());
assertFalse(hc.isAnonymousClass());
assertFalse(hc.isArray());
}
// These class files can't be defined as hidden classes
private static Object[][] cantBeHiddenClasses() {
return new Object[][] {
// a hidden class can't be a field's declaring type
// enum class with static final HiddenEnum[] $VALUES:
new Object[] { "HiddenEnum" },
// supertype of this class is a hidden class
new Object[] { "HiddenSuper" },
// a record class whose equals(HiddenRecord, Object) method
// refers to a hidden class in the parameter type and fails
// verification. Perhaps this method signature should be reconsidered.
new Object[] { "HiddenRecord" },
};
}
/*
* These class files
*/
@ParameterizedTest
@MethodSource("cantBeHiddenClasses")
public void failToDeriveAsHiddenClass(String name) throws Exception {
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
assertThrows(NoClassDefFoundError.class, () -> lookup().defineHiddenClass(bytes, false).lookupClass());
}
/*
* A hidden class can be successfully created but fails to be reflected
* if it refers to its own type in the descriptor.
* e.g. Class::getMethods resolves the declaring type of fields,
* parameter types and return type.
*/
@Test
public void hiddenCantReflect() throws Throwable {
HiddenTest t = (HiddenTest)defineHiddenClass("HiddenCantReflect").newInstance();
t.test();
Class<?> c = t.getClass();
Class<?>[] intfs = c.getInterfaces();
assertEquals(1, intfs.length);
assertSame(HiddenTest.class, intfs[0]);
var e = assertThrows(NoClassDefFoundError.class, c::getDeclaredMethods);
Throwable x = e.getCause();
if (x == null || !(x instanceof ClassNotFoundException && x.getMessage().contains("HiddenCantReflect"))) {
throw e;
}
}
@Test
public void cantDefineModule() throws Throwable {
Path src = Paths.get("module-info.java");
Path dir = CLASSES_DIR.resolve("m");
Files.write(src, List.of("module m {}"), StandardCharsets.UTF_8);
compileSources(src, dir);
byte[] bytes = Files.readAllBytes(dir.resolve("module-info.class"));
assertThrows(IllegalArgumentException.class, () -> lookup().defineHiddenClass(bytes, false));
}
@Test
public void cantDefineClassInAnotherPackage() throws Throwable {
Path src = Paths.get("ClassInAnotherPackage.java");
Files.write(src, List.of("package p;", "public class ClassInAnotherPackage {}"), StandardCharsets.UTF_8);
compileSources(src, CLASSES_DIR);
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("p").resolve("ClassInAnotherPackage.class"));
assertThrows(IllegalArgumentException.class, () -> lookup().defineHiddenClass(bytes, false));
}
@Test
public void lessPrivilegedLookup() throws Throwable {
Lookup lookup = lookup().dropLookupMode(Lookup.PRIVATE);
assertThrows(IllegalAccessException.class, () -> lookup.defineHiddenClass(hiddenClassBytes, false));
}
@Test
public void badClassFileVersion() throws Throwable {
Path dir = Paths.get(System.getProperty("test.classes", "."));
byte[] bytes = Files.readAllBytes(dir.resolve("BadClassFileVersion.class"));
assertThrows(UnsupportedClassVersionError.class, () -> lookup().defineHiddenClass(bytes, false));
}
// malformed class files
private static Object[][] malformedClassFiles() throws IOException {
Path dir = Paths.get(System.getProperty("test.classes", "."));
return new Object[][] {
// `this_class` has invalid CP entry
new Object[] { Files.readAllBytes(dir.resolve("BadClassFile.class")) },
new Object[] { Files.readAllBytes(dir.resolve("BadClassFile2.class")) },
// truncated file
new Object[] { new byte[0] },
new Object[] { new byte[] {(byte) 0xCA, (byte) 0xBA, (byte) 0xBE, (byte) 0x00} },
};
}
@ParameterizedTest
@MethodSource("malformedClassFiles")
public void badClassFile(byte[] bytes) throws Throwable {
assertThrows(ClassFormatError.class, () -> lookup().defineHiddenClass(bytes, false));
}
private static Object[][] nestedTypesOrAnonymousClass() {
return new Object[][] {
// class file with bad InnerClasses or EnclosingMethod attribute
new Object[] { "Outer", null },
new Object[] { "Outer$Inner", "Outer" },
new Object[] { "EnclosingClass", null },
new Object[] { "EnclosingClass$1", "EnclosingClass" },
};
}
@ParameterizedTest
@MethodSource("nestedTypesOrAnonymousClass")
public void hasInnerClassesOrEnclosingMethodAttribute(String className, String badDeclaringClassName) throws Throwable {
byte[] bytes = Files.readAllBytes(CLASSES_10_DIR.resolve(className + ".class"));
Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
hiddenClassWithBadAttribute(hc, badDeclaringClassName);
}
// define a hidden class with static nest membership
@Test
public void hasStaticNestHost() throws Exception {
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("Outer$Inner.class"));
Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
hiddenClassWithBadAttribute(hc, "Outer");
}
@Test
public void hasStaticNestMembers() throws Throwable {
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("Outer.class"));
Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
assertHiddenClass(hc);
assertSame(hc, hc.getNestHost());
Class<?>[] members = hc.getNestMembers();
assertEquals(1, members.length);
assertSame(hc, members[0]);
}
// a hidden class with bad InnerClasses or EnclosingMethod attribute
private void hiddenClassWithBadAttribute(Class<?> hc, String badDeclaringClassName) {
assertTrue(hc.isHidden());
assertNull(hc.getCanonicalName());
assertTrue(hc.getName().contains("/"));
if (badDeclaringClassName == null) {
// the following reflection API assumes a good name in InnerClasses
// or EnclosingMethod attribute can successfully be resolved.
assertFalse(hc.getSimpleName().isEmpty());
assertFalse(hc.isAnonymousClass());
assertFalse(hc.isLocalClass());
assertFalse(hc.isMemberClass());
} else {
declaringClassNotFound(hc, badDeclaringClassName);
}
// validation of nest membership
assertSame(hc, hc.getNestHost());
// validate the static nest membership
Class<?>[] members = hc.getNestMembers();
assertEquals(1, members.length);
assertSame(hc, members[0]);
}
// Class::getSimpleName, Class::isMemberClass
private void declaringClassNotFound(Class<?> c, String cn) {
var e = assertThrows(NoClassDefFoundError.class, c::isMemberClass);
if (!e.getMessage().equals(cn)) {
throw e;
}
e = assertThrows(NoClassDefFoundError.class, c::getSimpleName);
if (!e.getMessage().equals(cn)) {
throw e;
}
}
private static void singletonNest(Class<?> hc) {
assertSame(hc, hc.getNestHost());
assertEquals(1, hc.getNestMembers().length);
assertSame(hc, hc.getNestMembers()[0]);
}
private static void assertHiddenClass(Class<?> hc) {
assertTrue(hc.isHidden());
assertNull(hc.getCanonicalName());
assertTrue(hc.getName().contains("/"));
assertFalse(hc.isAnonymousClass());
assertFalse(hc.isLocalClass());
assertFalse(hc.isMemberClass());
assertFalse(hc.getSimpleName().isEmpty()); // sanity check
}
private static byte[] classBytes(String classname, int accessFlags) {
return classBytes(classname, CD_Object, accessFlags);
}
private static byte[] classBytes(String classname, ClassDesc superType, int accessFlags) {
return ClassFile.of().build(ClassDesc.ofInternalName(classname), clb -> clb
.withVersion(JAVA_14_VERSION, 0)
.withFlags(accessFlags | ACC_PUBLIC)
.withSuperclass(superType));
}
}

View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 2019, 2025, 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
* @library /test/lib
* @build HiddenNestmateTest
* @run junit/othervm HiddenNestmateTest
*/
import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.*;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.AccessFlag;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.stream.Stream;
import static java.lang.constant.ConstantDescs.CD_Object;
import static java.lang.constant.ConstantDescs.CD_int;
import static java.lang.constant.ConstantDescs.INIT_NAME;
import static java.lang.constant.ConstantDescs.MTD_void;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import static java.lang.invoke.MethodHandles.Lookup.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class HiddenNestmateTest {
private static final ClassDesc CD_HiddenNestmateTest = HiddenNestmateTest.class.describeConstable().orElseThrow();
private static final byte[] bytes = classBytes("HiddenInjected");
private static void assertNestmate(Lookup lookup) {
assertTrue((lookup.lookupModes() & PRIVATE) != 0);
assertTrue((lookup.lookupModes() & MODULE) != 0);
Class<?> hiddenClass = lookup.lookupClass();
Class<?> nestHost = hiddenClass.getNestHost();
assertTrue(hiddenClass.isHidden());
assertSame(MethodHandles.lookup().lookupClass(), nestHost);
// hidden nestmate is not listed in the return array of getNestMembers
assertTrue(Stream.of(nestHost.getNestMembers()).noneMatch(k -> k == hiddenClass));
assertTrue(hiddenClass.isNestmateOf(lookup.lookupClass()));
assertArrayEquals(nestHost.getNestMembers(), hiddenClass.getNestMembers());
}
/*
* Test a hidden class to have no access to private members of another class
*/
@Test
public void hiddenClass() throws Throwable {
// define a hidden class
Lookup lookup = MethodHandles.lookup().defineHiddenClass(bytes, false);
Class<?> c = lookup.lookupClass();
assertTrue(lookup.hasFullPrivilegeAccess());
assertEquals(ORIGINAL, lookup.lookupModes() & ORIGINAL);
assertSame(c, c.getNestHost()); // host of its own nest
assertTrue(c.isHidden());
// invoke int test(HiddenNestmateTest o) via MethodHandle
MethodHandle ctor = lookup.findConstructor(c, MethodType.methodType(void.class));
MethodHandle mh = lookup.findVirtual(c, "test", MethodType.methodType(int.class, HiddenNestmateTest.class));
assertThrows(IllegalAccessError.class, () -> {
int x = (int) mh.bindTo(ctor.invoke()).invokeExact(this);
});
// invoke int test(HiddenNestmateTest o)
assertThrows(IllegalAccessError.class, () -> testInjectedClass(c));
}
/*
* Test a hidden class to have access to private members of its nestmates
*/
@Test
public void hiddenNestmate() throws Throwable {
// define a hidden nestmate class
Lookup lookup = MethodHandles.lookup().defineHiddenClass(bytes, false, NESTMATE);
Class<?> c = lookup.lookupClass();
assertNestmate(lookup);
// invoke int test(HiddenNestmateTest o) via MethodHandle
MethodHandle ctor = lookup.findConstructor(c, MethodType.methodType(void.class));
MethodHandle mh = lookup.findVirtual(c, "test", MethodType.methodType(int.class, HiddenNestmateTest.class));
int x = (int)mh.bindTo(ctor.invoke()).invokeExact( this);
assertEquals(privMethod(), x);
// invoke int test(HiddenNestmateTest o)
int x1 = testInjectedClass(c);
assertEquals(privMethod(), x1);
}
/*
* Test a hidden class created with NESTMATE and STRONG option is a nestmate
*/
@Test
public void hiddenStrongClass() throws Throwable {
// define a hidden class strongly referenced by the class loader
Lookup lookup = MethodHandles.lookup().defineHiddenClass(bytes, false, NESTMATE, STRONG);
assertNestmate(lookup);
}
/*
* Fail to create a hidden class if dropping PRIVATE lookup mode
*/
@Test
public void noPrivateLookupAccess() throws Throwable {
Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.PRIVATE);
assertThrows(IllegalAccessException.class, () -> lookup.defineHiddenClass(bytes, false, NESTMATE));
}
public void teleportToNestmate() throws Throwable {
Lookup lookup = MethodHandles.lookup().defineHiddenClass(bytes, false, NESTMATE);
assertNestmate(lookup);
// Teleport to a hidden nestmate
Lookup lc = MethodHandles.lookup().in(lookup.lookupClass());
assertNotEquals(0, lc.lookupModes() & PRIVATE);
assertEquals(0, lc.lookupModes() & ORIGINAL);
Lookup lc2 = lc.defineHiddenClass(bytes, false, NESTMATE);
assertNestmate(lc2);
}
/*
* Fail to create a hidden class in a different package from the lookup class' package
*/
@Test
public void notSamePackage() throws Throwable {
assertThrows(IllegalArgumentException.class, () -> MethodHandles.lookup().defineHiddenClass(classBytes("p/HiddenInjected"), false, NESTMATE));
}
/*
* invoke int test(HiddenNestmateTest o) method defined in the injected class
*/
private int testInjectedClass(Class<?> c) throws Throwable {
try {
Method m = c.getMethod("test", HiddenNestmateTest.class);
return (int) m.invoke(c.newInstance(), this);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
private static byte[] classBytes(String classname) {
return ClassFile.of().build(ClassDesc.ofInternalName(classname), clb -> {
clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.FINAL);
clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> {
cob.aload(0);
cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
cob.return_();
});
clb.withMethodBody("test", MethodTypeDesc.of(CD_int, CD_HiddenNestmateTest), PUBLIC, cob -> {
cob.aload(1);
cob.invokevirtual(CD_HiddenNestmateTest, "privMethod", MethodTypeDesc.of(CD_int));
cob.ireturn();
});
});
}
private int privMethod() { return 1234; }
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2019, 2025, 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
* @summary define a lambda proxy class whose target class has an invalid
* nest membership
* @run junit/othervm p.LambdaNestedInnerTest
*/
package p;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class LambdaNestedInnerTest {
private static final String INNER_CLASSNAME = "p.LambdaNestedInnerTest$Inner";
private static final String DIR = "missingOuter";
public static class Inner implements Runnable {
// generate lambda proxy class
private Runnable lambda1 = this::doit;
@Override
public void run() {
// validate the lambda proxy class
Class<?> lambdaProxyClass = lambda1.getClass();
assertTrue(lambdaProxyClass.isHidden());
System.out.format("%s nest host %s nestmate of Inner class %s%n",
lambdaProxyClass, lambdaProxyClass.getNestHost(),
lambdaProxyClass.isNestmateOf(Inner.class));
assertTrue(lambdaProxyClass.getNestHost() == Inner.class.getNestHost());
assertTrue(Arrays.equals(lambdaProxyClass.getNestMembers(), Inner.class.getNestMembers()));
assertTrue(lambdaProxyClass.isNestmateOf(Inner.class));
lambda1.run();
}
// junit may not be visible to this class
private static void assertTrue(boolean x) {
if (!x) {
throw new AssertionError("expected true but found false");
}
}
private void doit() {
}
}
@BeforeAll
public static void setup() throws IOException {
String filename = INNER_CLASSNAME.replace('.', File.separatorChar) + ".class";
Path src = Paths.get(System.getProperty("test.classes"), filename);
Path dest = Paths.get(DIR, filename);
Files.createDirectories(dest.getParent());
Files.copy(src, dest, REPLACE_EXISTING);
}
@Test
public void test() throws Exception {
Class<?> inner = Class.forName(INNER_CLASSNAME);
// inner class is a nest member of LambdaNestedInnerTest
Class<?> nestHost = inner.getNestHost();
assertSame(LambdaNestedInnerTest.class, nestHost);
Set<Class<?>> members = Arrays.stream(nestHost.getNestMembers()).collect(Collectors.toSet());
assertEquals(Set.of(nestHost, inner, TestLoader.class), members);
// spin lambda proxy hidden class
Runnable runnable = (Runnable) inner.newInstance();
runnable.run();
}
@Test
public void nestHostNotExist() throws Exception {
URL[] urls = new URL[] { Paths.get(DIR).toUri().toURL() };
URLClassLoader loader = new URLClassLoader(urls, null);
Class<?> inner = loader.loadClass(INNER_CLASSNAME);
assertSame(loader, inner.getClassLoader());
assertSame(inner, inner.getNestHost()); // linkage error ignored
Runnable runnable = (Runnable) inner.newInstance();
// this validates the lambda proxy class
runnable.run();
}
/*
* Tests IncompatibleClassChangeError thrown since the true nest host is not
* in the same runtime package as the hidden class
*/
@Test
public void nestHostNotSamePackage() throws Exception {
URL[] urls = new URL[] { Paths.get(DIR).toUri().toURL() };
TestLoader loader = new TestLoader(urls);
Class<?> inner = loader.loadClass(INNER_CLASSNAME);
assertSame(loader, inner.getClassLoader());
assertSame(inner, inner.getNestHost()); // linkage error ignored.
Runnable runnable = (Runnable) inner.newInstance();
// this validates the lambda proxy class
runnable.run();
}
static class TestLoader extends URLClassLoader {
TestLoader(URL[] urls) {
super(urls, TestLoader.class.getClassLoader());
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (INNER_CLASSNAME.equals(name)) {
return findClass(name);
} else {
// delegate to its parent
return loadClass(name, false);
}
}
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2021, 2026, 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 8245432
* @modules jdk.compiler
* @library /test/lib
* @requires !java.enablePreview
* @build jdk.test.lib.Utils
* jdk.test.lib.compiler.CompilerUtils
* @run junit PreviewHiddenClass
* @summary verify UnsupportedClassVersionError thrown when defining a hidden class
* with preview minor version but --enable-preview is not set
* @comment This test itself cannot enablePreview, or hidden class definition
* will pass
*/
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.Utils;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class PreviewHiddenClass {
private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src");
private static final Path CLASSES_DIR = Paths.get("classes");
@Test
public void previewNotEnabled() throws Exception {
// compile a class with --enable-preview
Path sourceFile = SRC_DIR.resolve("HiddenInterface.java");
String[] options = new String[] {
"--enable-preview", "-source", String.valueOf(Runtime.version().feature()), "-XDforcePreview" };
if (!CompilerUtils.compile(sourceFile, CLASSES_DIR, options)) {
throw new RuntimeException("Compilation of the test failed: " + sourceFile);
}
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenInterface.class"));
var dis = new DataInputStream(new ByteArrayInputStream(bytes));
dis.skipBytes(4); // 0xCAFEBABE
assertEquals(65535, dis.readUnsignedShort()); // Minor version
assertThrows(UnsupportedClassVersionError.class, () -> MethodHandles.lookup().defineHiddenClass(bytes, false));
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 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
* 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.
*/
/*
* The classfile for this class will be used to define a hidden class
* The load of this class will fail because hidden classes cannot
* use their name in field signatures.
*/
public class SelfRefField implements Test {
SelfRefField other = null;
private void realTest() {
other = this; // field signature test
}
public void test() {
realTest();
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 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
* 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.
*/
/*
* The classfile for this class will be used to define a hidden class
* The load of this class will fail because hidden classes cannot
* use their names in method signatures.
*/
public class SelfRefMethod implements Test {
private void realTest() {
SelfRefMethod local = this;
set_other(local); // method signature test
}
private void set_other(SelfRefMethod t) {
}
public void test() {
realTest();
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2019, 2020, 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
* @modules jdk.compiler
* @library /test/lib
* @build jdk.test.lib.Utils
* jdk.test.lib.compiler.CompilerUtils
* SelfReferenceDescriptor
* @run main/othervm -Xverify:remote SelfReferenceDescriptor
* @summary Test that a hidden class cannot be referenced in descriptor
*/
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import static java.lang.invoke.MethodHandles.lookup;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Stream;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.Utils;
/* package-private */ interface Test {
void test();
}
public class SelfReferenceDescriptor {
private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC);
private static final Path CLASSES_DIR = Paths.get("classes");
static void compileSources(Path sourceFile, String... options) throws IOException {
Stream<String> ops = Stream.of("-cp", Utils.TEST_CLASSES + File.pathSeparator + CLASSES_DIR);
if (options != null && options.length > 0) {
ops = Stream.concat(ops, Arrays.stream(options));
}
if (!CompilerUtils.compile(sourceFile, CLASSES_DIR, ops.toArray(String[]::new))) {
throw new RuntimeException("Compilation of the test failed: " + sourceFile);
}
}
// Test that a hidden class cannot use its own name in a field
// signature.
public static void hiddenClassInFieldDescriptor() throws Exception {
compileSources(SRC_DIR.resolve("SelfRefField.java"));
Path path = CLASSES_DIR.resolve("SelfRefField.class");
byte[] bytes = Files.readAllBytes(path);
try {
lookup().defineHiddenClass(bytes, false, NESTMATE);
throw new RuntimeException("expected NCDFE in defining SelfRefField hidden class");
} catch (NoClassDefFoundError e) {
if (!e.getMessage().contains("SelfRefField")) throw e;
}
}
// Test that a hidden class cannot use its own name in a method
// signature.
public static void hiddenClassInMethodDescriptor() throws Exception {
compileSources(SRC_DIR.resolve("SelfRefMethod.java"));
Path path = CLASSES_DIR.resolve("SelfRefMethod.class");
byte[] bytes = Files.readAllBytes(path);
try {
lookup().defineHiddenClass(bytes, false, NESTMATE);
throw new RuntimeException("expected NCDFE in defining SelfRefMethod hidden class");
} catch (NoClassDefFoundError e) {
if (!e.getMessage().contains("SelfRefMethod")) throw e;
}
}
public static void main(String... args) throws Exception {
hiddenClassInMethodDescriptor();
hiddenClassInFieldDescriptor();
}
}

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2021, 2025, 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 8266925
* @summary hidden class members can't be statically invocable
* @modules java.base/jdk.internal.misc
* @build java.base/*
* @run junit StaticInvocableTest
*/
import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.LookupHelper;
import java.lang.reflect.AccessFlag;
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.constant.ConstantDescs.CD_Object;
import static java.lang.constant.ConstantDescs.CD_int;
import static java.lang.constant.ConstantDescs.INIT_NAME;
import static java.lang.constant.ConstantDescs.MTD_void;
import org.junit.jupiter.api.Test;
public class StaticInvocableTest {
public static void main(String[] args) throws Throwable {
StaticInvocableTest test = new StaticInvocableTest();
test.testJavaLang();
test.testJavaUtil();
test.testJdkInternalMisc();
test.testJavaLangInvoke();
test.testProhibitedJavaPkg();
System.out.println("TEST PASSED");
}
// Test hidden classes from different packages
// (see j.l.i.InvokerBytecodeGenerator::isStaticallyInvocable).
@Test public void testJavaLang() throws Throwable { test("java/lang"); }
@Test public void testJavaUtil() throws Throwable { test("java/util"); }
@Test public void testJdkInternalMisc() throws Throwable { test("jdk/internal/misc"); }
@Test public void testJavaLangInvoke() throws Throwable { test("java/lang/invoke"); }
@Test public void testProhibitedJavaPkg() throws Throwable {
try {
test("java/prohibited");
} catch (IllegalArgumentException e) {
return;
}
throw new RuntimeException("Expected SecurityException");
}
private static void test(String pkg) throws Throwable {
byte[] bytes = dumpClass(pkg);
Lookup lookup;
if (pkg.equals("java/prohibited")) {
StaticInvocableTest sampleclass = new StaticInvocableTest();
lookup = LookupHelper.newLookup(sampleclass.getClass());
} else if (pkg.equals("java/lang")) {
lookup = LookupHelper.newLookup(Object.class);
} else if (pkg.equals("java/util")) {
lookup = LookupHelper.newLookup(java.util.ArrayList.class);
} else if (pkg.equals("jdk/internal/misc")) {
lookup = LookupHelper.newLookup(jdk.internal.misc.Signal.class);
} else if (pkg.equals("java/lang/invoke")) {
lookup = LookupHelper.newLookup(java.lang.invoke.CallSite.class);
} else {
throw new RuntimeException("Unexpected pkg: " + pkg);
}
// Define hidden class
Lookup l = lookup.defineHiddenClass(bytes, true);
MethodType t = MethodType.methodType(Object.class, int.class);
MethodHandle target = l.findStatic(l.lookupClass(), "get", t);
// Wrap target into LF (convert) to get "target" referenced from LF
MethodHandle wrappedMH = target.asType(MethodType.methodType(Object.class, Integer.class));
// Invoke enough times to provoke LF compilation to bytecode.
for (int i = 0; i<100; i++) {
Object r = wrappedMH.invokeExact((Integer)1);
}
}
/*
* Constructs bytecode for the following class:
* public class pkg.MyClass {
* MyClass() {}
* public Object get(int i) { return null; }
* }
*/
public static byte[] dumpClass(String pkg) {
return ClassFile.of().build(ClassDesc.of(pkg.replace('/', '.'), "MyClass"), clb -> {
clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
clb.withMethodBody(INIT_NAME, MTD_void, 0, cob -> {
cob.aload(0);
cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
cob.return_();
});
clb.withMethodBody("get", MethodTypeDesc.of(CD_Object, CD_int),
ACC_PUBLIC | ACC_STATIC, cob -> {
cob.aconst_null();
cob.areturn();
});
});
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2020, 2025, 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 8242013
* @run junit/othervm test.TypeDescriptorTest
* @summary Test TypeDescriptor::descriptorString for hidden classes which
* cannot be used to produce ConstantDesc via ClassDesc or
* MethodTypeDesc factory methods
*/
package test;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.constant.*;
import java.lang.invoke.*;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Array;
import java.nio.file.Files;
import java.nio.file.Paths;
import static java.lang.invoke.MethodType.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class TypeDescriptorTest {
private static final Lookup HC_LOOKUP = defineHiddenClass();
private static final Class<?> HC = HC_LOOKUP.lookupClass();
private static Lookup defineHiddenClass() {
String classes = System.getProperty("test.classes");
try {
byte[] bytes = Files.readAllBytes(Paths.get(classes, "test/HiddenClass.class"));
return MethodHandles.lookup().defineHiddenClass(bytes, true);
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static Object[][] constables() throws Exception {
Class<?> hcArray = Array.newInstance(HC, 1).getClass();
return new Object[][] {
new Object[] { HC },
new Object[] { hcArray },
new Object[] { methodType(HC) },
new Object[] { methodType(void.class, HC) },
new Object[] { methodType(void.class, HC, int.class) },
new Object[] { HC_LOOKUP.findStatic(HC, "m", methodType(void.class)) },
new Object[] { HC_LOOKUP.findStaticVarHandle(HC, "f", Object.class) }
};
}
/*
* Hidden classes have no nominal descriptor.
* Constable::describeConstable returns empty optional.
*/
@ParameterizedTest
@MethodSource("constables")
public void noNominalDescriptor(Constable constable) {
assertTrue(constable.describeConstable().isEmpty());
}
/*
* ClassDesc factory methods throws IAE with the name or descriptor string
* from a hidden class
*/
@Test
public void testClassDesc() {
assertThrows(IllegalArgumentException.class, () -> ClassDesc.ofDescriptor(HC.descriptorString()));
assertThrows(IllegalArgumentException.class, () -> ClassDesc.ofDescriptor(HC.getName()));
assertThrows(IllegalArgumentException.class, () -> ClassDesc.of(HC.getPackageName(), HC.getSimpleName()));
assertThrows(IllegalArgumentException.class, () -> ClassDesc.of(HC.getName()));
}
private static Object[][] typeDescriptors() throws Exception {
Class<?> hcArray = Array.newInstance(HC, 1, 1).getClass();
return new Object[][] {
new Object[] { HC, "Ltest/HiddenClass.0x[0-9a-f]+;"},
new Object[] { hcArray, "\\[\\[Ltest/HiddenClass.0x[0-9a-f]+;"},
new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" },
new Object[] { methodType(void.class, HC), "\\(Ltest/HiddenClass.0x[0-9a-f]+;\\)V" },
new Object[] { methodType(void.class, HC, int.class, Object.class), "\\(Ltest/HiddenClass.0x[0-9a-f]+;ILjava/lang/Object;\\)V" }
};
}
/*
* Hidden classes have no nominal type descriptor
*/
@ParameterizedTest
@MethodSource("typeDescriptors")
public void testTypeDescriptor(TypeDescriptor td, String regex) throws Exception {
String desc = td.descriptorString();
assertTrue(desc.matches(regex));
if (td instanceof Class) {
assertThrows(IllegalArgumentException.class, () -> ClassDesc.ofDescriptor(desc));
} else if (td instanceof MethodType) {
assertThrows(IllegalArgumentException.class, () -> MethodTypeDesc.ofDescriptor(desc));
}
}
private static Object[][] methodTypes() throws Exception {
Class<?> hcArray = Array.newInstance(HC, 1, 1).getClass();
return new Object[][] {
new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" },
new Object[] { methodType(void.class, hcArray), "\\(\\[\\[Ltest/HiddenClass.0x[0-9a-f]+;\\)V" },
new Object[] { methodType(void.class, int.class, HC), "\\(ILtest/HiddenClass.0x[0-9a-f]+;\\)V" }
};
}
/*
* Test MethodType::toMethodDescriptorString with MethodType referencing to hidden class
*/
@ParameterizedTest
@MethodSource("methodTypes")
public void testToMethodDescriptorString(MethodType mtype, String regex) throws Exception {
String desc = mtype.toMethodDescriptorString();
assertTrue(desc.matches(regex));
assertThrows(IllegalArgumentException.class, () -> MethodType.fromMethodDescriptorString(desc, TypeDescriptorTest.class.getClassLoader()));
}
}
class HiddenClass {
private static final Object f = new Object();
public static void m() {
}
}

View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2020, 2025, 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
* @summary verify if the hidden class is unloaded when the class loader is GC'ed
* @modules jdk.compiler
* @library /test/lib/
* @build jdk.test.lib.util.ForceGC
* @run junit/othervm UnloadingTest
*/
import java.io.IOException;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.test.lib.util.ForceGC;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.Utils;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class UnloadingTest {
private static final Path CLASSES_DIR = Paths.get("classes");
private static byte[] hiddenClassBytes;
@BeforeAll
static void setup() throws IOException {
Path src = Paths.get(Utils.TEST_SRC, "src", "LookupHelper.java");
if (!CompilerUtils.compile(src, CLASSES_DIR)) {
throw new RuntimeException("Compilation of the test failed: " + src);
}
hiddenClassBytes = Files.readAllBytes(CLASSES_DIR.resolve("LookupHelper.class"));
}
/*
* Test that a hidden class is unloaded while the loader remains strongly reachable
*/
@Test
public void unloadable() throws Exception {
TestLoader loader = new TestLoader();
Class<?> helper = Class.forName("LookupHelper", true, loader);
Method m = helper.getMethod("getLookup");
Lookup lookup = (Lookup)m.invoke(null);
HiddenClassUnloader unloader = createHiddenClass(lookup, false);
// the hidden class should be unloaded
unloader.unload();
// loader is strongly reachable
Reference.reachabilityFence(loader);
}
/*
* Test that a hidden class is not unloaded when the loader is strongly reachable
*/
@Test
public void notUnloadable() throws Exception {
TestLoader loader = new TestLoader();
Class<?> helper = Class.forName("LookupHelper", true, loader);
Method m = helper.getMethod("getLookup");
Lookup lookup = (Lookup)m.invoke(null);
HiddenClassUnloader unloader = createHiddenClass(lookup, true);
assertFalse(unloader.tryUnload()); // hidden class is not unloaded
// loader is strongly reachable
Reference.reachabilityFence(loader);
}
/*
* Create a nest of two hidden classes.
* They can be unloaded even the loader is strongly reachable
*/
@Test
public void hiddenClassNest() throws Exception {
TestLoader loader = new TestLoader();
Class<?> helper = Class.forName("LookupHelper", true, loader);
Method m = helper.getMethod("getLookup");
Lookup lookup = (Lookup)m.invoke(null);
HiddenClassUnloader[] unloaders = createNestOfTwoHiddenClasses(lookup, false, false);
// keep a strong reference to the nest member class
Class<?> member = unloaders[1].weakRef.get();
assertNotNull(member);
// nest host and member will not be unloaded
assertFalse(unloaders[0].tryUnload());
assertFalse(unloaders[1].tryUnload());
// clear the reference to the nest member
Reference.reachabilityFence(member);
member = null;
// nest host and member will be unloaded
unloaders[0].unload();
unloaders[1].unload();
// loader is strongly reachable
Reference.reachabilityFence(loader);
}
/*
* Create a nest with a hidden class nest host and strong nest member.
* Test that both are not unloaded
*/
@Test
public void hiddenClassNestStrongMember() throws Exception {
TestLoader loader = new TestLoader();
Class<?> helper = Class.forName("LookupHelper", true, loader);
Method m = helper.getMethod("getLookup");
Lookup lookup = (Lookup)m.invoke(null);
HiddenClassUnloader[] unloaders = createNestOfTwoHiddenClasses(lookup, false, true);
assertFalse(unloaders[0].tryUnload()); // nest host cannot be unloaded
assertFalse(unloaders[1].tryUnload()); // nest member cannot be unloaded
// loader is strongly reachable
Reference.reachabilityFence(loader);
}
/*
* Create a nest with a strong hidden nest host and a hidden class member.
* The nest member can be unloaded whereas the nest host will not be unloaded.
*/
@Test
public void hiddenClassNestStrongHost() throws Exception {
TestLoader loader = new TestLoader();
Class<?> helper = Class.forName("LookupHelper", true, loader);
Method m = helper.getMethod("getLookup");
Lookup lookup = (Lookup)m.invoke(null);
HiddenClassUnloader[] unloaders = createNestOfTwoHiddenClasses(lookup, true, false);
assertFalse(unloaders[0].tryUnload()); // nest host cannot be unloaded
unloaders[1].unload();
// loader is strongly reachable
Reference.reachabilityFence(loader);
}
/*
* Create a HiddenClassUnloader that holds a weak reference to the newly created
* hidden class.
*/
static HiddenClassUnloader createHiddenClass(Lookup lookup, boolean strong) throws Exception {
Class<?> hc;
if (strong) {
hc = lookup.defineHiddenClass(hiddenClassBytes, false, STRONG).lookupClass();
} else {
hc = lookup.defineHiddenClass(hiddenClassBytes, false).lookupClass();
}
assertSame(lookup.lookupClass().getClassLoader(), hc.getClassLoader());
return new HiddenClassUnloader(hc);
}
/*
* Create an array of HiddenClassUnloader with two elements: the first element
* is for the nest host and the second element is for the nest member.
*/
static HiddenClassUnloader[] createNestOfTwoHiddenClasses(Lookup lookup, boolean strongHost, boolean strongMember) throws Exception {
Lookup hostLookup;
if (strongHost) {
hostLookup = lookup.defineHiddenClass(hiddenClassBytes, false, STRONG);
} else {
hostLookup = lookup.defineHiddenClass(hiddenClassBytes, false);
}
Class<?> host = hostLookup.lookupClass();
Class<?> member;
if (strongMember) {
member = hostLookup.defineHiddenClass(hiddenClassBytes, false, NESTMATE, STRONG).lookupClass();
} else {
member = hostLookup.defineHiddenClass(hiddenClassBytes, false, NESTMATE).lookupClass();
}
assertSame(host, member.getNestHost());
return new HiddenClassUnloader[] { new HiddenClassUnloader(host), new HiddenClassUnloader(member) };
}
static class HiddenClassUnloader {
private final WeakReference<Class<?>> weakRef;
private HiddenClassUnloader(Class<?> hc) {
assertTrue(hc.isHidden());
this.weakRef = new WeakReference<>(hc);
}
void unload() {
// Force garbage collection to trigger unloading of class loader
// and native library.
if (!ForceGC.wait(() -> weakRef.refersTo(null))) {
throw new RuntimeException("loader " + " not unloaded!");
}
}
boolean tryUnload() {
return ForceGC.waitFor(() -> weakRef.refersTo(null), 2000L);
}
}
static class TestLoader extends URLClassLoader {
static URL[] toURLs() {
try {
return new URL[] { CLASSES_DIR.toUri().toURL() };
} catch (MalformedURLException e) {
throw new Error(e);
}
}
static AtomicInteger counter = new AtomicInteger();
TestLoader() {
super("testloader-" + counter.addAndGet(1), toURLs(), ClassLoader.getSystemClassLoader());
}
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021, 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.
*/
package java.lang.invoke;
import java.lang.invoke.MethodHandles.Lookup;
public class LookupHelper {
public static Lookup newLookup(Class<?> c) {
return new Lookup(c);
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 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
* 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.
*/
public abstract class AbstractClass {
abstract void test();
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 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
* 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.
*/
public class EnclosingClass {
public static void run() {
Runnable r = new Runnable() {
public void run() {}
};
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020, 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.
*/
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public @interface HiddenAnnotation {
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 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
* 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.
*/
/*
* The classfile does not fail verification but would fail when
* getMethod
*/
public class HiddenCantReflect implements HiddenTest {
HiddenCantReflect other = null;
private String realTest() {
Object o = other;
HiddenCantReflect local = this;
local = other;
local = (HiddenCantReflect) o;
local = new HiddenCantReflect();
set_other(null);
local = getThis();
set_other_maybe(new Object());
set_other_maybe(this);
return "HiddenCantReflect";
}
private HiddenCantReflect getThis() {
return null;
}
private void set_other(HiddenCantReflect t) {
other = t;
}
private void set_other_maybe(Object o) {
if (o instanceof HiddenCantReflect) {
}
}
public void test() {
String result = realTest();
// Make sure that the Utf8 constant pool entry for "HiddenCantReflect" is okay.
if (!result.substring(0, 7).equals("HiddenC") ||
!result.substring(7).equals("antReflect")) {
throw new RuntimeException("'HiddenCantReflect string is bad: " + result);
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 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
* 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.
*/
/*
* The classfile for this class will be loaded directly and used to define
* a hidden class.
*/
public class HiddenClass implements HiddenTest {
HiddenClass other = null;
private String realTest() {
Object o = other;
HiddenClass local = this;
local = other;
local = (HiddenClass) o;
local = new HiddenClass();
set_other_maybe(new Object());
set_other_maybe(this);
return "HiddenClass";
}
private void set_other_maybe(Object o) {
if (o instanceof HiddenClass) {
}
}
public void test() {
String result = realTest();
// Make sure that the Utf8 constant pool entry for "HiddenClass" is okay.
if (!result.substring(0, 7).equals("HiddenC") ||
!result.substring(7).equals("lass")) {
throw new RuntimeException("'HiddenClass string is bad: " + result);
}
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 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
* 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.
*/
/*
* The classfile for this class will be loaded directly and used to define
* a hidden class.
*/
public class HiddenClassThrow implements HiddenTest {
public void test() {
throw new RuntimeException(this.getClass().getName());
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2020, 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.
*/
// fail to create HiddenEnum as a hidden class as it fails verification
// <clinit> initializes the static final HiddenEnum[] $VALUES field
public enum HiddenEnum {
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 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
* 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.
*/
/*
* The classfile for this class will be used to define a hidden interface.
* This class will fail to be created as a hidden class because hidden classes
* cannot user their name in field signatures.
*/
public interface HiddenInterface {
default void test() {
record R() {}
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024, 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.
*/
import java.util.function.Function;
public class HiddenLambda implements HiddenTest {
public void test() {
Function<Object, String> f = o -> o.toString();
String s = f.apply(this);
throw new Error("thrown by " + s);
}
public String toString() {
return getClass().getName();
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020, 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.
*/
// fail to create HiddenRecord as a hidden class
// verification fails in the BSM to invoke equals(HiddenRecord, Object) method
record HiddenRecord(int i) { }

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 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
* 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.
*/
public class HiddenSuper extends HiddenClass implements HiddenTest {
private void realTest() {
}
public void test() {
realTest();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 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
* 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.
*/
import java.util.function.Function;
public class Lambda implements HiddenTest {
public void test() {
Function<Object, String> f = Object::toString;
String s = f.apply(this);
throw new Error("thrown by " + s);
}
public String toString() {
return getClass().getName();
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020, 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.
*/
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
public class LookupHelper {
private Lookup lookup() {
return MethodHandles.lookup();
}
public static Lookup getLookup() {
return (new LookupHelper()).lookup();
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 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
* 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.
*/
public class Outer {
public static class Inner {
}
}