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 2022/08/28 12:36:17 UTC
[groovy] 02/03: Fix accessing `clone` illegally
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch danielsun/fix-clone-array-based-on-groovy10730pr
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 45146486e11af896103c7a8ac7c040527f7ffac7
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Aug 28 20:05:23 2022 +0800
Fix accessing `clone` illegally
---
src/main/java/groovy/lang/MetaClassImpl.java | 22 +---------------
.../org/codehaus/groovy/runtime/ArrayUtil.java | 30 ++++++++++++++++++++++
.../org/codehaus/groovy/vmplugin/v8/Selector.java | 11 ++++++++
src/test/groovy/bugs/Groovy9103.groovy | 9 +++++++
4 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index c32102989d..14ca8081fb 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -1131,7 +1131,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
if (receiverClass.isArray()) {
if (methodName.equals("clone") && arguments.length == 0) {
try {
- return (Object[]) MethodHandleHolder.CLONE_ARRAY_METHOD_HANDLE.invokeExact((Object[]) object);
+ return (Object[]) ArrayUtil.getCloneArrayMethodHandle().invokeExact((Object[]) object);
} catch (Throwable t) {
throw new GroovyRuntimeException(t);
}
@@ -1164,26 +1164,6 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
}
}
- private static class MethodHandleHolder {
- private static final MethodHandle CLONE_ARRAY_METHOD_HANDLE;
- static {
- final Class<ArrayUtil> arrayUtilClass = ArrayUtil.class;
- Method cloneArrayMethod;
- try {
- cloneArrayMethod = arrayUtilClass.getDeclaredMethod("cloneArray", Object[].class);
- } catch (NoSuchMethodException e) {
- throw new GroovyBugError("Failed to find `cloneArray` method in class `" + arrayUtilClass.getName() + "`", e);
- }
-
- try {
- CLONE_ARRAY_METHOD_HANDLE = MethodHandles.lookup().in(arrayUtilClass).unreflect(cloneArrayMethod);
- } catch (IllegalAccessException e) {
- throw new GroovyBugError("Failed to create method handle for " + cloneArrayMethod);
- }
- }
- private MethodHandleHolder() {}
- }
-
private static final ClassValue<Map<String, Set<Method>>> SPECIAL_METHODS_MAP = new ClassValue<Map<String, Set<Method>>>() {
@Override
protected Map<String, Set<Method>> computeValue(final Class<?> type) {
diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java b/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
index 72bcd83c51..d35a4d80ea 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
@@ -18,6 +18,12 @@
*/
package org.codehaus.groovy.runtime;
+import org.codehaus.groovy.GroovyBugError;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+
/**
* This is a generated class used internally during the writing of bytecode within the CallSiteWriter logic.
* This is not a class exposed to users, as is the case with almost all classes in the org.codehaus.groovy packages.
@@ -55,6 +61,30 @@ package org.codehaus.groovy.runtime;
public class ArrayUtil {
private static final Object[] EMPTY = new Object[0];
+ public static MethodHandle getCloneArrayMethodHandle() {
+ return MethodHandleHolder.CLONE_ARRAY_METHOD_HANDLE;
+ }
+
+ private static class MethodHandleHolder {
+ private static final MethodHandle CLONE_ARRAY_METHOD_HANDLE;
+ static {
+ final Class<ArrayUtil> arrayUtilClass = ArrayUtil.class;
+ Method cloneArrayMethod;
+ try {
+ cloneArrayMethod = arrayUtilClass.getDeclaredMethod("cloneArray", Object[].class);
+ } catch (NoSuchMethodException e) {
+ throw new GroovyBugError("Failed to find `cloneArray` method in class `" + arrayUtilClass.getName() + "`", e);
+ }
+
+ try {
+ CLONE_ARRAY_METHOD_HANDLE = MethodHandles.lookup().in(arrayUtilClass).unreflect(cloneArrayMethod);
+ } catch (IllegalAccessException e) {
+ throw new GroovyBugError("Failed to create method handle for " + cloneArrayMethod);
+ }
+ }
+ private MethodHandleHolder() {}
+ }
+
public static <T> T[] cloneArray(T[] array) {
return array.clone();
}
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
index 2352a1c21b..c5d75a4968 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -38,6 +38,7 @@ import org.codehaus.groovy.reflection.CachedMethod;
import org.codehaus.groovy.reflection.ClassInfo;
import org.codehaus.groovy.reflection.GeneratedMetaMethod;
import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
+import org.codehaus.groovy.runtime.ArrayUtil;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.GroovyCategorySupport;
import org.codehaus.groovy.runtime.GroovyCategorySupport.CategoryMethod;
@@ -673,9 +674,19 @@ public abstract class Selector {
}
}
+ private static final Method OBJECT_CLONE_METHOD;
+ static {
+ try {
+ OBJECT_CLONE_METHOD = Object.class.getDeclaredMethod("clone");
+ } catch (NoSuchMethodException e) {
+ throw new GroovyBugError(e); // should never happen
+ }
+ }
private MethodHandle correctClassForNameAndUnReflectOtherwise(Method m) throws IllegalAccessException {
if (m.getDeclaringClass() == Class.class && m.getName().equals("forName") && m.getParameterTypes().length == 1) {
return MethodHandles.insertArguments(CLASS_FOR_NAME, 1, true, sender.getClassLoader());
+ } else if (null != args && args.getClass().isArray() && OBJECT_CLONE_METHOD.equals(m)) {
+ return ArrayUtil.getCloneArrayMethodHandle();
} else {
return LOOKUP.unreflect(m);
}
diff --git a/src/test/groovy/bugs/Groovy9103.groovy b/src/test/groovy/bugs/Groovy9103.groovy
index ab1be1a0c5..721344f0c6 100644
--- a/src/test/groovy/bugs/Groovy9103.groovy
+++ b/src/test/groovy/bugs/Groovy9103.groovy
@@ -69,4 +69,13 @@ final class Groovy9103 {
Object obj = new Tuple1('abc')
assert obj.clone()
}
+
+ @Test
+ void testClone4() {
+ assertScript '''
+ int[] nums = [1, 2, 3]
+ int[] cloned = nums.clone()
+ assert nums == cloned
+ '''
+ }
}