diff options
author | jfrijters <jfrijters> | 2011-07-30 13:57:21 +0400 |
---|---|---|
committer | jfrijters <jfrijters> | 2011-07-30 13:57:21 +0400 |
commit | 442851c1258ab6c4a67ee338d9a3b7cbc0b29484 (patch) | |
tree | fa1703c897876554229e4cad739c5f99a912d5ca /openjdk | |
parent | a0d1c505ac3c99ea52d63cc8c32fa5d0813bddab (diff) |
Switched to a different way to force Thread.[get|set]ContextClassLoader methods to be JIT compiled eagerly to avod RuntimeHelpers.PrepareMethod() which requires full trust.
Added back in the (unused) OpenJDK override checking code.
Diffstat (limited to 'openjdk')
-rw-r--r-- | openjdk/java/lang/Thread.java | 142 | ||||
-rw-r--r-- | openjdk/map.xml | 10 |
2 files changed, 144 insertions, 8 deletions
diff --git a/openjdk/java/lang/Thread.java b/openjdk/java/lang/Thread.java index 5fdffea7..306d33f9 100644 --- a/openjdk/java/lang/Thread.java +++ b/openjdk/java/lang/Thread.java @@ -25,11 +25,16 @@ package java.lang; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; import sun.nio.ch.Interruptible; import sun.security.util.SecurityConstants; @@ -133,9 +138,15 @@ import sun.security.util.SecurityConstants; public class Thread implements Runnable { // [IKVM] - private static native void prepareCCL(); static { - prepareCCL(); + // force the set/getContextClassLoader methods to be JIT compiled, because isCCLOverridden(Thread) depends on it + // (we don't want to use RuntimeHelpers.PrepareMethod() because it requires full trust) + Thread dummy = new Thread((Void)null); + dummy.getContextClassLoader(); + dummy.setContextClassLoader(ClassLoader.DUMMY); + } + private Thread(Void _) { + // body replaced in map.xml } final class Cleanup { private final Thread thread; @@ -1752,6 +1763,10 @@ class Thread implements Runnable { * @since 1.2 */ public void setContextClassLoader(ClassLoader cl) { + if (cl == ClassLoader.DUMMY) { + // we're being called by Thread.<clinit> to force this method to be JIT compiled + return; + } SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("setContextClassLoader")); @@ -1928,14 +1943,75 @@ class Thread implements Runnable { private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION = new RuntimePermission("enableContextClassLoaderOverride"); + /** cache of subclass security audit results */ + /* Replace with ConcurrentReferenceHashMap when/if it appears in a future + * release */ + private static class Caches { + /** cache of subclass security audit results */ + static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = + new ConcurrentHashMap<>(); + + /** queue for WeakReferences to audited subclasses */ + static final ReferenceQueue<Class<?>> subclassAuditsQueue = + new ReferenceQueue<>(); + } + /** * Verifies that this (possibly subclass) instance can be constructed * without violating security constraints: the subclass must not override * security-sensitive non-final methods, or else the * "enableContextClassLoaderOverride" RuntimePermission is checked. */ + @cli.System.Runtime.CompilerServices.MethodImplAttribute.Annotation(value = cli.System.Runtime.CompilerServices.MethodImplOptions.__Enum.NoInlining) private static native boolean isCCLOverridden(Thread thread); // [IKVM] implemented in map.xml + private static boolean isCCLOverridden(Class cl) { + if (cl == Thread.class) + return false; + + processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); + WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); + Boolean result = Caches.subclassAudits.get(key); + if (result == null) { + result = Boolean.valueOf(auditSubclass(cl)); + Caches.subclassAudits.putIfAbsent(key, result); + } + + return result.booleanValue(); + } + + /** + * Performs reflective checks on given subclass to verify that it doesn't + * override security-sensitive non-final methods. Returns true if the + * subclass overrides any of the methods, false otherwise. + */ + private static boolean auditSubclass(final Class subcl) { + Boolean result = AccessController.doPrivileged( + new PrivilegedAction<Boolean>() { + public Boolean run() { + for (Class cl = subcl; + cl != Thread.class; + cl = cl.getSuperclass()) + { + try { + cl.getDeclaredMethod("getContextClassLoader", new Class[0]); + return Boolean.TRUE; + } catch (NoSuchMethodException ex) { + } + try { + Class[] params = {ClassLoader.class}; + cl.getDeclaredMethod("setContextClassLoader", params); + return Boolean.TRUE; + } catch (NoSuchMethodException ex) { + } + } + return Boolean.FALSE; + } + } + ); + return result.booleanValue(); + } + private static StackTraceElement[][] dumpThreads(Thread[] threads) { StackTraceElement[][] stacks = new StackTraceElement[threads.length][]; for (int i = 0; i < threads.length; i++) { @@ -2270,6 +2346,68 @@ class Thread implements Runnable { getUncaughtExceptionHandler().uncaughtException(this, e); } + /** + * Removes from the specified map any keys that have been enqueued + * on the specified reference queue. + */ + static void processQueue(ReferenceQueue<Class<?>> queue, + ConcurrentMap<? extends + WeakReference<Class<?>>, ?> map) + { + Reference<? extends Class<?>> ref; + while((ref = queue.poll()) != null) { + map.remove(ref); + } + } + + /** + * Weak key for Class objects. + **/ + static class WeakClassKey extends WeakReference<Class<?>> { + /** + * saved value of the referent's identity hash code, to maintain + * a consistent hash code after the referent has been cleared + */ + private final int hash; + + /** + * Create a new WeakClassKey to the given object, registered + * with a queue. + */ + WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { + super(cl, refQueue); + hash = System.identityHashCode(cl); + } + + /** + * Returns the identity hash code of the original referent. + */ + @Override + public int hashCode() { + return hash; + } + + /** + * Returns true if the given object is this identical + * WeakClassKey instance, or, if this object's referent has not + * been cleared, if the given object is another WeakClassKey + * instance with the identical non-null referent as this one. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + + if (obj instanceof WeakClassKey) { + Object referent = get(); + return (referent != null) && + (referent == ((WeakClassKey) obj).get()); + } else { + return false; + } + } + } + /* Some private helper methods */ private synchronized void setPriority0(int newPriority) { cli.System.Threading.Thread nativeThread = this.nativeThread; diff --git a/openjdk/map.xml b/openjdk/map.xml index e5920387..534272f4 100644 --- a/openjdk/map.xml +++ b/openjdk/map.xml @@ -1436,15 +1436,13 @@ <class name="java.lang.Thread"> <field name="parkLock" sig="Ljava.lang.Object;" modifiers="" /> <field name="parkState" sig="I" modifiers="" /> - <method name="prepareCCL" sig="()V"> + <constructor sig="(Ljava.lang.Void;)V"> <body> - <ldtoken class="java.lang.Thread" method="getContextClassLoader" sig="()Ljava.lang.ClassLoader;" /> - <call class="cli.System.Runtime.CompilerServices.RuntimeHelpers" name="PrepareMethod" sig="(Lcli.System.RuntimeMethodHandle;)V" /> - <ldtoken class="java.lang.Thread" method="setContextClassLoader" sig="(Ljava.lang.ClassLoader;)V" /> - <call class="cli.System.Runtime.CompilerServices.RuntimeHelpers" name="PrepareMethod" sig="(Lcli.System.RuntimeMethodHandle;)V" /> + <ldarg_0 /> + <call class="java.lang.Object" name="<init>" sig="()V" /> <ret /> </body> - </method> + </constructor> <method name="isCCLOverridden" sig="(Ljava.lang.Thread;)Z"> <body> <ldftn class="java.lang.Thread" name="getContextClassLoader" sig="()Ljava.lang.ClassLoader;" /> |