Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2011-07-30 13:57:21 +0400
committerjfrijters <jfrijters>2011-07-30 13:57:21 +0400
commit442851c1258ab6c4a67ee338d9a3b7cbc0b29484 (patch)
treefa1703c897876554229e4cad739c5f99a912d5ca /openjdk
parenta0d1c505ac3c99ea52d63cc8c32fa5d0813bddab (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.java142
-rw-r--r--openjdk/map.xml10
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="&lt;init&gt;" 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;" />