FULL PRODUCT VERSION :
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
Changes in the applet security classes made the code which worked in all previous version of JRE broken. See the code below and exception.
Detailed description:
When applet creates new Thread and the group is null, it asks a current security manager (System.getSecurityManager()) what to do:
[1.6.0_26-b03] [Applet2SecurityManager]: sun.plugin2.applet.Applet2ThreadGroup
[1.7.0-b147] [AWTAppletSecurityManager]: sun.plugin2.applet.Applet2ThreadGroup
So they both return comparable values and method ThreadGroup#checkAccess is called.
Then they do almost the same things until following point is reached:
[1.6.0_26-b03] [Applet2SecurityManager]:
protected boolean inThreadGroup(ThreadGroup g) {
if (currentAppletClassLoader() == null)
return false;
else
return getThreadGroup().parentOf(g);
}
[1.7.0-b147] [SecurityManagerHelper]:
static boolean inThreadGroup(SecurityManager securitymanager, ThreadGroup threadgroup, ClassLoader classloader, Class aclass[], Field field, Field field1) {
if (currentAppletClassLoader(classloader, aclass, field, field1) == null) {
return false;
} else {
return securitymanager.getThreadGroup().parentOf(threadgroup);
}
}
In both situations methods currentAppletClassLoader return not null value.
The difference there is that Applet2SecurityManager calls own method getThreadGroup(), and we get the same group which we got at the beginning in the Thread constructor (System.getSecurityManager().getThreadGroup()), method parentOf returns true, and creation of new thread is allowed.
Instead of this SecurityManagerHelper calls method getThreadGroup() of passed parameter, and this param is not current security manager(System.getSecurityManager()), it���s value of field AWTAppletSecurityManager - awtSM and it���s instance of class AWTSecurityManager.
AWTSecurityManager uses default behavior of SecurityManager#getThreadGroup and returns the thread group of the current thread.
Any custom created thread group in applet can���t be parent for System.getSecurityManager().getThreadGroup() - Applet2ThreadGroup.
And an applet has no permission to modify thread group ("java.lang.RuntimePermission" "modifyThreadGroup") by default. So the check fails and exception is thrown, new thread is not created.
REGRESSION. Last worked in version 6u25
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "Thread-12" java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at sun.plugin2.applet.SecurityManagerHelper.checkAccessHelper(Unknown Source)
at sun.plugin2.applet.AWTAppletSecurityManager.checkAccess(Unknown Source)
at java.lang.ThreadGroup.checkAccess(Unknown Source)
at java.lang.Thread.init(Unknown Source)
at java.lang.Thread.<init>(Unknown Source)
at TestApplet$1.run(TestApplet.java:44)
at java.lang.Thread.run(Unknown Source)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.*;
public class TestApplet extends JApplet {
public void init() {
new Thread(new ThreadGroup(Thread.currentThread().getThreadGroup().getParent(), "TestAppletGroup"), new Runnable() {
public void run() {
new Thread(new Runnable() {
public void run() {
System.out.println("test");
}
}).start();
}
}).start();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The simple workaround is not use custom thread groups in applet or if you started using them then you should use it everywhere.
But it���s not always possible to control new thread creation, for example following code doesn���t work too:
public class TestApplet extends JApplet {
public void init() {
new Thread(new ThreadGroup("TestAppletGroup"), new Runnable() {
public void run() {
SwingWorker worker = new SwingWorker() {
protected String doInBackground() throws Exception {
System.out.println("test");
return null;
}
};
worker.execute();
}
}).start();
}
}