Skip to content

Commit

Permalink
Merge pull request #3310 from JasonFengJ9/mhlookup
Browse files Browse the repository at this point in the history
Improve MethodHandles.lookup() field accesses
  • Loading branch information
DanHeidinga authored Oct 17, 2018
2 parents 8c6d5e2 + 071114c commit 84966ab
Show file tree
Hide file tree
Showing 8 changed files with 517 additions and 2 deletions.
13 changes: 11 additions & 2 deletions runtime/jcl/common/java_dyn_methodhandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,9 @@ Java_java_lang_invoke_PrimitiveHandle_lookupField(JNIEnv *env, jobject handle, j
{
J9UTF8 *signatureUTF8 = NULL;
char signatureUTF8Buffer[256];
J9Class *j9LookupClass; /* J9Class for java.lang.Class lookupClass */
J9Class *j9LookupClass = NULL; /* J9Class for java.lang.Class lookupClass */
J9Class *definingClass = NULL; /* Returned by calls to find field */
UDATA field;
UDATA field = 0;
jclass result = NULL;
UDATA romField = 0;
J9VMThread *vmThread = (J9VMThread *) env;
Expand Down Expand Up @@ -590,6 +590,15 @@ Java_java_lang_invoke_PrimitiveHandle_lookupField(JNIEnv *env, jobject handle, j
setClassLoadingConstraintLinkageError(vmThread, definingClass, signatureUTF8);
goto _cleanup;
}
if (NULL != accessClass) {
J9Class *j9AccessClass = J9VM_J9CLASS_FROM_JCLASS(vmThread, accessClass);
if ((j9AccessClass->classLoader != j9LookupClass->classLoader)
&& !accessCheckFieldSignature(vmThread, j9AccessClass, romField, J9VMJAVALANGINVOKEMETHODHANDLE_TYPE(vmThread, J9_JNI_UNWRAP_REFERENCE(handle)), signatureUTF8)
) {
setClassLoadingConstraintLinkageError(vmThread, j9AccessClass, signatureUTF8);
goto _cleanup;
}
}

J9VMJAVALANGINVOKEPRIMITIVEHANDLE_SET_VMSLOT(vmThread, J9_JNI_UNWRAP_REFERENCE(handle), field);
J9VMJAVALANGINVOKEPRIMITIVEHANDLE_SET_RAWMODIFIERS(vmThread, J9_JNI_UNWRAP_REFERENCE(handle), ((J9ROMFieldShape*) romField)->modifiers);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.openj9.test.java.security;

/*******************************************************************************
* Copyright (c) 2018, 2018 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 java.lang.invoke.MethodHandles;
import org.testng.Assert;

// This class is loaded by ClassLoaderOne.
public class ChildMHLookupField extends Parent {
private final ClassLoader clOne = ChildMHLookupField.class.getClassLoader();
private final Object objDummyOne = clOne.loadClass("org.openj9.test.java.security.Dummy").newInstance();
private final Class<?> clzDummyOne = objDummyOne.getClass();
private final ClassLoader clTwo = Parent.class.getClassLoader();
private final Object objDummyTwo = clTwo.loadClass("org.openj9.test.java.security.Dummy").newInstance();
private final Class<?> clzDummyTwo = objDummyTwo.getClass();
private final MethodHandles.Lookup mhLookup = MethodHandles.lookup();

public ChildMHLookupField() throws Exception {
// Verify that the classes are loaded by appropriate class loaders
Assert.assertEquals(clOne.getClass(), ClassLoaderOne.class);
Assert.assertEquals(clzDummyOne.getClassLoader().getClass(), ClassLoaderOne.class);

Assert.assertEquals(clTwo.getClass(), ClassLoaderTwo.class);
Assert.assertEquals(clzDummyTwo.getClassLoader().getClass(), ClassLoaderTwo.class);
}

// Loading constraints are violated when reference and type classes (instance field getter) are loaded by different class loaders.
public void instanceFieldGetter1() throws Throwable {
mhLookup.findGetter(Parent.class, "instanceField", clzDummyOne);
}

// Loading constraints are violated when reference/type(instance field getter) and access classes are loaded by different class loaders.
public void instanceFieldGetter2() throws Throwable {
mhLookup.findGetter(Parent.class, "instanceField", clzDummyTwo);
}

// Loading constraints are violated when reference and type classes (static field getter) are loaded by different class loaders.
public void staticFieldGetter1() throws Throwable {
mhLookup.findStaticGetter(Parent.class, "staticField", clzDummyOne);
}

// Loading constraints are violated when reference/type(static field getter) and access classes are loaded by different class loaders.
public void staticFieldGetter2() throws Throwable {
mhLookup.findStaticGetter(Parent.class, "staticField", clzDummyTwo);
}

// Loading constraints are violated when reference and type classes (instance field setter) are loaded by different class loaders.
public void instanceFieldSetter1() throws Throwable {
mhLookup.findSetter(Parent.class, "instanceField", clzDummyOne);
}

// Loading constraints are violated when reference/type(instance field setter) and access classes are loaded by different class loaders.
public void instanceFieldSetter2() throws Throwable {
mhLookup.findSetter(Parent.class, "instanceField", clzDummyTwo);
}

// Loading constraints are violated when reference and type classes (static field setter) are loaded by different class loaders.
public void staticFieldSetter1() throws Throwable {
mhLookup.findStaticSetter(Parent.class, "staticField", clzDummyOne);
}

// Loading constraints are violated when reference/type(static field setter) and access classes are loaded by different class loaders.
public void staticFieldSetter2() throws Throwable {
mhLookup.findStaticSetter(Parent.class, "staticField", clzDummyTwo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.openj9.test.java.security;

/*******************************************************************************
* Copyright (c) 2018, 2018 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 java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;

// This classloader loads classes ChildMHLookupField and Dummy.
public class ClassLoaderOne extends ClassLoader {
private ClassLoader clTwo;
private final Set<String> names = new HashSet<>();

public ClassLoaderOne(String... names) {
for (String name : names) {
this.names.add(name);
}
}

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.equals("org.openj9.test.java.security.Parent")) {
if (clTwo == null) {
clTwo = new ClassLoaderTwo(this, "org.openj9.test.java.security.Dummy", "org.openj9.test.java.security.Parent");
}
Class<?> parent = clTwo.loadClass("org.openj9.test.java.security.Parent");
return parent;
}
if (!names.contains(name)) {
return super.loadClass(name, resolve);
}
Class<?> result = findLoadedClass(name);
if (result == null) {
String filename = name.replace('.', '/') + ".class";
try (InputStream data = getResourceAsStream(filename)) {
if (data == null) {
throw new ClassNotFoundException();
}
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
int b;
do {
b = data.read();
if (b >= 0) {
buffer.write(b);
}
} while (b >= 0);
byte[] bytes = buffer.toByteArray();
result = defineClass(name, bytes, 0, bytes.length);
}
} catch (IOException e) {
throw new ClassNotFoundException("Error reading" + filename, e);
}
}
if (resolve) {
resolveClass(result);
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.openj9.test.java.security;

/*******************************************************************************
* Copyright (c) 2018, 2018 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 java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;

// This classloader loads classes Parent and Dummy.
public class ClassLoaderTwo extends ClassLoader {
private final Set<String> names = new HashSet<>();
private ClassLoader clOne;
public ClassLoaderTwo(ClassLoader cl, String... names) {
clOne = cl;
for (String name : names) {
this.names.add(name);
}
}

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.equals("org.openj9.test.java.security.ChildMHLookupField")) {
return clOne.loadClass(name);
}
if (!names.contains(name)) {
return super.loadClass(name, resolve);
}
Class<?> result = findLoadedClass(name);
if (result == null) {
if (name.equals("org.openj9.test.java.security.Parent")) {
loadClass("org.openj9.test.java.security.Dummy", resolve);
}
String filename = name.replace('.', '/') + ".class";
try (InputStream data = getResourceAsStream(filename)) {
if (data == null) {
throw new ClassNotFoundException();
}
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
int b;
do {
b = data.read();
if (b >= 0) {
buffer.write(b);
}
} while (b >= 0);
byte[] bytes = buffer.toByteArray();
result = defineClass(name, bytes, 0, bytes.length);
}
} catch (IOException e) {
throw new ClassNotFoundException("Error reading" + filename, e);
}
}
if (resolve) {
resolveClass(result);
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.openj9.test.java.security;

/*******************************************************************************
* Copyright (c) 2018, 2018 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
*******************************************************************************/

// This class will be loaded by ClassLoaderOne and ClassLoaderTwo.
public class Dummy {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.openj9.test.java.security;

/*******************************************************************************
* Copyright (c) 2018, 2018 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
*******************************************************************************/

//This class will be loaded by ClassLoaderTwo.
public class Parent {
public Dummy instanceField;
public static Dummy staticField = new Dummy();
public Parent() {
instanceField = new Dummy();
}
}
Loading

0 comments on commit 84966ab

Please sign in to comment.