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

Pipeline descends into infinite loop on deep class inheritence

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Minor Minor
    • workflow-cps-plugin

       

      The overrided methods of pipeline libraries start to loop on themselves after three iterations.

      Looks very similar to this groovy bug:

      https://issues.apache.org/jira/browse/GROOVY-6818


      Reproducing:

      pipeline library:

       

      ======== ./Order_0.groovy
      package [PACKAGE]
      import org.jenkinsci.plugins.workflow.cps.CpsFlowExecution
      import org.jenkinsci.plugins.workflow.cps.CpsThread
      
      class Order_0 implements Serializable {
          static protected def script
          def echo(Object data) {
              CpsThread thread = CpsThread.current()
              CpsFlowExecution execution = thread.execution 
              execution?.getOwner()?.getListener()?.getLogger()?.println(data)
          } 
      
          String doThingAsc () { echo '-0- (base)' }
      }
      ======== ./Order_1.groovy
      package [PACKAGE]
      class Order_1 extends Order_0 implements Serializable {
          @Override
          String doThingAsc () {
              echo '-1-'
              super.doThingAsc()
          }
          String doThingDsc () {
              echo '-1- (base)'
          }
      }
      ======== ./Order_2.groovy
      package [PACKAGE]
      class Order_2 extends Order_1 implements Serializable {
          @Override
          String doThingAsc () {
              echo '-2-'
              super.doThingAsc()
          }
          @Override
          String doThingDsc () {
              echo '-2-'
              super.doThingDsc()
          }
      }
      ======== ./Order_3.groovy
      package [PACKAGE]
      class Order_3 extends Order_2 implements Serializable {   
          @Override
          String doThingDsc () {
              echo '-3-'
              super.doThingDsc()
          }
      }
      

      pipeline file:

       

      @Library("[Library]") _;
      import [PACKAGE].*
      def test0 = new Order_0(script: this);
      def test1 = new Order_1(script: this);
      def test2 = new Order_2(script: this);
      def test3 = new Order_3(script: this);
      
      /////////////////////////////////////////
      try {
          test0.doThingAsc()
          test0.echo '-'*30
          test1.doThingAsc()
          test1.echo '-'*30
          test2.doThingAsc()
          test2.echo '-'*30
          test3.doThingAsc()
      } catch (java.lang.StackOverflowError ex) {
          echo 'We have an error ASC'
      }
      /////////////////////////////////////////
      try {
          test1.doThingDsc()
          test0.echo '-'*30
          test2.doThingDsc()
          test0.echo '-'*30
          test3.doThingDsc()
      } catch (java.lang.StackOverflowError ex) {
          echo 'We have an error DSC'
      }
      /////////////////////////////////////////

       

      We expect output:

       

      -0- (base)
      ------------------------------
      -1-
      -0- (base)
      ------------------------------
      -2-
      -1-
      -0- (base) 
      ------------------------------ 
      -2- 
      -1-
      -0- (base)
      
      
      -1- (base)
      ------------------------------
      -2-
      -1- (base)
      ------------------------------
      -3-
      -2-
      -1- (base)

       

       

       

       

       

      We get output:

      -0- (base)
      ------------------------------
      -1-
      -0- (base)
      ------------------------------
      -2-
      -1-
      -1-
      -1-
      -1-
      <... way too much ...>
      -1-
      -1-
      
      We have an error ASC
      
      
      -1- (base)
      ------------------------------
      -2-
      -1- (base)
      ------------------------------
      -3-
      -2-
      -2-
      -2-
      -2-
      -2-
      -2-
      -2-
      -2-
      -2-
      <... way too much ...>
      -2-
      -2-
      
      We have an error DSC

       

       

          [JENKINS-53248] Pipeline descends into infinite loop on deep class inheritence

          I have a similar issue.

          You can reproduce it with the following simple example:

          Shared Library:

          ./src/lib/Test1.groovy
          package lib
          
          class Test1 implements Serializable {
          
              def script
          
              def print() {
                  script.echo "print 1"
              }
          }
          ./src/lib/Test2.groovy
          package lib
          
          class Test2 extends Test1 {
          
              def print() {
                  script.echo "print 2"
                  super.print()
              }
          }

          Project:

          ./Jenkinsfile
          @Library('my-library') _
          
          import lib.Test2
          
          def test = new Test2( script: this )
          test.print()

          Expected Output:

          print 2
          print 1

          Got Output:

          print 2
          print 2
          print 2
          print 2
          print 2
          print 2
          print 2
          ...

          This ends up into an infinite loop. The print method from class Test1 is never called.

          But if i put the classes from the lib into the Jenkinsfile, all is working fine:

          Project:

          ./Jenkinsfile
          class Test1 implements Serializable {
          
              def script
          
              def print() {
                  script.echo "print 1"
              }
          }
          
          class Test2 extends Test1 {
          
              def print() {
                  script.echo "print 2"
                  super.print()
              }
          }
          
          def test = new Test2( script: this )
          test.print()

          Output:

          print 2
          print 1

          It works also if i add a @NonCPS annotation to the print method of both library classes. But this is not a workaround for me because i have to call some steps from these methods.

          Benjamin Fischer added a comment - I have a similar issue. You can reproduce it with the following simple example: Shared Library: ./src/lib/Test1.groovy package lib class Test1 implements Serializable { def script def print() { script.echo "print 1" } } ./src/lib/Test2.groovy package lib class Test2 extends Test1 { def print() { script.echo "print 2" super .print() } } Project: ./Jenkinsfile @Library( 'my-library' ) _ import lib.Test2 def test = new Test2( script: this ) test.print() Expected Output: print 2 print 1 Got Output: print 2 print 2 print 2 print 2 print 2 print 2 print 2 ... This ends up into an infinite loop. The print  method from class Test1  is never called. But if i put the classes from the lib into the Jenkinsfile , all is working fine: Project: ./Jenkinsfile class Test1 implements Serializable { def script def print() { script.echo "print 1" } } class Test2 extends Test1 { def print() { script.echo "print 2" super .print() } } def test = new Test2( script: this ) test.print() Output: print 2 print 1 It works also if i add a @NonCPS  annotation to the print method of both library classes. But this is not a workaround for me because i have to call some steps from these methods.

          Sam Van Oort added a comment -

          abayer Please could you give this one a look? It sounds up your alley.

          Sam Van Oort added a comment - abayer Please could you give this one a look? It sounds up your alley.

          Andrew Bayer added a comment -

          Yup, it's on my list.

          Andrew Bayer added a comment - Yup, it's on my list.

          Stuart Rowe added a comment -

          This appears to be the same as the issue I described in JENKINS-52395.

          Stuart Rowe added a comment - This appears to be the same as the issue I described in  JENKINS-52395 .

            Unassigned Unassigned
            trueconf_kiryanov Alexey Kiryanov
            Votes:
            2 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: