JDK-6857855 : 6.0u14 new plugin executing javascipt can hang IE
  • Type: Bug
  • Component: deploy
  • Sub-Component: plugin
  • Affected Version: 6u14
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2009-07-07
  • Updated: 2013-01-08
  • Resolved: 2009-10-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
6u18 b04Fixed 7Fixed
Related Reports
Relates :  
A javascript invocation is hanging IE6.x.  This used to work in 5.0_x JVMs.

Attached to the bug report is the jstack traces.

Using windbg,
0:000> ~0kb 
ChildEBP RetAddr  Args to Child              
0013500c 7c90df4a 7c809590 00000002 00135038 ntdll!KiFastSystemCallRet
00135010 7c809590 00000002 00135038 00000001 ntdll!ZwWaitForMultipleObjects+0xc
001350ac 7e4195f9 00000002 001350d4 00000000 kernel32!WaitForMultipleObjectsEx+0x12c
00135108 7752ebd6 00000001 00135150 000003e8 user32!RealMsgWaitForMultipleObjectsEx+0x13e
00135130 7752ecfd 00135150 000003e8 00135160 ole32!CCliModalLoop::BlockFn+0x80
00135158 77525fc1 ffffffff 00135250 00135188 ole32!ModalLoop+0x5b
00135168 77601efe 00197a28 00135250 00000000 ole32!SwitchSTA+0x21
00135188 7760108a 00135250 089cc9ac 001352ac ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0xd1
00135268 7752edaa 089cc9ac 0013537c 0013536c ole32!CRpcChannelBuffer::SendReceive2+0xc8
00135284 7752ed53 0013537c 0013536c 089cc9ac ole32!CCliModalLoop::SendReceive+0x1e
001352f0 7752cdb2 089cc9ac 0013537c 0013536c ole32!CAptRpcChnl::SendReceive+0x6f
00135344 77ef4db5 089cc9ac 0013537c 0013536c ole32!CCtxComChnl::SendReceive+0x113

0:000> dd (poi (089cc9ac  + 18) +8) 
00197a30  0000009c 00000dd0 17a59799 0b21bbb9

The COM call is blocked by pid 0x9c (156d) and thread id 0xdd0.  The stack trace of 0xdd0 is this thread.
"Thread-3" prio=6 tid=0x05ff8400 nid=0xdd0 runnable [0x0d50b000]
   java.lang.Thread.State: RUNNABLE
        at sun.plugin2.main.server.WindowsHelper.runMessagePump0(Native Method)
        at sun.plugin2.main.server.WindowsHelper.runMessagePump(Unknown Source)
        at sun.plugin2.main.server.IExplorerPlugin.runMessagePump(Unknown Source)
        at sun.plugin2.main.server.IExplorerPlugin.runMessagePump(Unknown Source)
        at sun.plugin2.main.server.IExplorerPlugin.access$400(Unknown Source)
        at sun.plugin2.main.server.IExplorerPlugin$1.waitForSignal(Unknown Source)
        at sun.plugin2.main.server.ResultHandler.waitForResult(Unknown Source)
        at sun.plugin2.main.server.AbstractPlugin.doJavaObjectOp(Unknown Source)
        at sun.plugin2.main.server.IExplorerPlugin.doJavaObjectOp(Unknown Source)
        at sun.plugin2.main.server.AbstractPlugin.javaObjectInvoke(Unknown Source)

SUGGESTED FIX Applet's manager is stored in a thread local storage for all threads spawned from the applet's lifecycle thread (e.g. threads created from init(), start(), stop(), etc.) and the liveconnect worker thread for that applet. Plugin2Manager.getCurrentManager() called on those threads should get the correct Plugin2Manager. The only problem left is the awt event queue because this thread is shared among all applets in the AppContext. If EventQueue.invoke*() or SwingUtilities.invoke*() are used, Plugin2Manager.getCurrentManager() won't get precise answer running on the event queue thread.

EVALUATION A simple test case for this issue can be found in Attachments section. To reproduce, just open Test1.html with IE (whether from a local disk or a web server) and press the button two times. The problem happens with Plugin2 only. A Java thread dump collected using jstack indicates that the "Applet 2 LiveConnect Worker Thread" in the client VM (java.exe) is stuck at sun.plugin2.main.client.MessagePassingExecutionContext.getProxyList(), and the browser VM (iexplore.exe) is inside runMessagePump(). Testing with an instrumented JDK confirmed this. The "Applet 2 LiveConnect Worker Thread" issues an asynchronous GET_PROXY request to some other thread. This request goes to a pipe, and the issuing thread waits for a response, but it never gets any notification. Probably it happens because the targeted thread is already waiting for some other event, and doesn't read the message from the pipe. There is also some periodic message exchange going through the same pipe. It happens every 10 seconds, even after IE hangs. Thanks to Hao Dong's help, the root cause is found. The problem is that Plugin2 could not get the correct Applet2Manager for the running applet. When the applet in the second window tries to get a proxy, Plugin2 gets a wrong Applet2Manager (it got the manager for the applet in the first window) and used a wrong ExecutionContext to get the proxy list. The GetProxyMessage has the AppletID of the first applet. On the browser side, the message is routed to the main thread of the window where the first applet resides in. That main thread is blocked doing a JavaScript call and no message pump is running. Thus the browser deadlocked. The message should be routed to the main thread of the second window on which a message pump is running. There is actually a good FIXME in Plugin2Manager.java about this semantic problem. /** Fetches the Plugin2Manager instance associated with the current AppContext. <P> NOTE: (FIXME) this method may return imprecise answers, in particular in the case where the old "class loader caching" mechanism is being used and we have multiple applets all running in the same AppContext. This definitely isn't the execution model we want to support long term going forward; it causes all sorts of encapsulation and termination problems. In the meantime, callers of this method should implicitly assume that it might return a "random" Plugin2Manager if multiple applets are running in the same AppContext. If more precise answers are required, such as for Java-to-JavaScript calls, different mechanisms should be used. */ public static Plugin2Manager getCurrentManager() { Well, the root is the class loader caching that Plugin2 want to get rid of very much. One possible workaround may be to disable classloading sharing in applet's param <param name="classloader_cache" value="false">. We checked it with the customer, and unfortunately it doesn't work in their application. It causes their applet to be blank and hung. Their application relies on the fact that the applets should be loaded by the same classloader. Another workaround is to close a pop up applet window and open it again, but the customer is reluctant to use it.