You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/12/29 14:13:11 UTC

[groovy] 18/28: GROOVY-8843: Fix illegal reflective access within o.c.g.vmplugin.v7.Java7 (closes #811)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch refine-groovydoc
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit f40f76af134b6d5fd2d466d410ac48ad907e3b15
Author: Paul King <pa...@asert.com.au>
AuthorDate: Mon Oct 15 18:12:45 2018 +1000

    GROOVY-8843: Fix illegal reflective access within o.c.g.vmplugin.v7.Java7 (closes #811)
---
 build.gradle                                       |  6 +-
 .../org/codehaus/groovy/vmplugin/v7/Java7.java     | 67 +++++++++++-----------
 .../org/codehaus/groovy/vmplugin/v9/Java9.java     | 66 ++++++++++++++++++++-
 3 files changed, 103 insertions(+), 36 deletions(-)

diff --git a/build.gradle b/build.gradle
index b36eb55..36db7ba 100644
--- a/build.gradle
+++ b/build.gradle
@@ -414,11 +414,11 @@ task checkCompatibility {
     }
 }
 
-if (!JavaVersion.current().java8Compatible) {
+if (!JavaVersion.current().java9Compatible) {
     logger.lifecycle '''
     **************************************** WARNING ********************************************
-    ******   You are running the build with an older JDK. NEVER try to release with 1.7.   ******
-    ******   You must use a JDK 1.8+ in order to compile all features of the language.     ******
+    ******   You are running the build with an older JDK. NEVER try to release with 1.8.   ******
+    ******   You must use a JDK 1.9+ in order to compile all features of the language.     ******
     *********************************************************************************************
 '''
 }
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java b/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java
index 11a2091..8694d38 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java
@@ -29,40 +29,44 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 
 /**
- * Java 7 based functions. Currently just a stub but you can
- * add your own methods to your own version and place it on the classpath
- * ahead of this one.
+ * Java 7 based functions.
  *
- * @author Jochen Theodorou
+ * For crude customization, you can add your own methods to your own version and place it on the classpath ahead of this one.
  */
 public class Java7 extends Java6 {
-    private static final Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
-    static {
-        Constructor<MethodHandles.Lookup> con = null;
-        try {
-            con = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
-        } catch (NoSuchMethodException e) {
-            throw new GroovyBugError(e);
-        }
-        try {
-            if (!con.isAccessible()) {
-                final Constructor tmp = con;
-                AccessController.doPrivileged(new PrivilegedAction() {
-                    @Override
-                    public Object run() {
-                        tmp.setAccessible(true);
-                        return null;
-                    }
-                });
+    private static class LookupHolder {
+        private static final Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
+        static {
+            Constructor<MethodHandles.Lookup> con = null;
+            try {
+                con = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
+            } catch (NoSuchMethodException e) {
+                throw new GroovyBugError(e);
             }
-        } catch (SecurityException se) {
-            con = null;
-        } catch (RuntimeException re) {
-            // test for JDK9 JIGSAW
-            if (!"java.lang.reflect.InaccessibleObjectException".equals(re.getClass().getName())) throw re;
-            con = null;
+            try {
+                if (!con.isAccessible()) {
+                    final Constructor tmp = con;
+                    AccessController.doPrivileged(new PrivilegedAction() {
+                        @Override
+                        public Object run() {
+                            tmp.setAccessible(true);
+                            return null;
+                        }
+                    });
+                }
+            } catch (SecurityException se) {
+                con = null;
+            } catch (RuntimeException re) {
+                // test for JDK9 JIGSAW
+                if (!"java.lang.reflect.InaccessibleObjectException".equals(re.getClass().getName())) throw re;
+                con = null;
+            }
+            LOOKUP_Constructor = con;
         }
-        LOOKUP_Constructor = con;
+    }
+
+    private static Constructor<MethodHandles.Lookup> getLookupConstructor() {
+        return LookupHolder.LOOKUP_Constructor;
     }
 
     @Override
@@ -77,7 +81,7 @@ public class Java7 extends Java6 {
 
     @Override
     public Object getInvokeSpecialHandle(final Method method, final Object receiver) {
-        if (LOOKUP_Constructor==null) {
+        if (getLookupConstructor() == null) {
             return super.getInvokeSpecialHandle(method, receiver);
         }
         if (!method.isAccessible()) {
@@ -91,8 +95,7 @@ public class Java7 extends Java6 {
         }
         Class declaringClass = method.getDeclaringClass();
         try {
-            return LOOKUP_Constructor.
-                    newInstance(declaringClass, -1).
+            return getLookupConstructor().newInstance(declaringClass, -1).
                     unreflectSpecial(method, declaringClass).
                     bindTo(receiver);
         } catch (ReflectiveOperationException e) {
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
index 7468581..290a654 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
@@ -18,14 +18,78 @@
  */
 package org.codehaus.groovy.vmplugin.v9;
 
+import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.vmplugin.v8.Java8;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
 /**
- * Java 9 based functions will be added here if needed.
+ * Additional Java 9 based functions will be added here as needed.
  */
 public class Java9 extends Java8 {
+
+    private static class LookupHolder {
+        private static final Method PRIVATE_LOOKUP;
+        private static final Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
+        static {
+            Constructor<MethodHandles.Lookup> lookup = null;
+            Method privateLookup = null;
+            try { // java 9
+                privateLookup = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
+            } catch (final NoSuchMethodException | RuntimeException e) { // java 8 or fallback if anything else goes wrong
+                try {
+                    lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
+                    if (!lookup.isAccessible()) {
+                        lookup.setAccessible(true);
+                    }
+                } catch (final NoSuchMethodException ex) {
+                    throw new IllegalStateException("Incompatible JVM", e);
+                }
+            }
+            PRIVATE_LOOKUP = privateLookup;
+            LOOKUP_Constructor = lookup;
+        }
+    }
+
+    private static Constructor<MethodHandles.Lookup> getLookupConstructor() {
+        return LookupHolder.LOOKUP_Constructor;
+    }
+
+    private static Method getPrivateLookup() {
+        return LookupHolder.PRIVATE_LOOKUP;
+    }
+
+    public static MethodHandles.Lookup of(final Class<?> declaringClass) {
+        try {
+            if (getPrivateLookup() != null) {
+                return MethodHandles.Lookup.class.cast(getPrivateLookup().invoke(null, declaringClass, MethodHandles.lookup()));
+            }
+            return getLookupConstructor().newInstance(declaringClass, MethodHandles.Lookup.PRIVATE).in(declaringClass);
+        } catch (final IllegalAccessException | InstantiationException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     @Override
     public int getVersion() {
         return 9;
     }
+
+    @Override
+    public Object getInvokeSpecialHandle(Method method, Object receiver) {
+        if (getLookupConstructor() != null) {
+            Class declaringClass = method.getDeclaringClass();
+            try {
+                return of(declaringClass).unreflectSpecial(method, receiver.getClass()).bindTo(receiver);
+            } catch (ReflectiveOperationException e) {
+                throw new GroovyBugError(e);
+            }
+        }
+        return super.getInvokeSpecialHandle(method, receiver);
+    }
 }