Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-31484

Endless loop in DefaultInvoker.getProperty when accessing field via getter/setter without @

      The following script for some reason will make Jenkins go out of memory and will never complete the execution.

      node {
      	HipNotifier chip = new HipNotifier('A')
          echo chip.name	
      }
      
      public class HipNotifier {
          private String name;
      
          public HipNotifier(String pName) {
              this.name = pName
          }
      
          String getName() {
              return name
          }
      }
      

          [JENKINS-31484] Endless loop in DefaultInvoker.getProperty when accessing field via getter/setter without @

          Jesse Glick added a comment -

          Reproducible:

          "Computer.threadPoolForRemoting [#4]" … runnable …
             java.lang.Thread.State: RUNNABLE
          	at java.lang.Throwable.fillInStackTrace(Native Method)
          	at java.lang.Throwable.fillInStackTrace(Throwable.java:783)
          	- locked <0x00000007ae52b740> (a org.codehaus.groovy.runtime.InvokerInvocationException)
          	at java.lang.Throwable.<init>(Throwable.java:250)
          	at java.lang.Exception.<init>(Exception.java:54)
          	at java.lang.RuntimeException.<init>(RuntimeException.java:51)
          	at groovy.lang.GroovyRuntimeException.<init>(GroovyRuntimeException.java:49)
          	at org.codehaus.groovy.runtime.InvokerInvocationException.<init>(InvokerInvocationException.java:31)
          	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97)
          	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
          	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1612)
          	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3343)
          	at Something.getProperty(WorkflowScript)
          	at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:156)
          	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:452)
          	at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.getProperty(DefaultInvoker.java:25)
          	at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:17)
          	at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:62)
          	at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
          	at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:54)
          	at sun.reflect.GeneratedMethodAccessor84.invoke(Unknown Source)
          	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          	at java.lang.reflect.Method.invoke(Method.java:497)
          	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
          	at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
          	at com.cloudbees.groovy.cps.Next.step(Next.java:58)
          	at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:145)
          	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164)
          	at …
          

          Jesse Glick added a comment - Reproducible: "Computer.threadPoolForRemoting [#4]" … runnable … java.lang.Thread.State: RUNNABLE at java.lang.Throwable.fillInStackTrace(Native Method) at java.lang.Throwable.fillInStackTrace(Throwable.java:783) - locked <0x00000007ae52b740> (a org.codehaus.groovy.runtime.InvokerInvocationException) at java.lang.Throwable.<init>(Throwable.java:250) at java.lang.Exception.<init>(Exception.java:54) at java.lang.RuntimeException.<init>(RuntimeException.java:51) at groovy.lang.GroovyRuntimeException.<init>(GroovyRuntimeException.java:49) at org.codehaus.groovy.runtime.InvokerInvocationException.<init>(InvokerInvocationException.java:31) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233) at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1612) at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3343) at Something.getProperty(WorkflowScript) at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:156) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:452) at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.getProperty(DefaultInvoker.java:25) at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:17) at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:62) at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30) at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:54) at sun.reflect.GeneratedMethodAccessor84.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21) at com.cloudbees.groovy.cps.Next.step(Next.java:58) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:145) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164) at …

          Jesse Glick added a comment -

          A hard kill from JENKINS-25550 allows the build to be marked as aborted, but does not actually kill the CpsVmExecutorService call, so Jenkins will still crash. Probably need to escalate to a Thread.stop in such a case.

          Jesse Glick added a comment - A hard kill from JENKINS-25550 allows the build to be marked as aborted, but does not actually kill the CpsVmExecutorService call, so Jenkins will still crash. Probably need to escalate to a Thread.stop in such a case.

          Junpeng Luo added a comment -

          Similar issue occured when using getter in class of pipeline global shared lib. We decided not use getters for now. Any solutions for this problem?

          Junpeng Luo added a comment - Similar issue occured when using getter in class of pipeline global shared lib. We decided not use getters for now. Any solutions for this problem?

          Jesse Glick added a comment -

          As a workaround, try explicitly calling .getName() rather than using the .name shorthand. Have not yet found time to track down the actual issue; probably some mistake in groovy-cps.

          Jesse Glick added a comment - As a workaround, try explicitly calling .getName() rather than using the .name shorthand. Have not yet found time to track down the actual issue; probably some mistake in groovy-cps .

          Jesse Glick added a comment -

          Possibly related to JENKINS-38021?

          Jesse Glick added a comment - Possibly related to JENKINS-38021 ?

          Jesse Glick added a comment -

          Reproduced hang in test, but cannot find anything in the physical thread dump; high CPU activity seems to be in GC threads. I do see:

          com.cloudbees.jenkins.support.SupportPlugin writeBundle
          WARNING: Could not attach 'nodes/master/pipeline-thread-dump.txt' to support bundle
          java.lang.StackOverflowError
          	at com.cloudbees.groovy.cps.impl.SourceLocation.toStackTrace(SourceLocation.java:22)
          	at com.cloudbees.groovy.cps.impl.CallEnv.buildStackTraceElements(CallEnv.java:101)
          	at com.cloudbees.groovy.cps.impl.FunctionCallEnv.buildStackTraceElements(FunctionCallEnv.java:13)
          	at com.cloudbees.groovy.cps.impl.ProxyEnv.buildStackTraceElements(ProxyEnv.java:64)
          	at com.cloudbees.groovy.cps.impl.ProxyEnv.buildStackTraceElements(ProxyEnv.java:64)
          	at com.cloudbees.groovy.cps.impl.CallEnv.buildStackTraceElements(CallEnv.java:103)
          	at com.cloudbees.groovy.cps.impl.FunctionCallEnv.buildStackTraceElements(FunctionCallEnv.java:13)
          	at …
          

          Jesse Glick added a comment - Reproduced hang in test, but cannot find anything in the physical thread dump; high CPU activity seems to be in GC threads. I do see: com.cloudbees.jenkins.support.SupportPlugin writeBundle WARNING: Could not attach 'nodes/master/pipeline-thread-dump.txt' to support bundle java.lang.StackOverflowError at com.cloudbees.groovy.cps.impl.SourceLocation.toStackTrace(SourceLocation.java:22) at com.cloudbees.groovy.cps.impl.CallEnv.buildStackTraceElements(CallEnv.java:101) at com.cloudbees.groovy.cps.impl.FunctionCallEnv.buildStackTraceElements(FunctionCallEnv.java:13) at com.cloudbees.groovy.cps.impl.ProxyEnv.buildStackTraceElements(ProxyEnv.java:64) at com.cloudbees.groovy.cps.impl.ProxyEnv.buildStackTraceElements(ProxyEnv.java:64) at com.cloudbees.groovy.cps.impl.CallEnv.buildStackTraceElements(CallEnv.java:103) at com.cloudbees.groovy.cps.impl.FunctionCallEnv.buildStackTraceElements(FunctionCallEnv.java:13) at …

          Jesse Glick added a comment -

          Using .getName() rather than .name is not the issue, since the bug is inside the getter itself. The workaround is to use the more explicit:

          String getName() {this.@name}
          

          Similarly for setters:

          void setName(String name) {this.@name = name}
          

          Jesse Glick added a comment - Using .getName() rather than .name is not the issue, since the bug is inside the getter itself. The workaround is to use the more explicit: String getName() { this .@name} Similarly for setters: void setName( String name) { this .@name = name}

          Jesse Glick added a comment -

          It is worth noting that this behavior of accessing the backing field directly is done in order to prevent a stack overflow when using the property access syntax within a class that defines the property.

          Intuitive enough, though it is hard to see how a CompilationCustomizer is supposed to be informed of this difference. In the proposed PR I just used trial and error. Javadoc is minimal to nonexistent, as is typical in Groovy sources.

          Jesse Glick added a comment - It is worth noting that this behavior of accessing the backing field directly is done in order to prevent a stack overflow when using the property access syntax within a class that defines the property. Intuitive enough, though it is hard to see how a CompilationCustomizer is supposed to be informed of this difference. In the proposed PR I just used trial and error. Javadoc is minimal to nonexistent, as is typical in Groovy sources.

          Devin Nusbaum added a comment -

          Ran into another variant of this issue, and opened a PR against groovy-cps with an ignored test case: https://github.com/cloudbees/groovy-cps/pull/95. The issue is that a getter like the following works in regular Groovy, but fails with a StackOverflowError in groovy-cps:

          String getName() {this.name}
          

          Devin Nusbaum added a comment - Ran into another variant of this issue, and opened a PR against groovy-cps with an ignored test case: https://github.com/cloudbees/groovy-cps/pull/95 . The issue is that a getter like the following works in regular Groovy, but fails with a StackOverflowError in groovy-cps: String getName() { this .name}

          Megan Smith added a comment -

          This still seems broken - we just ran into it with Jenkins version Jenkins 2.235.2

          Megan Smith added a comment - This still seems broken - we just ran into it with Jenkins version Jenkins 2.235.2

            jglick Jesse Glick
            vexdev Luca Vitucci
            Votes:
            4 Vote for this issue
            Watchers:
            12 Start watching this issue

              Created:
              Updated:
              Resolved: