You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gs...@apache.org on 2007/02/02 15:42:28 UTC

svn commit: r502616 - /harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java

Author: gshimansky
Date: Fri Feb  2 06:42:27 2007
New Revision: 502616

URL: http://svn.apache.org/viewvc?view=rev&rev=502616
Log:
Applied HARMONY-1930 [drlvm][kernel classes] java.lang.Class.newInstance() sometimes returns unexpected IllegalAccessException when several threads try to create instance of package access class

Tests passed on Ubuntu6 x86, Windows 2003 server x86 and SuSE9 x86_64


Modified:
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java?view=diff&rev=502616&r1=502615&r2=502616
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/Class.java Fri Feb  2 06:42:27 2007
@@ -97,6 +97,9 @@
 
     private transient ProtectionDomain domain;
 
+    /** It is required for synchronization in newInstance method. */
+    private boolean isDefaultConstructorInitialized;
+
     // TODO make it soft reference
     transient ReflectionData reflectionData;
     transient SoftReference<GACache> softCache;
@@ -699,35 +702,63 @@
             sc.checkMemberAccess(this, Member.PUBLIC);
             sc.checkPackageAccess(reflectionData.packageName);
         }
-        try {
-            if (reflectionData.defaultConstructor == null) {
-                reflectionData.initDefaultConstructor();
+
+        /*
+         * HARMONY-1930: The synchronization issue is possible here.
+         *
+         * The issues is caused by fact that:
+         * - first thread starts defaultConstructor initialization, including
+         *   setting "isAccessible" flag to "true" for Constrcutor object
+         * - another thread bypasses initialization and calls "newInstance" 
+         *   for defaultConstructor (while isAccessible is "false" yet)
+         * - so, for this "another" thread the Constructor.newInstance checks
+         *   the access rights by mistake and IllegalAccessException happens
+         */
+        while (!isDefaultConstructorInitialized) {
+            synchronized (reflectionData) {
+                if (isDefaultConstructorInitialized) {
+                    break; // non-first threads can be here - nothing to do
+                }
+
+                // only first thread can reach this point & do initialization
+                try {
+                    reflectionData.initDefaultConstructor();
+                } catch (NoSuchMethodException e) {
+                    throw new InstantiationException(e.getMessage()
+                            + " method not found");
+                }
                 final Constructor<T> c = reflectionData.defaultConstructor;
+
                 try {
                     AccessController.doPrivileged(new PrivilegedAction<Object>() {
-
-                        public Object run() {
+                            public Object run() {
                             c.setAccessible(true);
                             return null;
-                        }
-                    });
+                            }
+                            });
                 } catch (SecurityException e) {
                     // can't change accessibilty of the default constructor
                     IllegalAccessException ex = new IllegalAccessException();
                     ex.initCause(e);
                     throw ex;
                 }
+
+                // default constructor is initialized, access flag is set
+                isDefaultConstructorInitialized = true;
+                break;
             }
-            Reflection.checkMemberAccess(
+        }
+
+        // initialization is done, threads may work from here in any order
+        Reflection.checkMemberAccess(
                 VMStack.getCallerClass(0),
                 reflectionData.defaultConstructor.getDeclaringClass(),
                 reflectionData.defaultConstructor.getDeclaringClass(),
                 reflectionData.defaultConstructor.getModifiers()
             );
+
+        try {
             newInstance = reflectionData.defaultConstructor.newInstance();
-        } catch (NoSuchMethodException e) {
-            throw new InstantiationException(e.getMessage()
-                + " method not found");
         } catch (InvocationTargetException e) {
             System.rethrow(e.getCause());
         }