code review request: 7118809: rcache deadlock

Weijun Wang weijun.wang at oracle.com
Tue Jan 10 05:41:16 UTC 2012


Hi Valerie

Please review my fix:

    http://cr.openjdk.java.net/~weijun/7118809/webrev.00/

Basically, CacheTable.put() operates on ReplayCache inside it, and 
ReplayCache.put() operates on CacheTable containing it, and both methods 
are synchronized and using thread-safe Hashtable.

My solution is to move the "table.remove(principal)" line in 
ReplayCache.put() outside the method. I search thru JDK and 
CacheTable.put() is the only place the method is called:

     public synchronized void put(String principal, AuthTime time, long 
currTime) {
         ReplayCache rc = super.get(principal);
         if (rc == null) {
             if (DEBUG) {
                 System.out.println("replay cache for " + principal + " 
is null.");
             }
             rc = new ReplayCache(principal, this);
             rc.put(time, currTime);
             super.put(principal, rc);
         }
         else {
             rc.put(time, currTime);
             // re-insert the entry, since rc.put could have removed the 
entry
             super.put(principal, rc);
             if (DEBUG) {
                 System.out.println("replay cache found.");
             }
         }
     }

Curiously, you can see after each call, the ReplayCache object is added 
back into the CacheTable. Therefore, the remove action is useless.

Maybe the most correct way is to remove a ReplayCache from a CacheTable 
if it's empty, but that re-insert line was added in a security fix some 
years ago which I cannot decipher.

So my fix simply removes the "remove" call in ReplayCache.

No regression test, hard to reproduce failure.

Thanks
Max

-------- Original Message --------
*Change Request ID*: 7118809
*Synopsis*: rcache deadlock

=== *Description* 
============================================================
A DESCRIPTION OF THE PROBLEM :
The program as below:
--------------------------------------------------
import sun.security.krb5.internal.rcache.*;
import sun.security.krb5.internal.*;
import java.util.*;

public class KTest2 {
   public static void main(String [] a) throws Exception{
     final CacheTable ct = new CacheTable();
     final long time = System.currentTimeMillis();
     ct.put("TheOnlyOne", new AuthTime( time - 
Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW * 1000L, 0), time);
     final ReplayCache rc = (ReplayCache) ct.get("TheOnlyOne");
     new Thread() {
       public void run() {
         rc.put(new AuthTime( time - Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW * 
1000L, 0), time + 300*1000);
       }
     }.start();
     ct.put("TheOnlyOne", new AuthTime( time - 
Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW * 1000L, 0), time);
   }
}
--------------------------------------------------
When compiles as in: javac KTest2.java
and executed as in: java KTest2
can deadlock the hosting JVM as is reproduced by the stack-trace dump, 
below:
-------------------------------------------------
Found one Java-level deadlock:
=============================
"Thread-0":
   waiting to lock monitor 0x0921d720 (object 0xa5621b80, a 
sun.security.krb5.internal.rcache.CacheTable),
   which is held by "main"
"main":
   waiting to lock monitor 0x0921caa0 (object 0xa5622fb8, a 
sun.security.krb5.internal.rcache.ReplayCache),
   which is held by "Thread-0"

Java stack information for the threads listed above:
===================================================
"Thread-0":
	at java.util.Hashtable.remove(Hashtable.java:435)
	- waiting to lock <0xa5621b80> (a 
sun.security.krb5.internal.rcache.CacheTable)
	at sun.security.krb5.internal.rcache.ReplayCache.put(ReplayCache.java:123)
	- locked <0xa5622fb8> (a sun.security.krb5.internal.rcache.ReplayCache)
	at KTest2$1.run(KTest2.java:13)
"main":
	at sun.security.krb5.internal.rcache.ReplayCache.put(ReplayCache.java:62)
	- waiting to lock <0xa5622fb8> (a 
sun.security.krb5.internal.rcache.ReplayCache)
	at sun.security.krb5.internal.rcache.CacheTable.put(CacheTable.java:59)
	- locked <0xa5621b80> (a sun.security.krb5.internal.rcache.CacheTable)
	at KTest2.main(KTest2.java:16)

Found 1 deadlock.
...




More information about the security-dev mailing list