-
Notifications
You must be signed in to change notification settings - Fork 710
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15044 from thallium/master
Tests for final fields of hidden class, regular class, and interface
- Loading branch information
Showing
5 changed files
with
290 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
.../functional/Java15andUp/src/org/openj9/test/hiddenclasses/HiddenClassFinalFieldTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package org.openj9.test.hiddenclasses; | ||
|
||
/******************************************************************************* | ||
* Copyright (c) 2022, 2022 IBM Corp. and others | ||
* | ||
* This program and the accompanying materials are made available under | ||
* the terms of the Eclipse Public License 2.0 which accompanies this | ||
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* or the Apache License, Version 2.0 which accompanies this distribution and | ||
* is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* This Source Code may also be made available under the following | ||
* Secondary Licenses when the conditions for such availability set | ||
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU | ||
* General Public License, version 2 with the GNU Classpath | ||
* Exception [1] and GNU General Public License, version 2 with the | ||
* OpenJDK Assembly Exception [2]. | ||
* | ||
* [1] https://www.gnu.org/software/classpath/license.html | ||
* [2] http://openjdk.java.net/legal/assembly-exception.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception | ||
*******************************************************************************/ | ||
|
||
import jdk.internal.misc.Unsafe; | ||
import org.objectweb.asm.ClassWriter; | ||
import org.objectweb.asm.FieldVisitor; | ||
import org.objectweb.asm.MethodVisitor; | ||
import org.testng.annotations.Test; | ||
|
||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.VarHandle; | ||
import java.lang.reflect.Field; | ||
|
||
import static org.objectweb.asm.Opcodes.*; | ||
|
||
@Test(groups = { "level.sanity" }) | ||
public class HiddenClassFinalFieldTests { | ||
|
||
static Unsafe unsafe = Unsafe.getUnsafe(); | ||
|
||
Class<?> makeHiddenClass() throws Exception { | ||
MethodHandles.Lookup lookup = MethodHandles.lookup(); | ||
|
||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); | ||
FieldVisitor fv; | ||
MethodVisitor mv; | ||
cw.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "org/openj9/test/hiddenclasses/TestHiddenClass", null, "java/lang/Object", null); | ||
{ | ||
fv = cw.visitField(ACC_PUBLIC | ACC_STATIC, "modifiableField", "Ljava/lang/String;", null, "old"); | ||
fv.visitEnd(); | ||
} | ||
{ | ||
cw.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, "finalField", "Ljava/lang/String;", null, "old"); | ||
fv.visitEnd(); | ||
} | ||
{ | ||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); | ||
mv.visitCode(); | ||
mv.visitVarInsn(ALOAD, 0); | ||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); | ||
mv.visitInsn(RETURN); | ||
mv.visitMaxs(1, 1); | ||
mv.visitEnd(); | ||
} | ||
cw.visitEnd(); | ||
|
||
return lookup.defineHiddenClass(cw.toByteArray(), true, MethodHandles.Lookup.ClassOption.NESTMATE).lookupClass(); | ||
} | ||
|
||
/* Final static fields in hidden classes are not modifiable through reflection. */ | ||
@Test(expectedExceptions = java.lang.IllegalAccessException.class) | ||
public void test_javaLangReflectFieldSet_finalStaticHiddenClassField() throws Throwable { | ||
Class<?> c = makeHiddenClass(); | ||
|
||
Object hiddenClassObject = c.getConstructor().newInstance(); | ||
Field finalHiddenClassField = hiddenClassObject.getClass().getDeclaredField("finalField"); | ||
finalHiddenClassField.setAccessible(true); | ||
finalHiddenClassField.set(hiddenClassObject, "new"); | ||
} | ||
|
||
/* Make sure non-final fields in hidden classes can still be modified. */ | ||
@Test | ||
public void test_javaLangReflectFieldSet_StaticHiddenClassField() throws Throwable { | ||
Class<?> c = makeHiddenClass(); | ||
|
||
Object hiddenClassObject = c.getConstructor().newInstance(); | ||
Field finalHiddenClassField = hiddenClassObject.getClass().getDeclaredField("modifiableField"); | ||
finalHiddenClassField.setAccessible(true); | ||
finalHiddenClassField.set(hiddenClassObject, "new"); | ||
} | ||
|
||
/* Check that Unsafe.staticFieldOffset supports hidden classes. */ | ||
@Test | ||
public void test_jdkInternalMiscUnsafe_staticFieldOffset() throws Throwable { | ||
Class<?> c = makeHiddenClass(); | ||
Field finalHiddenClassField = c.getDeclaredField("finalField"); | ||
unsafe.staticFieldOffset(finalHiddenClassField); | ||
} | ||
|
||
/* Check that Unsafe.staticFieldBase supports hidden classes. */ | ||
@Test | ||
public void test_jdkInternalMiscUnsafe_staticFieldBase() throws Throwable { | ||
Class<?> c = makeHiddenClass(); | ||
Field finalHiddenClassField = c.getDeclaredField("finalField"); | ||
unsafe.staticFieldBase(finalHiddenClassField); | ||
} | ||
|
||
/* VarHandle.set is not supported for hidden classes. */ | ||
@Test(expectedExceptions = java.lang.UnsupportedOperationException.class) | ||
public void test_javaLangInvokeMethodHandles_unreflectVarHandle_static() throws Throwable { | ||
Class<?> c = makeHiddenClass(); | ||
Field finalHiddenClassField = c.getDeclaredField("finalField"); | ||
finalHiddenClassField.setAccessible(true); | ||
VarHandle finalHiddenClassFieldHandle = MethodHandles.lookup().unreflectVarHandle(finalHiddenClassField); | ||
finalHiddenClassFieldHandle.set("new"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
.../org/openj9/test/regularclassesandinterfaces/RegularClassAndInterfaceFinalFieldTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package org.openj9.test.regularclassesandinterfaces; | ||
|
||
/******************************************************************************* | ||
* Copyright (c) 2022, 2022 IBM Corp. and others | ||
* | ||
* This program and the accompanying materials are made available under | ||
* the terms of the Eclipse Public License 2.0 which accompanies this | ||
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* or the Apache License, Version 2.0 which accompanies this distribution and | ||
* is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* This Source Code may also be made available under the following | ||
* Secondary Licenses when the conditions for such availability set | ||
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU | ||
* General Public License, version 2 with the GNU Classpath | ||
* Exception [1] and GNU General Public License, version 2 with the | ||
* OpenJDK Assembly Exception [2]. | ||
* | ||
* [1] https://www.gnu.org/software/classpath/license.html | ||
* [2] http://openjdk.java.net/legal/assembly-exception.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception | ||
*******************************************************************************/ | ||
|
||
import jdk.internal.misc.Unsafe; | ||
import org.testng.annotations.Test; | ||
|
||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.VarHandle; | ||
import java.lang.reflect.Field; | ||
|
||
@Test(groups = { "level.sanity" }) | ||
public class RegularClassAndInterfaceFinalFieldTests { | ||
static Unsafe unsafe = Unsafe.getUnsafe(); | ||
|
||
private class TestClass { | ||
static String modifiableField = "old"; | ||
static final String finalField = "old"; | ||
} | ||
|
||
private interface TestInterface { | ||
static final String finalField = "old"; | ||
} | ||
|
||
/* Final static fields in regular classes are not modifiable through reflection. */ | ||
@Test(expectedExceptions = java.lang.IllegalAccessException.class) | ||
public void test_javaLangReflectFieldSet_finalStaticClassField() throws Throwable { | ||
TestClass classObject = new TestClass(); | ||
Field finalClassField = classObject.getClass().getDeclaredField("finalField"); | ||
finalClassField.setAccessible(true); | ||
finalClassField.set(classObject, "new"); | ||
} | ||
|
||
/* Make sure non-final fields in regular classes can still be modified. */ | ||
@Test | ||
public void test_javaLangReflectFieldSet_staticClassField() throws Throwable { | ||
TestClass classObject = new TestClass(); | ||
Field classField = classObject.getClass().getDeclaredField("modifiableField"); | ||
classField.setAccessible(true); | ||
classField.set(null, "new"); | ||
} | ||
|
||
/* Final static fields in interface are not modifiable through reflection. */ | ||
@Test(expectedExceptions = java.lang.IllegalAccessException.class) | ||
public void test_javaLangReflectFieldSet_finalStaticInterfaceField() throws Throwable { | ||
Field finalInterfaceField = TestInterface.class.getDeclaredField("finalField"); | ||
finalInterfaceField.setAccessible(true); | ||
finalInterfaceField.set(null, "new"); | ||
} | ||
|
||
/* Check that Unsafe.staticFieldOffset supports regular classes. */ | ||
@Test | ||
public void test_jdkInternalMiscUnsafe_staticClassFieldOffset() throws Throwable { | ||
Field finalClassField = TestClass.class.getDeclaredField("finalField"); | ||
unsafe.staticFieldOffset(finalClassField); | ||
} | ||
|
||
/* Check that Unsafe.staticFieldBase supports regular classes. */ | ||
@Test | ||
public void test_jdkInternalMiscUnsafe_staticClassFieldBase() throws Throwable { | ||
Field finalClassField = TestClass.class.getDeclaredField("finalField"); | ||
unsafe.staticFieldBase(finalClassField); | ||
} | ||
|
||
/* Check that Unsafe.staticFieldOffset supports interfaces. */ | ||
@Test | ||
public void test_jdkInternalMiscUnsafe_staticInterfaceFieldOffset() throws Throwable { | ||
Field finalInterfaceField = TestInterface.class.getDeclaredField("finalField"); | ||
unsafe.staticFieldOffset(finalInterfaceField); | ||
} | ||
|
||
/* Check that Unsafe.staticFieldBase supports interfaces. */ | ||
@Test | ||
public void test_jdkInternalMiscUnsafe_staticInterfaceFieldBase() throws Throwable { | ||
Field finalInterfaceField = TestInterface.class.getDeclaredField("finalField"); | ||
unsafe.staticFieldBase(finalInterfaceField); | ||
} | ||
|
||
/* VarHandle.set is not supported for final field in regular classes. */ | ||
@Test(expectedExceptions = java.lang.UnsupportedOperationException.class) | ||
public void test_javaLangInvokeMethodHandles_unreflectVarHandle_class_static() throws Throwable { | ||
Field finalClassField = TestClass.class.getDeclaredField("finalField"); | ||
finalClassField.setAccessible(true); | ||
VarHandle finalClassFieldHandle = MethodHandles.lookup().unreflectVarHandle(finalClassField); | ||
finalClassFieldHandle.set("new"); | ||
} | ||
|
||
/* VarHandle.set is not supported for final field in interfaces. */ | ||
@Test(expectedExceptions = java.lang.UnsupportedOperationException.class) | ||
public void test_javaLangInvokeMethodHandles_unreflectVarHandle_interface_static() throws Throwable { | ||
Field finalInterfaceField = TestInterface.class.getDeclaredField("finalField"); | ||
finalInterfaceField.setAccessible(true); | ||
VarHandle finalInterfaceFieldHandle = MethodHandles.lookup().unreflectVarHandle(finalInterfaceField); | ||
finalInterfaceFieldHandle.set("new"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters