You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Frédéric Chuong (JIRA)" <ji...@apache.org> on 2019/04/03 04:29:02 UTC
[jira] [Created] (GROOVY-9063) @CompileStatic generates invalid
bytecode (leading to runtime ClassCastException) when accessing protected
instance member from 2 level of nested closures
Frédéric Chuong created GROOVY-9063:
---------------------------------------
Summary: @CompileStatic generates invalid bytecode (leading to runtime ClassCastException) when accessing protected instance member from 2 level of nested closures
Key: GROOVY-9063
URL: https://issues.apache.org/jira/browse/GROOVY-9063
Project: Groovy
Issue Type: Bug
Components: Static compilation
Reporter: Frédéric Chuong
Provided the following class:
{code:groovy}
import groovy.transform.CompileStatic
import org.objectweb.asm.ClassReader
import org.objectweb.asm.util.TraceClassVisitor
@CompileStatic
class NoBug {
protected String message = "hello"
void noBug() {
{ ->
{ ->
printClass(getClass().name)
message.length()
}.call()
}.call()
}
static void printClass(String className) {
new ClassReader(className).accept(new TraceClassVisitor(new PrintWriter(System.out)), 0)
}
static void main(String[] args) {
new NoBug().noBug()
}
}
{code}
{panel:title=No problem with 2.5.5|borderColor=green}
Compilation ans execution with Groovy 2.5.5 works fine and produce the following output:
{noformat}
// class version 52.0 (52)
// access flags 0x31
public final class groovy255/NoBug$_noBug_closure1$_closure2 extends groovy/lang/Closure implements org/codehaus/groovy/runtime/GeneratedClosure {
// compiled from: NoBug.groovy
OUTERCLASS groovy255/NoBug$_noBug_closure1 doCall ()Ljava/lang/Object;
// access flags 0x11
public final INNERCLASS groovy255/NoBug$_noBug_closure1$_closure2 null _closure2
// access flags 0x100A
private static synthetic Lorg/codehaus/groovy/reflection/ClassInfo; $staticClassInfo
// access flags 0x1089
public static transient synthetic Z __$stMC
// access flags 0x1
public <init>(Ljava/lang/Object;Ljava/lang/Object;)V
L0
ALOAD 0
ALOAD 1
ALOAD 2
INVOKESPECIAL groovy/lang/Closure.<init> (Ljava/lang/Object;Ljava/lang/Object;)V
L1
RETURN
LOCALVARIABLE this Lgroovy255/NoBug$_noBug_closure1$_closure2; L0 L1 0
LOCALVARIABLE _outerInstance Ljava/lang/Object; L0 L1 1
LOCALVARIABLE _thisObject Ljava/lang/Object; L0 L1 2
MAXSTACK = 3
MAXLOCALS = 3
// access flags 0x1
public doCall()Ljava/lang/Object;
L0
LINENUMBER 14 L0
ALOAD 0
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
INVOKESTATIC groovy255/NoBug.printClass (Ljava/lang/String;)V
ACONST_NULL
POP
L1
LINENUMBER 15 L1
ALOAD 0
LDC "message"
INVOKEINTERFACE groovy/lang/GroovyObject.getProperty (Ljava/lang/String;)Ljava/lang/Object; (itf)
CHECKCAST java/lang/String
INVOKEVIRTUAL java/lang/String.length ()I
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
ARETURN
L2
LINENUMBER 14 L2
FRAME FULL [] [java/lang/Throwable]
NOP
ATHROW
LOCALVARIABLE this Lgroovy255/NoBug$_noBug_closure1$_closure2; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x1004
protected synthetic $getStaticMetaClass()Lgroovy/lang/MetaClass;
ALOAD 0
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
LDC Lgroovy255/NoBug$_noBug_closure1$_closure2;.class
IF_ACMPEQ L0
ALOAD 0
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.initMetaClass (Ljava/lang/Object;)Lgroovy/lang/MetaClass;
ARETURN
L0
FRAME SAME
GETSTATIC groovy255/NoBug$_noBug_closure1$_closure2.$staticClassInfo : Lorg/codehaus/groovy/reflection/ClassInfo;
ASTORE 1
ALOAD 1
IFNONNULL L1
ALOAD 0
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
INVOKESTATIC org/codehaus/groovy/reflection/ClassInfo.getClassInfo (Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;
DUP
ASTORE 1
PUTSTATIC groovy255/NoBug$_noBug_closure1$_closure2.$staticClassInfo : Lorg/codehaus/groovy/reflection/ClassInfo;
L1
FRAME APPEND [org/codehaus/groovy/reflection/ClassInfo]
ALOAD 1
INVOKEVIRTUAL org/codehaus/groovy/reflection/ClassInfo.getMetaClass ()Lgroovy/lang/MetaClass;
ARETURN
MAXSTACK = 2
MAXLOCALS = 2
}
{noformat}
{panel}
{panel:title=Problem with 2.5.6|borderColor=red}
Now with Groovy 2.5.6, compilation seems fine but execution leads to {{ClassCastException}}, and inspection of the inner closure reveals that the bytecode differs:
{noformat}
// class version 52.0 (52)
// access flags 0x31
public final class groovy256/Bug$_bug_closure1$_closure2 extends groovy/lang/Closure implements org/codehaus/groovy/runtime/GeneratedClosure {
// compiled from: Bug.groovy
OUTERCLASS groovy256/Bug$_bug_closure1 doCall ()Ljava/lang/Object;
// access flags 0x11
public final INNERCLASS groovy256/Bug$_bug_closure1$_closure2 null _closure2
// access flags 0x100A
private static synthetic Lorg/codehaus/groovy/reflection/ClassInfo; $staticClassInfo
// access flags 0x1089
public static transient synthetic Z __$stMC
// access flags 0x1
public <init>(Ljava/lang/Object;Ljava/lang/Object;)V
L0
ALOAD 0
ALOAD 1
ALOAD 2
INVOKESPECIAL groovy/lang/Closure.<init> (Ljava/lang/Object;Ljava/lang/Object;)V
L1
RETURN
LOCALVARIABLE this Lgroovy256/Bug$_bug_closure1$_closure2; L0 L1 0
LOCALVARIABLE _outerInstance Ljava/lang/Object; L0 L1 1
LOCALVARIABLE _thisObject Ljava/lang/Object; L0 L1 2
MAXSTACK = 3
MAXLOCALS = 3
// access flags 0x1
public doCall()Ljava/lang/Object;
L0
LINENUMBER 14 L0
ALOAD 0
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
INVOKESTATIC groovy256/Bug.printClass (Ljava/lang/String;)V
ACONST_NULL
POP
L1
LINENUMBER 15 L1
ALOAD 0
CHECKCAST groovy256/Bug$_bug_closure1$_closure2
INVOKEVIRTUAL groovy256/Bug$_bug_closure1$_closure2.getOwner ()Ljava/lang/Object;
CHECKCAST groovy256/Bug
GETFIELD groovy256/Bug.message : Ljava/lang/String;
INVOKEVIRTUAL java/lang/String.length ()I
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
ARETURN
L2
LINENUMBER 14 L2
FRAME FULL [] [java/lang/Throwable]
NOP
ATHROW
LOCALVARIABLE this Lgroovy256/Bug$_bug_closure1$_closure2; L0 L2 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1004
protected synthetic $getStaticMetaClass()Lgroovy/lang/MetaClass;
ALOAD 0
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
LDC Lgroovy256/Bug$_bug_closure1$_closure2;.class
IF_ACMPEQ L0
ALOAD 0
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter.initMetaClass (Ljava/lang/Object;)Lgroovy/lang/MetaClass;
ARETURN
L0
FRAME SAME
GETSTATIC groovy256/Bug$_bug_closure1$_closure2.$staticClassInfo : Lorg/codehaus/groovy/reflection/ClassInfo;
ASTORE 1
ALOAD 1
IFNONNULL L1
ALOAD 0
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
INVOKESTATIC org/codehaus/groovy/reflection/ClassInfo.getClassInfo (Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;
DUP
ASTORE 1
PUTSTATIC groovy256/Bug$_bug_closure1$_closure2.$staticClassInfo : Lorg/codehaus/groovy/reflection/ClassInfo;
L1
FRAME APPEND [org/codehaus/groovy/reflection/ClassInfo]
ALOAD 1
INVOKEVIRTUAL org/codehaus/groovy/reflection/ClassInfo.getMetaClass ()Lgroovy/lang/MetaClass;
ARETURN
MAXSTACK = 2
MAXLOCALS = 2
}
{noformat}
{noformat}
groovy256.Bug$_bug_closure1 cannot be cast to groovy256.Bug
java.lang.ClassCastException: groovy256.Bug$_bug_closure1 cannot be cast to groovy256.Bug
at groovy256.Bug$_bug_closure1$_closure2.doCall(Bug.groovy:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
at groovy.lang.Closure.call(Closure.java:405)
at groovy.lang.Closure.call(Closure.java:399)
at groovy256.Bug$_bug_closure1.doCall(Bug.groovy:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
at groovy.lang.Closure.call(Closure.java:405)
at groovy.lang.Closure.call(Closure.java:399)
at groovy256.Bug.bug(Bug.groovy:12)
at groovy256.BugTest.bug(BugTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
{noformat}
{panel}
{panel:title=Note}
Replacing
{noformat}
message.length()
{noformat}
with
{noformat}
this.@message.length()
{noformat}
does not exhibit that problem.
{panel}
This may be related to [GROOVY-7687] which relates to similar conditions (nested closure and {{\@CompileStatic}}
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)