Index: java/security/AccessController.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/security/AccessController.java,v
retrieving revision 1.8
diff -u -b -B -w -r1.8 AccessController.java
--- java/security/AccessController.java 3 Jun 2004 09:16:58 -0000 1.8
+++ java/security/AccessController.java 21 Aug 2004 22:05:22 -0000
@@ -47,11 +47,6 @@
* And provides a getContext()
method which gives the access
* control context of the current thread that can be used for checking
* permissions at a later time and/or in another thread.
- *
- * XXX - Mostly a stub implementation at the moment. Needs native support
- * from the VM to function correctly. XXX - Do not forget to think about
- * how to handle java.lang.reflect.Method.invoke()
on the
- * doPrivileged()
methods.
*
* @author Mark Wielaard (address@hidden)
* @since 1.2
@@ -95,8 +90,16 @@
*/
public static Object doPrivileged(PrivilegedAction action)
{
+ VMAccessController.pushContext(null);
+ try
+ {
return action.run();
}
+ finally
+ {
+ VMAccessController.popContext();
+ }
+ }
/**
* Calls the run()
method of the given action with as
@@ -115,14 +118,14 @@
public static Object doPrivileged(PrivilegedAction action,
AccessControlContext context)
{
- VMAccessController.pushContext (context, action.getClass());
+ VMAccessController.pushContext(context);
try
{
return action.run();
}
finally
{
- VMAccessController.popContext (action.getClass());
+ VMAccessController.popContext();
}
}
@@ -145,7 +148,7 @@
public static Object doPrivileged(PrivilegedExceptionAction action)
throws PrivilegedActionException
{
-
+ VMAccessController.pushContext(null);
try
{
return action.run();
@@ -154,6 +157,10 @@
{
throw new PrivilegedActionException(e);
}
+ finally
+ {
+ VMAccessController.popContext();
+ }
}
/**
@@ -178,8 +185,7 @@
AccessControlContext context)
throws PrivilegedActionException
{
- VMAccessController.pushContext (context, action.getClass());
-
+ VMAccessController.pushContext(context);
try
{
return action.run();
@@ -190,7 +196,7 @@
}
finally
{
- VMAccessController.popContext (action.getClass());
+ VMAccessController.popContext();
}
}
Index: vm/reference/java/security/VMAccessController.java
===================================================================
RCS file: /cvsroot/classpath/classpath/vm/reference/java/security/VMAccessController.java,v
retrieving revision 1.2
diff -u -b -B -w -r1.2 VMAccessController.java
--- vm/reference/java/security/VMAccessController.java 4 Jul 2004 18:32:32 -0000 1.2
+++ vm/reference/java/security/VMAccessController.java 21 Aug 2004 22:05:22 -0000
@@ -52,15 +52,24 @@
// -------------------------------------------------------------------------
/**
- * A mapping between pairs (thread, classname) to access
- * control contexts. The thread and classname are the thread
- * and classname current as of the last call to doPrivileged with
- * an AccessControlContext argument.
+ * This is a per-thread stack of AccessControlContext objects (which can
+ * be null) for each call to AccessController.doPrivileged in each thread's
+ * call stack. We use this to remember which context object corresponds to
+ * which call.
*/
- private static final Map contexts = Collections.synchronizedMap(new HashMap());
+ private static final ThreadLocal contexts = new ThreadLocal();
+ /**
+ * This is a Boolean that, if set, tells getContext that it has already
+ * been called once, allowing us to handle recursive permission checks
+ * caused by methods getContext calls.
+ */
private static final ThreadLocal inGetContext = new ThreadLocal();
+ /**
+ * And we return this all-permissive context to ensure that privileged
+ * methods called from getContext succeed.
+ */
private final static AccessControlContext DEFAULT_CONTEXT;
static
{
@@ -97,15 +106,18 @@
* pushed from one thread will not be available to another.
*
* @param acc The access control context.
- * @param clazz The class that implements address@hidden PrivilegedAction}.
*/
- static void pushContext (AccessControlContext acc, Class clazz)
+ static void pushContext (AccessControlContext acc)
+ {
+ if (DEBUG)
+ debug("pushing " + acc);
+ LinkedList stack = (LinkedList) contexts.get();
+ if (stack == null)
{
- ArrayList pair = new ArrayList (2);
- pair.add (Thread.currentThread());
- pair.add (clazz);
- if (DEBUG) debug ("pushing " + pair);
- contexts.put (pair, acc);
+ stack = new LinkedList();
+ contexts.set(stack);
+ }
+ stack.addFirst(acc);
}
/**
@@ -113,16 +125,21 @@
* This method is used by address@hidden AccessController} when exiting from a
* call to address@hidden
* AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}.
- *
- * @param clazz The class that implements address@hidden PrivilegedAction}.
*/
- static void popContext (Class clazz)
+ static void popContext()
{
- ArrayList pair = new ArrayList (2);
- pair.add (Thread.currentThread());
- pair.add (clazz);
- if (DEBUG) debug ("popping " + pair);
- contexts.remove (pair);
+ if (DEBUG)
+ debug("popping context");
+
+ // Stack should never be null, nor should it be empty, if this method
+ // and its counterpart has been called properly.
+ LinkedList stack = (LinkedList) contexts.get();
+ if (stack != null)
+ {
+ stack.removeFirst();
+ if (stack.isEmpty())
+ contexts.set(null);
+ }
}
/**
@@ -143,28 +160,31 @@
Boolean inCall = (Boolean) inGetContext.get();
if (inCall != null && inCall.booleanValue())
{
- if (DEBUG) debug ("already in getContext");
+ if (DEBUG)
+ debug("already in getContext");
return DEFAULT_CONTEXT;
}
+ inGetContext.set(Boolean.TRUE);
+
Object[][] stack = getStack();
Class[] classes = (Class[]) stack[0];
String[] methods = (String[]) stack[1];
- inGetContext.set (Boolean.TRUE);
-
- if (DEBUG) debug (">>> got trace of length " + classes.length);
+ if (DEBUG)
+ debug(">>> got trace of length " + classes.length);
HashSet domains = new HashSet();
HashSet seenDomains = new HashSet();
AccessControlContext context = null;
+ int privileged = 0;
// We walk down the stack, adding each ProtectionDomain for each
// class in the call stack. If we reach a call to doPrivileged,
// we don't add any more stack frames. We skip the first three stack
// frames, since they comprise the calls to getStack, getContext,
// and AccessController.getContext.
- for (int i = 3; i < classes.length; i++)
+ for (int i = 3; i < classes.length && privileged < 2; i++)
{
Class clazz = classes[i];
String method = methods[i];
@@ -175,17 +195,20 @@
debug (">>> loader = " + clazz.getClassLoader());
}
+ // If the previous frame was a call to doPrivileged, then this is
+ // the last frame we look at.
+ if (privileged == 1)
+ privileged = 2;
+
if (clazz.equals (AccessController.class)
&& method.equals ("doPrivileged"))
{
// If there was a call to doPrivileged with a supplied context,
// return that context.
- List pair = new ArrayList(2);
- pair.add (Thread.currentThread());
- pair.add (classes[i-1]);
- if (contexts.containsKey (pair))
- context = (AccessControlContext) contexts.get (pair);
- break;
+ LinkedList l = (LinkedList) contexts.get();
+ if (l != null)
+ context = (AccessControlContext) l.getFirst();
+ privileged = 1;
}
ProtectionDomain domain = clazz.getProtectionDomain();
@@ -202,7 +225,8 @@
domain.getPermissions()));
}
- if (DEBUG) debug ("created domains: " + domains);
+ if (DEBUG)
+ debug("created domains: " + domains);
ProtectionDomain[] result = (ProtectionDomain[])
domains.toArray (new ProtectionDomain[domains.size()]);