Race Condition Inside the Microsoft JVM
Here’s a story about an unreported Internet Explorer Java bug. Anyone that creates applets is affected:
About two weeks ago, I got a message from FutureSource’s excellent Q. A. team informing me that an applet sometimes turns up blank on Windows NT 4. Just a gray rectangle. But as soon as the browser is resized, the applet repaints correctly. This was never happening for the first instance of the applet, but only when new windows containing applets were spawned or the window containing the applet was refreshed.
After installing NT4+SP4+IE5+JVM3802 on one of the boxes, I managed to reproduce the problem. This was good news. If you can reproduce it you can fix it.
By adding some traces and a timer to the applet, I found out that this was not a paint problem, nor a validation problem as I initially thought. Instead, my applet had a size of (0, 0) inside the Applet.init method, and that size stayed until the browser window was first resized.
Next, I overloaded the applet’s setSize() and setBounds() methods to trace the parameters they receive and then call the super’s implementation. What I found out is that on the runs when everything works, applet’s setBounds() is called just before a call to the init() method. On the runs when the applet failed to show, the setBounds() method was never called.
This was obviously a problem in IE’s JVM, not in my code. But I needed to fix it anyway because it would piss off the customers.
After unsuccessfully throwing a few wild guesses at the problem, I decided to take the time and solve it properly. I downloaded the NMI Java Decompiler and decompiled the classes that make up the com.ms.applet package. Now that I had the source code finding the problem was easy:
There is a race condition inside Microsoft’s code that happens on applet startup.
There are two threads working together on applet startup. One is the event queue thread, which controls the applet and its parent, BrowserAppletFrame, and another which calls the init, start, stop and destroy methods and which is represented by the AppletPanel runnable. Both of these classes are in the com.ms.applet package.
The event queue thread is responsible for processing an event that sets a Dimension object named objectSize to the desired size. The AppletPanel thread is responsible for using that object to set the applet’s size. If the event queue thread is faster, then all is well. But if the AppletPanel thread is faster, it will use the initial value of objectSize which is (0, 0) before the event queue thread has a chance to set it to the real size. The user will see only an ugly gray box.
The workaround is to add a component listener to the parent in the applet’s init method and then to set the applet size to the parent’s size when the parent’s size changes the first time.
This bug is not in the MS Knowledge Base. I tried to report it but found no way to do so on Microsoft’s website.
