1 /*
2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.internal.misc;
27 
28 import java.security.AccessControlContext;
29 import java.security.AccessController;
30 import java.security.ProtectionDomain;
31 import java.security.PrivilegedAction;
32 import java.util.concurrent.atomic.AtomicInteger;
33 
34 /**
35  * A thread that has no permissions, is not a member of any user-defined
36  * ThreadGroup and supports the ability to erase ThreadLocals.
37  */
38 public final class InnocuousThread extends Thread {
39     private static final jdk.internal.misc.Unsafe UNSAFE;
40     private static final long THREAD_LOCALS;
41     private static final long INHERITABLE_THREAD_LOCALS;
42     private static final ThreadGroup INNOCUOUSTHREADGROUP;
43     private static final AccessControlContext ACC;
44     private static final long INHERITEDACCESSCONTROLCONTEXT;
45     private static final long CONTEXTCLASSLOADER;
46 
47     private static final AtomicInteger threadNumber = new AtomicInteger(1);
newName()48     private static String newName() {
49         return "InnocuousThread-" + threadNumber.getAndIncrement();
50     }
51 
52     /**
53      * Returns a new InnocuousThread with an auto-generated thread name
54      * and its context class loader is set to the system class loader.
55      */
newThread(Runnable target)56     public static Thread newThread(Runnable target) {
57         return newThread(newName(), target);
58     }
59 
60     /**
61      * Returns a new InnocuousThread with its context class loader
62      * set to the system class loader.
63      */
newThread(String name, Runnable target)64     public static Thread newThread(String name, Runnable target) {
65         return AccessController.doPrivileged(
66                 new PrivilegedAction<Thread>() {
67                     @Override
68                     public Thread run() {
69                         return new InnocuousThread(INNOCUOUSTHREADGROUP,
70                                                    target,
71                                                    name,
72                                                    ClassLoader.getSystemClassLoader());
73                     }
74                 });
75     }
76 
77     /**
78      * Returns a new InnocuousThread with an auto-generated thread name.
79      * Its context class loader is set to null.
80      */
81     public static Thread newSystemThread(Runnable target) {
82         return newSystemThread(newName(), target);
83     }
84 
85     /**
86      * Returns a new InnocuousThread with null context class loader.
87      */
88     public static Thread newSystemThread(String name, Runnable target) {
89         return AccessController.doPrivileged(
90                 new PrivilegedAction<Thread>() {
91                     @Override
92                     public Thread run() {
93                         return new InnocuousThread(INNOCUOUSTHREADGROUP,
94                                                    target, name, null);
95                     }
96                 });
97     }
98 
99     private InnocuousThread(ThreadGroup group, Runnable target, String name, ClassLoader tccl) {
100         super(group, target, name, 0L, false);
101         UNSAFE.putObjectRelease(this, INHERITEDACCESSCONTROLCONTEXT, ACC);
102         UNSAFE.putObjectRelease(this, CONTEXTCLASSLOADER, tccl);
103     }
104 
105     @Override
106     public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) {
107         // silently fail
108     }
109 
110     @Override
111     public void setContextClassLoader(ClassLoader cl) {
112         // Allow clearing of the TCCL to remove the reference to the system classloader.
113         if (cl == null)
114             super.setContextClassLoader(null);
115         else
116             throw new SecurityException("setContextClassLoader");
117     }
118 
119     /**
120      * Drops all thread locals (and inherited thread locals).
121      */
122     public final void eraseThreadLocals() {
123         UNSAFE.putObject(this, THREAD_LOCALS, null);
124         UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null);
125     }
126 
127     // ensure run method is run only once
128     private volatile boolean hasRun;
129 
130     @Override
131     public void run() {
132         if (Thread.currentThread() == this && !hasRun) {
133             hasRun = true;
134             super.run();
135         }
136     }
137 
138     // Use Unsafe to access Thread group and ThreadGroup parent fields
139     static {
140         try {
141             ACC = new AccessControlContext(new ProtectionDomain[] {
142                 new ProtectionDomain(null, null)
143             });
144 
145             // Find and use topmost ThreadGroup as parent of new group
146             UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
147             Class<?> tk = Thread.class;
148             Class<?> gk = ThreadGroup.class;
149 
150             THREAD_LOCALS = UNSAFE.objectFieldOffset(tk, "threadLocals");
151             INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset
152                     (tk, "inheritableThreadLocals");
153             INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset
154                 (tk, "inheritedAccessControlContext");
155             CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset
156                 (tk, "contextClassLoader");
157 
158             long tg = UNSAFE.objectFieldOffset(tk, "group");
159             long gp = UNSAFE.objectFieldOffset(gk, "parent");
160             ThreadGroup group = (ThreadGroup)
161                 UNSAFE.getObject(Thread.currentThread(), tg);
162 
163             while (group != null) {
164                 ThreadGroup parent = (ThreadGroup)UNSAFE.getObject(group, gp);
165                 if (parent == null)
166                     break;
167                 group = parent;
168             }
169             final ThreadGroup root = group;
170             INNOCUOUSTHREADGROUP = AccessController.doPrivileged(
171                 new PrivilegedAction<ThreadGroup>() {
172                     @Override
173                     public ThreadGroup run() {
174                         return new ThreadGroup(root, "InnocuousThreadGroup");
175                     }
176                 });
177         } catch (Exception e) {
178             throw new Error(e);
179         }
180     }
181 }
182