Hi, Since nobody complained about my context class loader fix, I'm checking it in. I also made the generation of anonymous thread names thread safe and corrected the security check in getContextClassLoader.
Regards, Jeroen 2006-05-19 Jeroen Frijters <[EMAIL PROTECTED]> * java/lang/Thread.java (contextClassLoaderIsSystemClassLoader): New field. (Thread(ThreadGroup,Runnable)): Call createAnonymousThreadName. (Thread(VMThread,String,int,boolean)): Call createAnonymousThreadName and set contextClassLoaderIsSystemClassLoader. (Thread(ThreadGroup,Runnable,String,long)): Set contextClassLoaderIsSystemClassLoader. (createAnonymousThreadName): New method. (getContextClassLoader): Check contextClassLoaderIsSystemClassLoader and fixed security check. (setContextClassLoader): Clear contextClassLoaderIsSystemClassLoader.
Index: java/lang/Thread.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/lang/Thread.java,v retrieving revision 1.22 diff -u -r1.22 Thread.java --- java/lang/Thread.java 9 May 2006 14:42:13 -0000 1.22 +++ java/lang/Thread.java 19 May 2006 09:33:13 -0000 @@ -38,6 +38,7 @@ package java.lang; +import gnu.classpath.VMStackWalker; import gnu.java.util.WeakIdentityHashMap; import java.security.Permission; import java.util.Map; @@ -131,7 +132,8 @@ /** The context classloader for this Thread. */ private ClassLoader contextClassLoader; - + private boolean contextClassLoaderIsSystemClassLoader; + /** This thread's ID. */ private final long threadId; @@ -248,7 +250,7 @@ */ public Thread(ThreadGroup group, Runnable target) { - this(group, target, "Thread-" + ++numAnonymousThreadsCreated, 0); + this(group, target, createAnonymousThreadName(), 0); } /** @@ -364,6 +366,8 @@ priority = current.priority; daemon = current.daemon; contextClassLoader = current.contextClassLoader; + contextClassLoaderIsSystemClassLoader = + current.contextClassLoaderIsSystemClassLoader; group.addThread(this); InheritableThreadLocal.newChildThread(this); @@ -373,6 +377,9 @@ * Used by the VM to create thread objects for threads started outside * of Java. Note: caller is responsible for adding the thread to * a group and InheritableThreadLocal. + * Note: This constructor should not call any methods that could result + * in a call to Thread.currentThread(), because that makes life harder + * for the VM. * * @param vmThread the native thread * @param name the thread name or null to use the default naming scheme @@ -384,16 +391,32 @@ this.vmThread = vmThread; this.runnable = null; if (name == null) - name = "Thread-" + ++numAnonymousThreadsCreated; + name = createAnonymousThreadName(); this.name = name; this.priority = priority; this.daemon = daemon; - this.contextClassLoader = ClassLoader.getSystemClassLoader(); + // By default the context class loader is the system class loader, + // we set a flag to signal this because we don't want to call + // ClassLoader.getSystemClassLoader() at this point, because on + // VMs that lazily create the system class loader that might result + // in running user code (when a custom system class loader is specified) + // and that user code could call Thread.currentThread(). + // ClassLoader.getSystemClassLoader() can also return null, if the system + // is currently in the process of constructing the system class loader + // (and, as above, the constructiong sequence calls Thread.currenThread()). + contextClassLoaderIsSystemClassLoader = true; synchronized (Thread.class) { this.threadId = nextThreadId++; } + } + /** + * Generate a name for an anonymous thread. + */ + private static synchronized String createAnonymousThreadName() + { + return "Thread-" + ++numAnonymousThreadsCreated; } /** @@ -746,12 +769,18 @@ */ public synchronized ClassLoader getContextClassLoader() { - // Bypass System.getSecurityManager, for bootstrap efficiency. + ClassLoader loader = contextClassLoaderIsSystemClassLoader ? + ClassLoader.getSystemClassLoader() : contextClassLoader; + // Check if we may get the classloader SecurityManager sm = SecurityManager.current; - if (sm != null) - // XXX Don't check this if the caller's class loader is an ancestor. - sm.checkPermission(new RuntimePermission("getClassLoader")); - return contextClassLoader; + if (loader != null && sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && !cl.isAncestorOf(loader)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return loader; } /** @@ -772,6 +801,7 @@ if (sm != null) sm.checkPermission(new RuntimePermission("setContextClassLoader")); this.contextClassLoader = classloader; + contextClassLoaderIsSystemClassLoader = false; } /**