Created: 10/7/96 TimN

Updated: 10/9/96 PatrickB

Return to the Java Hall of Shame

Race Condition in Javac Generated Code

There is a race condition in the code emitted by the java compiler that could allow a synchronized region to be left without releasing the monitor lock. The language spec says that monitors should be released if a synchronized block is left through an exception. However, the byte-codes generated by javac to ensure this contain a race condition. Consider this code:
        public void foo(Object o) {
           synchronized(this) {
results in the following byte-code:
       Method void foo(java.lang.Object)
          0 aload_0
          1 astore_2
          2 aload_2
          3 monitorenter
          4 aload_1
          5 invokevirtual #3 <Method java.lang.Object.toString()Ljava/lang/String;>
          8 pop
          9 aload_2
         10 monitorexit
         11 return
         12 aload_2
         13 monitorexit
         14 athrow
       Exception table:
        from   to  target type
          4     9    12   any
What does the method do when passed a null object? The method will grab the monitor lock and then throw a null pointer exception at line 5. Since 5 is in the exception range of 4 to 9 the program will continue executing at the exception handler at line 12. Consider what happens when an asynchronous exception is thrown (by the java.lang.Thread.stop() method) before or immediately after executing the aload_2 instruction at line 12. The VM checks if line 12 is in the exception range - it is not. The VM then considers this exception to be handled at a higher level and the handler at a higher level is invoked. The monitor lock was never released.

According to the VM spec it is legal (but not mandatory) to defer handling of asynchronous exceptions until a change in control flow. Any implementation that does this will not have this race condition since the asynchronous exception raised at line 12 will not be detected until the athrow after the monitor is exited. The race condition can be eliminated by having a second exception range that points back to the same exception handler: from line 12 to 13 pointing back to line 12, in this case.

Return to the Java Hall of Shame