8139884: Use privileged blocks when working with class loaders

Reviewed-by: hannesw, mhaupt, sundar
This commit is contained in:
Attila Szegedi 2015-10-19 22:36:03 +02:00
parent cabd8f2f06
commit 3d0ec10abd
4 changed files with 49 additions and 12 deletions

View File

@ -150,15 +150,15 @@ abstract class ClassMap<T> {
final T newV = computeValue(clazz);
assert newV != null;
final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
final Boolean canReferenceDirectly = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
public Boolean run() {
return Guards.canReferenceDirectly(classLoader, clazz.getClassLoader());
}
}, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT);
// If allowed to strongly reference, put it in the fast map
if(Guards.canReferenceDirectly(classLoader, clazzLoader)) {
if(canReferenceDirectly) {
final T oldV = map.putIfAbsent(clazz, newV);
return oldV != null ? oldV : newV;
}

View File

@ -85,6 +85,9 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.List;
import jdk.internal.dynalink.linker.LinkerServices;
@ -97,6 +100,8 @@ import jdk.internal.dynalink.support.TypeUtilities;
* JLS.
*/
final class ClassString {
private static final Permission GET_CLASS_LOADER_PERMISSION = new RuntimePermission("getClassLoader");
/**
* An anonymous inner class used solely to represent the "type" of null values for method applicability checking.
*/
@ -143,12 +148,17 @@ final class ClassString {
}
boolean isVisibleFrom(final ClassLoader classLoader) {
for(int i = 0; i < classes.length; ++i) {
if(!Guards.canReferenceDirectly(classLoader, classes[i].getClassLoader())) {
return false;
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
for(final Class<?> clazz: classes) {
if(!Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) {
return false;
}
}
return true;
}
}
return true;
}, null, GET_CLASS_LOADER_PERMISSION);
}
List<MethodHandle> getMaximallySpecifics(final List<MethodHandle> methods, final LinkerServices linkerServices, final boolean varArg) {

View File

@ -85,6 +85,11 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
@ -218,10 +223,27 @@ class OverloadedDynamicMethod extends DynamicMethod {
for(final SingleDynamicMethod method: invokables) {
methodHandles.add(method.getTarget(callSiteDescriptor));
}
return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
return new OverloadedMethod(methodHandles, this, getCallSiteClassLoader(callSiteDescriptor), callSiteType, linkerServices).getInvoker();
}
}
}
private static final AccessControlContext GET_CALL_SITE_CLASS_LOADER_CONTEXT;
static {
final Permissions perms = new Permissions();
perms.add(new RuntimePermission("getClassLoader"));
perms.add(CallSiteDescriptor.GET_LOOKUP_PERMISSION);
GET_CALL_SITE_CLASS_LOADER_CONTEXT = new AccessControlContext(
new ProtectionDomain[] { new ProtectionDomain(null, perms) });
}
private static ClassLoader getCallSiteClassLoader(final CallSiteDescriptor callSiteDescriptor) {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return callSiteDescriptor.getLookup().lookupClass().getClassLoader();
}
}, GET_CALL_SITE_CLASS_LOADER_CONTEXT);
}
@Override

View File

@ -104,15 +104,20 @@ import jdk.internal.dynalink.support.TypeUtilities;
class OverloadedMethod {
private final Map<ClassString, MethodHandle> argTypesToMethods = new ConcurrentHashMap<>();
private final OverloadedDynamicMethod parent;
private final ClassLoader callSiteClassLoader;
private final MethodType callSiteType;
private final MethodHandle invoker;
private final LinkerServices linkerServices;
private final ArrayList<MethodHandle> fixArgMethods;
private final ArrayList<MethodHandle> varArgMethods;
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
OverloadedMethod(final List<MethodHandle> methodHandles,
final OverloadedDynamicMethod parent,
final ClassLoader callSiteClassLoader,
final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
this.callSiteClassLoader = callSiteClassLoader;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
@ -179,7 +184,7 @@ class OverloadedMethod {
}
// Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader
// memory leaks.
if(classString.isVisibleFrom(parent.getClassLoader())) {
if(classString.isVisibleFrom(callSiteClassLoader)) {
argTypesToMethods.put(classString, method);
}
}