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()]);