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

Varargs call to sprintf() from static field throws MissingMethodException after plugins upgrade

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • script-security-plugin
    • None
    • Pipeline - December

      After upgrading my local dev Jenkins instance core and plugins, calling sprintf() with varargs from the initial value of a static field throws the following exception. (Running in sandbox mode.):

      hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.lang.Class.sprintf() is applicable for argument types: (java.lang.String, java.lang.String, java.lang.String) values: [Hello all you %s out there in %s, developers, the Jenkins World]
      Possible solutions: sprintf(java.lang.String, java.lang.Object), sprintf(java.lang.String, [Ljava.lang.Object;), printf(java.lang.String, [Ljava.lang.Object;), printf(java.lang.String, java.lang.Object), println(), print(java.io.PrintWriter)
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:121)
      	at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:153)
      	at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:157)
      	at org.kohsuke.groovy.sandbox.impl.Checker$checkedCall$2.callStatic(Unknown Source)
      	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194)
      	at ConstantsBoom.<clinit>(WorkflowScript:26)
      	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:93)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
      	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1855)
      	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3758)
      	at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:177)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:456)
      	at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:284)
      	at org.kohsuke.groovy.sandbox.GroovyInterceptor.onGetProperty(GroovyInterceptor.java:68)
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:334)
      	at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:282)
      	at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:286)
      	at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
      	at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
      Caused: hudson.remoting.ProxyException: java.lang.ExceptionInInitializerError
      	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:93)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
      	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1855)
      	at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3758)
      	at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:177)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getProperty(ScriptBytecodeAdapter.java:456)
      	at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:284)
      	at org.kohsuke.groovy.sandbox.GroovyInterceptor.onGetProperty(GroovyInterceptor.java:68)
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:334)
      	at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:282)
      	at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:286)
      	at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
      	at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
      	at WorkflowScript.run(WorkflowScript:48)
      	at ___cps.transform___(Native Method)
      	at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
      	at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
      	at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
      	at sun.reflect.GeneratedMethodAccessor365.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	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:83)
      	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:173)
      	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:162)
      	at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
      	at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
      	at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:162)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:19)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:35)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:32)
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:32)
      	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:330)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:82)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:242)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:230)
      	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
      	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
      	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      	at java.lang.Thread.run(Thread.java:748)
      

      A script to reproduce, along with a few control tests that do not throw the exception, is:

      class ConstantsControl {
        static HOWDY_FOLKS_FMT = 'Good day %s wherever you are in %s'
        
        //two args; last presumably autocasted to Object[]
        static HOWDY_INDUSTRIOUS_ENGINEERS = sprintf(
          HOWDY_FOLKS_FMT,
          [
            'engineers',
            'the world',
          ],
        )
      
        //3 args; variadic call String, Object...; last autocasted to Object[]
        String greeting = sprintf(
          HOWDY_FOLKS_FMT,
          'friends',
          'CI land',
        )
      }
      
      class ConstantsBoom {
        static HOWDY_FOLKS_FMT = 'Hello all you %s out there in %s'
        
        //MissingMethodException as below
        static HOWDY_JENKINS_DEVS = sprintf(
          HOWDY_FOLKS_FMT,
          'developers',
          'the Jenkins World',
        )
      }
      
      //Production: script-security 1.29 + workflow-cps 2.36
      //Local: script-security 1.31 + workflow-cps 2.39
      //
      //(control tests); no exceptions in either Jenkins instance
      echo ConstantsControl.HOWDY_INDUSTRIOUS_ENGINEERS
      
      cc = new ConstantsControl()
      echo cc.greeting
      
      //Production: script-security 1.29 + workflow-cps 2.36
      //no exception
      //
      //Local: script-security 1.31 + workflow-cps 2.39
      //hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No 
      //signature of method: java.lang.Class.sprintf() is applicable for argument 
      //types: (java.lang.String, java.lang.String, java.lang.String) ...
      echo ConstantsBoom.HOWDY_JENKINS_DEVS
      

      As noted in the comments the variadic call in the static field works fine in the older production instance, and the variadic call in the instance field works fine in both instances. Plus there's the workaround of passing an ArrayList. The <clinit> context makes me wonder if this is similar to the recent issues with static initializers and final fields, but that's just a guess.

          [JENKINS-46213] Varargs call to sprintf() from static field throws MissingMethodException after plugins upgrade

          Brian Ray created issue -

          Brian Ray added a comment -

          Note: The two plugins listings in the Attachments are nonexhaustive. Just limited them to Pipeline and Script Security given the nature of the issue.

          Brian Ray added a comment - Note: The two plugins listings in the Attachments are nonexhaustive. Just limited them to Pipeline and Script Security given the nature of the issue.
          Andrew Bayer made changes -
          Component/s Original: script-security-plugin [ 18520 ]
          Andrew Bayer made changes -
          Assignee New: Andrew Bayer [ abayer ]
          Andrew Bayer made changes -
          Status Original: Open [ 1 ] New: In Progress [ 3 ]

          Andrew Bayer added a comment -

          I've narrowed this down to workflow-cps - I can reproduce the error there but not in a non-Pipeline sandboxed Groovy script. Will investigate further.

          Andrew Bayer added a comment - I've narrowed this down to workflow-cps - I can reproduce the error there but not in a non-Pipeline sandboxed Groovy script. Will investigate further.

          Andrew Bayer added a comment -

          Noting for myself as I dig into this tomorrow/Friday - I've determined this was caused by the move to groovy-cps 1.17 and script-security 1.30 (with groovy-sandbox 1.12). Exactly what in there is causing the problem, I'm not sure yet, but will keep looking.

          Andrew Bayer added a comment - Noting for myself as I dig into this tomorrow/Friday - I've determined this was caused by the move to groovy-cps 1.17 and script-security 1.30 (with groovy-sandbox 1.12). Exactly what in there is causing the problem, I'm not sure yet, but will keep looking.

          Brian Ray added a comment - - edited

          Excellent, thanks for digging into this. In the meantime it was easy enough for me to sweep our pipeline repos and bracket those variadic args to get me over the blocker. And I ran across some older code in which I'd had to do the same thing. It's interesting that the error has manifested consistently inconsistently in different contexts over time.

          Brian Ray added a comment - - edited Excellent, thanks for digging into this. In the meantime it was easy enough for me to sweep our pipeline repos and bracket those variadic args to get me over the blocker. And I ran across some older code in which I'd had to do the same thing. It's interesting that the error has manifested consistently inconsistently in different contexts over time.

          Andrew Bayer added a comment -

          Grr, running into weirdness due to sprintf not being whitelisted for some tests. Any chance you've got a version of this with another method call?

          Andrew Bayer added a comment - Grr, running into weirdness due to sprintf not being whitelisted for some tests. Any chance you've got a version of this with another method call?

          Andrew Bayer added a comment -

          Ha, that actually revealed something - when I disable sandbox, it works fine. So it's definitely a problem with sandboxing. I'm just confused as to why I couldn't reproduce this in groovy-cps directly...more experiments needed!

          Andrew Bayer added a comment - Ha, that actually revealed something - when I disable sandbox, it works fine. So it's definitely a problem with sandboxing. I'm just confused as to why I couldn't reproduce this in groovy-cps directly...more experiments needed!

            abayer Andrew Bayer
            brianeray Brian Ray
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: