Skip to content

Commit

Permalink
Remove SecurityManager-related code; refactor resetThreadLocals
Browse files Browse the repository at this point in the history
  • Loading branch information
DougLea committed Nov 22, 2024
1 parent 93d4ad4 commit 5346c6a
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 125 deletions.
111 changes: 11 additions & 100 deletions src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@

import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.Permission;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -811,9 +805,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* initialization. Since it (or any other created pool) need
* never be used, we minimize initial construction overhead and
* footprint to the setup of about a dozen fields, although with
* some System property parsing and security processing that takes
* far longer than the actual construction when SecurityManagers
* are used or properties are set. The common pool is
* some System property parsing properties are set. The common pool is
* distinguished by having a null workerNamePrefix (which is an
* odd convention, but avoids the need to decode status in factory
* classes). It also has PRESET_SIZE config set if parallelism
Expand All @@ -839,13 +831,12 @@ public class ForkJoinPool extends AbstractExecutorService {
*
* As a more appropriate default in managed environments, unless
* overridden by system properties, we use workers of subclass
* InnocuousForkJoinWorkerThread when there is a SecurityManager
* present. These workers have no permissions set, do not belong
* to any user-defined ThreadGroup, and clear all ThreadLocals and
* reset the ContextClassLoader before (re)activating to execute
* top-level task. The associated mechanics may be JVM-dependent
* and must access particular Thread class fields to achieve this
* effect.
* InnocuousForkJoinWorkerThread for the commonPool. These
* workers do not belong to any user-defined ThreadGroup, and
* clear all ThreadLocals and reset the ContextClassLoader before
* (re)activating to execute top-level tasks. The associated
* mechanics may be JVM-dependent and must access particular
* Thread class fields to achieve this effect.
*
* InterruptibleTasks
* ====================
Expand Down Expand Up @@ -1097,21 +1088,6 @@ static long slotOffset(int index) {
return ((long)index << ASHIFT) + ABASE;
}

/**
* If there is a security manager, makes sure caller has
* permission to modify threads.
*/
@SuppressWarnings("removal")
private static void checkPermission() {
SecurityManager security; RuntimePermission perm;
if ((security = System.getSecurityManager()) != null) {
if ((perm = modifyThreadPermission) == null)
modifyThreadPermission = perm = // races OK
new RuntimePermission("modifyThread");
security.checkPermission(perm);
}
}

// Nested classes

/**
Expand Down Expand Up @@ -1147,64 +1123,9 @@ public static interface ForkJoinWorkerThreadFactory {
static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
boolean isCommon = (pool.workerNamePrefix == null);
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null && isCommon)
return newCommonWithACC(pool);
else
return newRegularWithACC(pool);
}

/*
* Create and use static AccessControlContexts only if there
* is a SecurityManager. (These can be removed if/when
* SecurityManagers are removed from platform.) The ACCs are
* immutable and equivalent even when racily initialized, so
* they don't require locking, although with the chance of
* needlessly duplicate construction.
*/
@SuppressWarnings("removal")
static volatile AccessControlContext regularACC, commonACC;

@SuppressWarnings("removal")
static ForkJoinWorkerThread newRegularWithACC(ForkJoinPool pool) {
AccessControlContext acc = regularACC;
if (acc == null) {
Permissions ps = new Permissions();
ps.add(new RuntimePermission("getClassLoader"));
ps.add(new RuntimePermission("setContextClassLoader"));
regularACC = acc =
new AccessControlContext(new ProtectionDomain[] {
new ProtectionDomain(null, ps) });
}
return AccessController.doPrivileged(
new PrivilegedAction<>() {
public ForkJoinWorkerThread run() {
return new ForkJoinWorkerThread(null, pool, true, false);
}}, acc);
}

@SuppressWarnings("removal")
static ForkJoinWorkerThread newCommonWithACC(ForkJoinPool pool) {
AccessControlContext acc = commonACC;
if (acc == null) {
Permissions ps = new Permissions();
ps.add(new RuntimePermission("getClassLoader"));
ps.add(new RuntimePermission("setContextClassLoader"));
ps.add(new RuntimePermission("modifyThread"));
ps.add(new RuntimePermission("enableContextClassLoaderOverride"));
ps.add(new RuntimePermission("modifyThreadGroup"));
commonACC = acc =
new AccessControlContext(new ProtectionDomain[] {
new ProtectionDomain(null, ps) });
}
return AccessController.doPrivileged(
new PrivilegedAction<>() {
public ForkJoinWorkerThread run() {
return new ForkJoinWorkerThread.
InnocuousForkJoinWorkerThread(pool);
}}, acc);
return ((pool.workerNamePrefix == null) ? // is commonPool
new ForkJoinWorkerThread.InnocuousForkJoinWorkerThread(pool) :
new ForkJoinWorkerThread(null, pool, true, false));
}
}

Expand Down Expand Up @@ -3024,7 +2945,6 @@ public ForkJoinPool(int parallelism,
Predicate<? super ForkJoinPool> saturate,
long keepAliveTime,
TimeUnit unit) {
checkPermission();
int p = parallelism;
if (p <= 0 || p > MAX_CAP || p > maximumPoolSize || keepAliveTime <= 0L)
throw new IllegalArgumentException();
Expand Down Expand Up @@ -3312,7 +3232,6 @@ public int setParallelism(int size) {
throw new IllegalArgumentException();
if ((config & PRESET_SIZE) != 0)
throw new UnsupportedOperationException("Cannot override System property");
checkPermission();
return getAndSetParallelism(size);
}

Expand Down Expand Up @@ -3710,7 +3629,6 @@ public String toString() {
* may not be rejected.
*/
public void shutdown() {
checkPermission();
if (workerNamePrefix != null) // not common pool
tryTerminate(false, true);
}
Expand All @@ -3730,7 +3648,6 @@ public void shutdown() {
* @return an empty list
*/
public List<Runnable> shutdownNow() {
checkPermission();
if (workerNamePrefix != null) // not common pool
tryTerminate(true, true);
return Collections.emptyList();
Expand Down Expand Up @@ -3837,7 +3754,6 @@ public boolean awaitQuiescence(long timeout, TimeUnit unit) {
@Override
public void close() {
if (workerNamePrefix != null) {
checkPermission();
CountDownLatch done = null;
boolean interrupted = false;
while ((tryTerminate(interrupted, true) & TERMINATED) == 0) {
Expand Down Expand Up @@ -4075,11 +3991,6 @@ public void endCompensatedBlock(ForkJoinPool pool, long post) {
});
defaultForkJoinWorkerThreadFactory =
new DefaultForkJoinWorkerThreadFactory();
@SuppressWarnings("removal")
ForkJoinPool p = common = (System.getSecurityManager() == null) ?
new ForkJoinPool((byte)0) :
AccessController.doPrivileged(new PrivilegedAction<>() {
public ForkJoinPool run() {
return new ForkJoinPool((byte)0); }});
common = new ForkJoinPool((byte)0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@

package java.util.concurrent;

import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
Expand Down Expand Up @@ -84,7 +80,7 @@ public class ForkJoinWorkerThread extends Thread {
super.setDaemon(true);
if (handler != null)
super.setUncaughtExceptionHandler(handler);
if (useSystemClassLoader)
if (useSystemClassLoader & !clearThreadLocals) // else done by Thread ctor
super.setContextClassLoader(ClassLoader.getSystemClassLoader());
}

Expand Down Expand Up @@ -228,18 +224,22 @@ static boolean hasKnownQueuedWork() {
}

/**
* Clears ThreadLocals, and if necessary resets ContextClassLoader
* Clears ThreadLocals
*/
final void resetThreadLocals() {
final void resetThreadLocals() {
if (U.getReference(this, THREADLOCALS) != null)
U.putReference(this, THREADLOCALS, null);
if (U.getReference(this, INHERITABLETHREADLOCALS) != null)
U.putReference(this, INHERITABLETHREADLOCALS, null);
if ((this instanceof InnocuousForkJoinWorkerThread) &&
((InnocuousForkJoinWorkerThread)this).needCCLReset())
super.setContextClassLoader(ClassLoader.getSystemClassLoader());
onThreadLocalReset();
}

/**
* Peforms any associated cleanup on resetThreadLocals
*/
void onThreadLocalReset() {
}

private static final Unsafe U = Unsafe.getUnsafe();
private static final long THREADLOCALS
= U.objectFieldOffset(Thread.class, "threadLocals");
Expand All @@ -248,10 +248,10 @@ final void resetThreadLocals() {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();

/**
* A worker thread that has no permissions, is not a member of any
* user-defined ThreadGroup, uses the system class loader as
* thread context class loader, and clears all ThreadLocals after
* running each top-level task.
* A worker thread that is not a member of any user-defined
* ThreadGroup, uses the system class loader as thread context
* class loader, and clears all ThreadLocals after running each
* top-level task.
*/
static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
/** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
Expand All @@ -264,21 +264,20 @@ static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
@Override // to silently fail
public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }

@Override // paranoically
@SuppressWarnings("removal")
@Override // to record changes
public void setContextClassLoader(ClassLoader cl) {
if (System.getSecurityManager() != null &&
cl != null && ClassLoader.getSystemClassLoader() != cl)
throw new SecurityException("setContextClassLoader");
resetCCL = true;
super.setContextClassLoader(cl);
if (ClassLoader.getSystemClassLoader() != cl) {
resetCCL = true;
super.setContextClassLoader(cl);
}
}

final boolean needCCLReset() { // get and clear
boolean needReset;
if (needReset = resetCCL)
@Override // to re-establish CCL if necessary
final void onThreadLocalReset() {
if (resetCCL) {
resetCCL = false;
return needReset;
super.setContextClassLoader(ClassLoader.getSystemClassLoader());
}
}

static ThreadGroup createGroup() {
Expand Down

0 comments on commit 5346c6a

Please sign in to comment.