Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

GROOVY-5285: Stack overflow error when calling super.setMetaClass on …

…an object which doesn't have a superclass
  • Loading branch information...
commit c146b063b0ca7a82b3d664007f8525262558e8d3 1 parent c31efd5
@melix melix authored
View
30 src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -18105,7 +18105,7 @@ public static void setMetaClass(Class self, MetaClass metaClass) {
}
/**
- * Set the metaclass for an object
+ * Set the metaclass for an object.
* @param self the object whose metaclass we want to set
* @param metaClass the new metaclass value
* @since 1.6.0
@@ -18114,16 +18114,28 @@ public static void setMetaClass(Object self, MetaClass metaClass) {
if (metaClass instanceof HandleMetaClass)
metaClass = ((HandleMetaClass)metaClass).getAdaptee();
- if (self instanceof GroovyObject) {
- ((GroovyObject)self).setMetaClass(metaClass);
- disablePrimitiveOptimization(self);
- } else if (self instanceof Class) {
- ((MetaClassRegistryImpl)GroovySystem.getMetaClassRegistry()).setMetaClass((Class)self, metaClass);
+ if (self instanceof Class) {
+ ((MetaClassRegistryImpl)GroovySystem.getMetaClassRegistry()).setMetaClass((Class) self, metaClass);
} else {
((MetaClassRegistryImpl)GroovySystem.getMetaClassRegistry()).setMetaClass(self, metaClass);
}
}
+ /**
+ * Set the metaclass for a GroovyObject.
+ * @param self the object whose metaclass we want to set
+ * @param metaClass the new metaclass value
+ * @since 2.0.0
+ */
+ public static void setMetaClass(GroovyObject self, MetaClass metaClass) {
+ // this method was introduced as to prevent from a stack overflow, described in GROOVY-5285
+ if (metaClass instanceof HandleMetaClass)
+ metaClass = ((HandleMetaClass)metaClass).getAdaptee();
+
+ self.setMetaClass(metaClass);
+ disablePrimitiveOptimization(self);
+ }
+
private static void disablePrimitiveOptimization(Object self) {
Field sdyn;
Class c = self.getClass();
@@ -18197,7 +18209,11 @@ public static MetaClass metaClass (Object self, Closure closure){
final ExpandoMetaClass metaClass = new ExpandoMetaClass(self.getClass(), false, true);
metaClass.initialize();
metaClass.define(closure);
- setMetaClass(self, metaClass);
+ if (self instanceof GroovyObject) {
+ setMetaClass((GroovyObject)self, metaClass);
+ } else {
+ setMetaClass(self, metaClass);
+ }
return metaClass;
}
else {
View
2  src/main/org/codehaus/groovy/runtime/HandleMetaClass.java
@@ -64,7 +64,7 @@ public GroovyObject replaceDelegate() {
((ExpandoMetaClass)delegate).registerInstanceMethod(method);
}
delegate.initialize();
- DefaultGroovyMethods.setMetaClass(object, delegate);
+ MetaClassHelper.doSetMetaClass(object, delegate);
object = NONE;
}
}
View
24 src/main/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -16,10 +16,7 @@
package org.codehaus.groovy.runtime;
-import groovy.lang.Closure;
-import groovy.lang.GString;
-import groovy.lang.GroovyRuntimeException;
-import groovy.lang.MetaMethod;
+import groovy.lang.*;
import org.codehaus.groovy.reflection.CachedClass;
import org.codehaus.groovy.util.FastArray;
import org.codehaus.groovy.reflection.ParameterTypes;
@@ -1035,4 +1032,23 @@ public static void unwrap(Object[] arguments) {
}
}
}
+
+ /**
+ * Sets the meta class for an object, by delegating to the appropriate
+ * {@link DefaultGroovyMethods} helper method. This method was introduced as
+ * a breaking change in 2.0 to solve rare cases of stack overflow. See GROOVY-5285.
+ *
+ * The method is named doSetMetaClass in order to prevent misusages. Do not use
+ * this method directly unless you know what you do.
+ *
+ * @param self the object for which to set the meta class
+ * @param mc the metaclass
+ */
+ public static void doSetMetaClass(Object self, MetaClass mc) {
+ if (self instanceof GroovyObject) {
+ DefaultGroovyMethods.setMetaClass((GroovyObject)self, mc);
+ } else {
+ DefaultGroovyMethods.setMetaClass(self, mc);
+ }
+ }
}
View
4 src/main/org/codehaus/groovy/runtime/metaclass/MixedInMetaClass.java
@@ -17,11 +17,11 @@
package org.codehaus.groovy.runtime.metaclass;
import org.codehaus.groovy.runtime.InvokerHelper;
-import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import java.lang.ref.WeakReference;
import groovy.lang.*;
+import org.codehaus.groovy.runtime.MetaClassHelper;
/**
* @author Alex Tkachman
@@ -33,7 +33,7 @@
public MixedInMetaClass(Object instance, Object owner) {
super(GroovySystem.getMetaClassRegistry().getMetaClass(instance.getClass()));
this.owner = new WeakReference(owner);
- DefaultGroovyMethods.setMetaClass (instance, this);
+ MetaClassHelper.doSetMetaClass(instance, this);
}
protected Object getOwner() {
View
16 src/test/groovy/bugs/Groovy5285Bug.groovy
@@ -0,0 +1,16 @@
+package groovy.bugs
+
+class Groovy5285Bug extends GroovyTestCase {
+ void testShouldNotThrowStackOverflow() {
+ assertScript '''
+ class Test {
+ void setMetaClass(MetaClass metaClass) {
+ super.setMetaClass(metaClass)
+ }
+ }
+
+ def obj = new Test()
+ obj.metaClass = obj.metaClass
+ '''
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.