Details
-
Bug
-
Resolution: Won't Do
-
Major
-
2.3.4.Final
Description
My name is Yu Lin. I'm a Ph.D. student in the CS department at
UIUC. I'm currently doing research on mining Java concurrent library
misusages. I found some misusages of ConcurrentHashMap in RestEasy
2.3.4, which may result in potential atomicity violation bugs.
The code below is a snapshot of the code in file
providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/XmlJAXBContextFinder.java
from line 64 to 71
L64 CacheKey key = new CacheKey(classes);
L65 JAXBContext ctx = collectionCache.get(key);
L66 if (ctx != null) return ctx;
L68 ctx = createContext(paraAnnotations, classes);
L69 collectionCache.put(key, ctx);
L71 return ctx;
In the code above, an atomicity violation may occur between line 67
and 69. Suppose a thread T1 executes line 65 and finds out the
concurrent hashmap "collectionCache" does not contain the key
"key". Before it gets to execute line 69, another thread T2 puts a
pair <key, v> in the concurrent hashmap "collectionCache". Now thread
T1 resumes execution and it will overwrite the value written by thread
T2. Thus, the code no longer preserves the "put-if-absent"
semantics. We can fix this by using "putIfAbsent" method at line 69.
I also found other 4 places in the code that have this problem:
XmlJAXBContextFinder.java line 82; JsonJAXBContextFinder.java lines
111 and 119; SimpleServerCache.java line 83. I attach a patch that can
fix it.
Meanwhile, there are also misusages on "putIfAbsent" operation. For
example, here is the code in
security/resteasy-oauth/src/main/java/org/jboss/resteasy/auth/oauth/OAuthMemoryProvider.java
from line 140 to 146
L140 OAuthConsumer consumer = consumers.get(consumerKey);
L141 if (consumer == null)
L144 consumer = new OAuthConsumer(consumerKey, "therealfrog", displayName, connectURI);
L145 consumers.putIfAbsent(consumerKey, consumer);
L146 return consumer;
Suppose thread T1 executes line 140 and finds out the concurrent
hashmap "consumers" does not contain the key "consumerKey". Before it
gets to execute line 145, another thread T2 puts a pair <consumerKey,
v> into the concurrent hashmap "consumers". Now thread T1 resumes
execution but it won't put the "consumer" into the map because T2
already put a value with key "consumerKey". Thus, the "consumer"
returned by T1 isn't in the map actually.
I also find 5 other places in the code that misuse the "putIfAbsent":
JAXBCache.java line 71; JsonJAXBContextFinder.java line 149;
ResourceLocator.java line 135; SimpleSecurityDomain.java line 26.