]> source.dussan.org Git - javassist.git/commitdiff
Fix a race condition in CtClassType#getClassFile3 363/head
authormichalkurka <michalk@h2o.ai>
Wed, 17 Mar 2021 17:12:21 +0000 (13:12 -0400)
committermichalkurka <michalk@h2o.ai>
Wed, 17 Mar 2021 17:12:21 +0000 (13:12 -0400)
javassist fails to find a class when concurrently running process
compresses the class (converts classfile to raw bytes)

the idea of the fix is to make sure to only update rawClassfile and classfile
under lock in getClassFile3, all other places that modify classfile are
already synchronized

when reading the object state, we need to read under lock both classfile and
rawClassFile otherwise we might get an inconsistent state

src/main/javassist/CtClassType.java

index ae196c4a31ca13f442c40cc89de67e002432c362..959ec302073b67a844b57902101aa3bbbc8c5d5e 100644 (file)
@@ -179,6 +179,7 @@ class CtClassType extends CtClass {
     }
 
     public ClassFile getClassFile3(boolean doCompress) {
+        // quick path - no locking
         ClassFile cfile = classfile;
         if (cfile != null)
             return cfile;
@@ -186,17 +187,29 @@ class CtClassType extends CtClass {
         if (doCompress)
             classPool.compress();
 
-        if (rawClassfile != null) {
+        byte[] rcfile;
+        synchronized (this) {
+            // repeat under lock to make sure we get a consistent result (classfile might have been set by another thread)
+            cfile = classfile;
+            if (cfile != null)
+                return cfile;
+
+            rcfile = rawClassfile;
+        }
+
+        if (rcfile != null) {
+            final ClassFile cf;
             try {
-                ClassFile cf = new ClassFile(new DataInputStream(
-                                             new ByteArrayInputStream(rawClassfile)));
-                rawClassfile = null;
-                getCount = GET_THRESHOLD;
-                return setClassFile(cf);
+                cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(rcfile)));
             }
             catch (IOException e) {
                 throw new RuntimeException(e.toString(), e);
             }
+            getCount = GET_THRESHOLD;
+            synchronized (this) {
+                rawClassfile = null;
+                return setClassFile(cf);
+            }
         }
 
         InputStream fin = null;