提交 f0abcf49 编写于 作者: D dholmes

7103570: AtomicIntegerFieldUpdater does not work when SecurityManager is installed

Summary: Perform class.getField inside a doPrivileged block
Reviewed-by: chegar, psandoz
上级 06f5881b
...@@ -35,7 +35,11 @@ ...@@ -35,7 +35,11 @@
package java.util.concurrent.atomic; package java.util.concurrent.atomic;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.lang.reflect.*; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
/** /**
* A reflection-based utility that enables atomic updates to * A reflection-based utility that enables atomic updates to
...@@ -67,7 +71,9 @@ public abstract class AtomicIntegerFieldUpdater<T> { ...@@ -67,7 +71,9 @@ public abstract class AtomicIntegerFieldUpdater<T> {
* @throws IllegalArgumentException if the field is not a * @throws IllegalArgumentException if the field is not a
* volatile integer type * volatile integer type
* @throws RuntimeException with a nested reflection-based * @throws RuntimeException with a nested reflection-based
* exception if the class does not hold field or is the wrong type * exception if the class does not hold field or is the wrong type,
* or the field is inaccessible to the caller according to Java language
* access control
*/ */
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName); return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
...@@ -267,17 +273,29 @@ public abstract class AtomicIntegerFieldUpdater<T> { ...@@ -267,17 +273,29 @@ public abstract class AtomicIntegerFieldUpdater<T> {
private final Class<T> tclass; private final Class<T> tclass;
private final Class<?> cclass; private final Class<?> cclass;
AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) { AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) {
Field field = null; Field field = null;
Class<?> caller = null; Class<?> caller = null;
int modifiers = 0; int modifiers = 0;
try { try {
field = tclass.getDeclaredField(fieldName); field = AccessController.doPrivileged(
new PrivilegedExceptionAction<Field>() {
public Field run() throws NoSuchFieldException {
return tclass.getDeclaredField(fieldName);
}
});
caller = sun.reflect.Reflection.getCallerClass(3); caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers(); modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess( sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers); caller, tclass, null, modifiers);
ClassLoader cl = tclass.getClassLoader();
ClassLoader ccl = caller.getClassLoader();
if ((ccl != null) && (ccl != cl) &&
((cl == null) || !isAncestor(cl, ccl))) {
sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
}
} catch (PrivilegedActionException pae) {
throw new RuntimeException(pae.getException());
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
...@@ -295,6 +313,22 @@ public abstract class AtomicIntegerFieldUpdater<T> { ...@@ -295,6 +313,22 @@ public abstract class AtomicIntegerFieldUpdater<T> {
offset = unsafe.objectFieldOffset(field); offset = unsafe.objectFieldOffset(field);
} }
/**
* Returns true if the second classloader can be found in the first
* classloader's delegation chain.
* Equivalent to the inaccessible: first.isAncestor(second).
*/
private static boolean isAncestor(ClassLoader first, ClassLoader second) {
ClassLoader acl = first;
do {
acl = acl.getParent();
if (second == acl) {
return true;
}
} while (acl != null);
return false;
}
private void fullCheck(T obj) { private void fullCheck(T obj) {
if (!tclass.isInstance(obj)) if (!tclass.isInstance(obj))
throw new ClassCastException(); throw new ClassCastException();
......
...@@ -35,7 +35,11 @@ ...@@ -35,7 +35,11 @@
package java.util.concurrent.atomic; package java.util.concurrent.atomic;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.lang.reflect.*; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
/** /**
* A reflection-based utility that enables atomic updates to * A reflection-based utility that enables atomic updates to
...@@ -67,7 +71,9 @@ public abstract class AtomicLongFieldUpdater<T> { ...@@ -67,7 +71,9 @@ public abstract class AtomicLongFieldUpdater<T> {
* @throws IllegalArgumentException if the field is not a * @throws IllegalArgumentException if the field is not a
* volatile long type. * volatile long type.
* @throws RuntimeException with a nested reflection-based * @throws RuntimeException with a nested reflection-based
* exception if the class does not hold field or is the wrong type. * exception if the class does not hold field or is the wrong type,
* or the field is inaccessible to the caller according to Java language
* access control
*/ */
public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
if (AtomicLong.VM_SUPPORTS_LONG_CAS) if (AtomicLong.VM_SUPPORTS_LONG_CAS)
...@@ -267,17 +273,29 @@ public abstract class AtomicLongFieldUpdater<T> { ...@@ -267,17 +273,29 @@ public abstract class AtomicLongFieldUpdater<T> {
private final Class<T> tclass; private final Class<T> tclass;
private final Class<?> cclass; private final Class<?> cclass;
CASUpdater(Class<T> tclass, String fieldName) { CASUpdater(final Class<T> tclass, final String fieldName) {
Field field = null; Field field = null;
Class<?> caller = null; Class<?> caller = null;
int modifiers = 0; int modifiers = 0;
try { try {
field = tclass.getDeclaredField(fieldName); field = AccessController.doPrivileged(
new PrivilegedExceptionAction<Field>() {
public Field run() throws NoSuchFieldException {
return tclass.getDeclaredField(fieldName);
}
});
caller = sun.reflect.Reflection.getCallerClass(3); caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers(); modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess( sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers); caller, tclass, null, modifiers);
ClassLoader cl = tclass.getClassLoader();
ClassLoader ccl = caller.getClassLoader();
if ((ccl != null) && (ccl != cl) &&
((cl == null) || !isAncestor(cl, ccl))) {
sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
}
} catch (PrivilegedActionException pae) {
throw new RuntimeException(pae.getException());
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
...@@ -350,17 +368,29 @@ public abstract class AtomicLongFieldUpdater<T> { ...@@ -350,17 +368,29 @@ public abstract class AtomicLongFieldUpdater<T> {
private final Class<T> tclass; private final Class<T> tclass;
private final Class<?> cclass; private final Class<?> cclass;
LockedUpdater(Class<T> tclass, String fieldName) { LockedUpdater(final Class<T> tclass, final String fieldName) {
Field field = null; Field field = null;
Class<?> caller = null; Class<?> caller = null;
int modifiers = 0; int modifiers = 0;
try { try {
field = tclass.getDeclaredField(fieldName); field = AccessController.doPrivileged(
new PrivilegedExceptionAction<Field>() {
public Field run() throws NoSuchFieldException {
return tclass.getDeclaredField(fieldName);
}
});
caller = sun.reflect.Reflection.getCallerClass(3); caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers(); modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess( sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers); caller, tclass, null, modifiers);
ClassLoader cl = tclass.getClassLoader();
ClassLoader ccl = caller.getClassLoader();
if ((ccl != null) && (ccl != cl) &&
((cl == null) || !isAncestor(cl, ccl))) {
sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
}
} catch (PrivilegedActionException pae) {
throw new RuntimeException(pae.getException());
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
...@@ -433,4 +463,20 @@ public abstract class AtomicLongFieldUpdater<T> { ...@@ -433,4 +463,20 @@ public abstract class AtomicLongFieldUpdater<T> {
); );
} }
} }
/**
* Returns true if the second classloader can be found in the first
* classloader's delegation chain.
* Equivalent to the inaccessible: first.isAncestor(second).
*/
private static boolean isAncestor(ClassLoader first, ClassLoader second) {
ClassLoader acl = first;
do {
acl = acl.getParent();
if (second == acl) {
return true;
}
} while (acl != null);
return false;
}
} }
...@@ -35,7 +35,11 @@ ...@@ -35,7 +35,11 @@
package java.util.concurrent.atomic; package java.util.concurrent.atomic;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.lang.reflect.*; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
/** /**
* A reflection-based utility that enables atomic updates to * A reflection-based utility that enables atomic updates to
...@@ -86,7 +90,9 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { ...@@ -86,7 +90,9 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
* @return the updater * @return the updater
* @throws IllegalArgumentException if the field is not a volatile reference type. * @throws IllegalArgumentException if the field is not a volatile reference type.
* @throws RuntimeException with a nested reflection-based * @throws RuntimeException with a nested reflection-based
* exception if the class does not hold field or is the wrong type. * exception if the class does not hold field or is the wrong type,
* or the field is inaccessible to the caller according to Java language
* access control
*/ */
public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) { public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass, return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
...@@ -197,21 +203,33 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { ...@@ -197,21 +203,33 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
* screenings fail. * screenings fail.
*/ */
AtomicReferenceFieldUpdaterImpl(Class<T> tclass, AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
Class<V> vclass, Class<V> vclass,
String fieldName) { final String fieldName) {
Field field = null; Field field = null;
Class<?> fieldClass = null; Class<?> fieldClass = null;
Class<?> caller = null; Class<?> caller = null;
int modifiers = 0; int modifiers = 0;
try { try {
field = tclass.getDeclaredField(fieldName); field = AccessController.doPrivileged(
new PrivilegedExceptionAction<Field>() {
public Field run() throws NoSuchFieldException {
return tclass.getDeclaredField(fieldName);
}
});
caller = sun.reflect.Reflection.getCallerClass(3); caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers(); modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess( sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers); caller, tclass, null, modifiers);
ClassLoader cl = tclass.getClassLoader();
ClassLoader ccl = caller.getClassLoader();
if ((ccl != null) && (ccl != cl) &&
((cl == null) || !isAncestor(cl, ccl))) {
sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
}
fieldClass = field.getType(); fieldClass = field.getType();
} catch (PrivilegedActionException pae) {
throw new RuntimeException(pae.getException());
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
...@@ -232,6 +250,22 @@ public abstract class AtomicReferenceFieldUpdater<T, V> { ...@@ -232,6 +250,22 @@ public abstract class AtomicReferenceFieldUpdater<T, V> {
offset = unsafe.objectFieldOffset(field); offset = unsafe.objectFieldOffset(field);
} }
/**
* Returns true if the second classloader can be found in the first
* classloader's delegation chain.
* Equivalent to the inaccessible: first.isAncestor(second).
*/
private static boolean isAncestor(ClassLoader first, ClassLoader second) {
ClassLoader acl = first;
do {
acl = acl.getParent();
if (second == acl) {
return true;
}
} while (acl != null);
return false;
}
void targetCheck(T obj) { void targetCheck(T obj) {
if (!tclass.isInstance(obj)) if (!tclass.isInstance(obj))
throw new ClassCastException(); throw new ClassCastException();
......
/*
* Copyright (c) 2012, 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 7103570
* @author David Holmes
* @run main/othervm AtomicUpdaters
* @run main/othervm AtomicUpdaters UseSM
* @summary Checks the (in)ability to create field updaters for differently
* accessible fields in different locations with/without a security
* manager
*/
import java.util.concurrent.atomic.*;
import java.lang.reflect.*;
import java.security.AccessControlException;
public class AtomicUpdaters {
enum TYPE { INT, LONG, REF }
static class Config {
final Class<?> clazz;
final String field;
final String access;
final boolean reflectOk;
final boolean updaterOk;
final String desc;
final TYPE type;
Config(Class<?> clazz, String field, String access,
boolean reflectOk, boolean updaterOk, String desc, TYPE type) {
this.clazz = clazz;
this.field = field;
this.access = access;
this.reflectOk = reflectOk;
this.updaterOk = updaterOk;
this.desc = desc;
this.type =type;
}
public String toString() {
return desc + ": " + access + " " + clazz.getName() + "." + field;
}
}
static Config[] tests;
static void initTests(boolean hasSM) {
tests = new Config[] {
new Config(AtomicUpdaters.class, "pub_int", "public", true, true, "public int field of current class", TYPE.INT),
new Config(AtomicUpdaters.class, "priv_int", "private", true, true, "private int field of current class", TYPE.INT),
new Config(AtomicUpdaters.class, "pub_long", "public", true, true, "public long field of current class", TYPE.LONG),
new Config(AtomicUpdaters.class, "priv_long", "private", true, true, "private long field of current class", TYPE.LONG),
new Config(AtomicUpdaters.class, "pub_ref", "public", true, true, "public ref field of current class", TYPE.REF),
new Config(AtomicUpdaters.class, "priv_ref", "private", true, true, "private ref field of current class", TYPE.REF),
// Would like to test a public volatile in a class in another
// package - but of course there aren't any
new Config(java.util.concurrent.atomic.AtomicInteger.class, "value", "private", hasSM ? false : true, false, "private int field of class in different package", TYPE.INT),
new Config(java.util.concurrent.atomic.AtomicLong.class, "value", "private", hasSM ? false : true, false, "private long field of class in different package", TYPE.LONG),
new Config(java.util.concurrent.atomic.AtomicReference.class, "value", "private", hasSM ? false : true, false, "private reference field of class in different package", TYPE.REF),
};
}
public volatile int pub_int;
private volatile int priv_int;
public volatile long pub_long;
private volatile long priv_long;
public volatile Object pub_ref;
private volatile Object priv_ref;
// This should be set dynamically at runtime using a System property, but
// ironically we get a SecurityException if we try to do that with a
// SecurityManager installed
static boolean verbose;
public static void main(String[] args) throws Throwable {
boolean hasSM = false;
for (String arg : args) {
if ("-v".equals(arg)) {
verbose = true;
}
else if ("UseSM".equals(arg)) {
SecurityManager m = System.getSecurityManager();
if (m != null)
throw new RuntimeException("No security manager should initially be installed");
System.setSecurityManager(new java.lang.SecurityManager());
hasSM = true;
}
else {
throw new IllegalArgumentException("Unexpected option: " + arg);
}
}
initTests(hasSM);
int failures = 0;
System.out.printf("Testing with%s a SecurityManager present\n", hasSM ? "" : "out");
for (Config c : tests) {
System.out.println("Testing: " + c);
Error reflectionFailure = null;
Error updaterFailure = null;
Class<?> clazz = c.clazz;
// See if we can reflectively access the field
System.out.println(" - testing getDeclaredField");
try {
Field f = clazz.getDeclaredField(c.field);
if (!c.reflectOk)
reflectionFailure = new Error("Unexpected reflective access: " + c);
}
catch (AccessControlException e) {
if (c.reflectOk)
reflectionFailure = new Error("Unexpected reflective access failure: " + c, e);
else if (verbose) {
System.out.println("Got expected reflection exception: " + e);
e.printStackTrace(System.out);
}
}
if (reflectionFailure != null) {
reflectionFailure.printStackTrace(System.out);
}
// see if we can create an atomic updater for the field
Object u = null;
try {
switch (c.type) {
case INT:
System.out.println(" - testing AtomicIntegerFieldUpdater");
u = AtomicIntegerFieldUpdater.newUpdater(clazz, c.field);
break;
case LONG:
System.out.println(" - testing AtomicLongFieldUpdater");
u = AtomicLongFieldUpdater.newUpdater(clazz, c.field);
break;
case REF:
System.out.println(" - testing AtomicReferenceFieldUpdater");
u = AtomicReferenceFieldUpdater.newUpdater(clazz, Object.class, c.field);
break;
}
if (!c.updaterOk)
updaterFailure = new Error("Unexpected updater access: " + c);
}
catch (Exception e) {
if (c.updaterOk)
updaterFailure = new Error("Unexpected updater access failure: " + c, e);
else if (verbose) {
System.out.println("Got expected updater exception: " + e);
e.printStackTrace(System.out);
}
}
if (updaterFailure != null) {
updaterFailure.printStackTrace(System.out);
}
if (updaterFailure != null || reflectionFailure != null) {
failures++;
}
}
if (failures > 0) {
throw new Error("Some tests failed - see previous stacktraces");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册