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

unclassified new org.codehaus.groovy.runtime.GStringImpl java.lang.String java.lang.String[]

      Defining and running a workflow, from a Groovy CPS DSL from SCM with this repo:
      https://github.com/witokondoria/jenkins-workflow-issues, branch master and script path test.groovy throws an exception:

      org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified new org.codehaus.groovy.runtime.GStringImpl java.lang.String java.lang.String[]
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onNewInstance(SandboxInterceptor.java:84)
      	at org.kohsuke.groovy.sandbox.impl.Checker$3.call(Checker.java:126)
      	at org.kohsuke.groovy.sandbox.impl.Checker.checkedConstructor(Checker.java:123)
      	at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.constructorCall(SandboxInvoker.java:19)
      	at Script1.startServices(Script1.groovy:20)
      	at WorkflowScript.run(WorkflowScript:24)
      	at Unknown.Unknown(Unknown)
      	at ___cps.transform___(Native Method)
      	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:90)
      	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:76)
      	at sun.reflect.GeneratedMethodAccessor93.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
      	at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:71)
      	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:100)
      	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:76)
      	at sun.reflect.GeneratedMethodAccessor93.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	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.SandboxContinuable.access$001(SandboxContinuable.java:19)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:33)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:30)
      	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:106)
      	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:30)
      	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:268)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$000(CpsThreadGroup.java:71)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:177)
      	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:175)
      	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:47)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
      	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:111)
      	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
      	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
      	at java.lang.Thread.run(Thread.java:745)
      

          [JENKINS-27306] unclassified new org.codehaus.groovy.runtime.GStringImpl java.lang.String java.lang.String[]

          Ryan Fox added a comment -

          I saw this:

          org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified field groovy.util.Node project

          Ryan Fox added a comment - I saw this: org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified field groovy.util.Node project

          James Sandlin added a comment - - edited

          can't use join

          org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified method java.lang.String[] join

          James Sandlin added a comment - - edited can't use join org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified method java.lang. String [] join

          Leandro Ribeiro added a comment - - edited

          The same as the one reported by Ryan Fox:

          org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified field groovy.util.Node version

          (trying to read the tag "version" from a xml file).

          Env:
          Jenkins 2.10
          Pipeline plugin 2.2
          Script Security plugin 1.21

          Leandro Ribeiro added a comment - - edited The same as the one reported by Ryan Fox: org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified field groovy.util.Node version (trying to read the tag "version" from a xml file). Env: Jenkins 2.10 Pipeline plugin 2.2 Script Security plugin 1.21

          org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified method hudson.scm.SubversionChangeLogSet getMsg

          Jenkins 2.28
          Script Security plugin 1.24

          Lionel Orellana added a comment - org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified method hudson.scm.SubversionChangeLogSet getMsg Jenkins 2.28 Script Security plugin 1.24

          Jesse Glick added a comment -

          Many of these are likely to be unrelated issues. There are numerous reasons why an “unclassified method” error can be thrown, due to different vagaries of Groovy semantics which are not properly handled.

          Jesse Glick added a comment - Many of these are likely to be unrelated issues. There are numerous reasons why an “unclassified method” error can be thrown, due to different vagaries of Groovy semantics which are not properly handled.

          Andrew Bayer added a comment -

          So the original error here is because of the following:

          lib.KAFKAIMG = ['KAFKAIP', 'kafka:0.8.1.1', 1, "--env \"ZK_CONNECT=${-> lib.IPS['ZKIP']}:2181\" "]
          

          Specifically, referencing lib.KAFKAIMG[2] inside a GString itself is where things blow up. This is because something's going wrong with the nested lazy GString. Here's a more minimal reproduction case:

          def foo = "foo"
          def bar = "ha ${ -> foo } ha"
          echo "hee ${bar} hee"
          

          I'm not yet sure what inside the sandbox code is at fault here (or if it's actually somewhere off in CPS transformation), but hey, more info is useful.

          Andrew Bayer added a comment - So the original error here is because of the following: lib.KAFKAIMG = [ 'KAFKAIP' , 'kafka:0.8.1.1' , 1, "--env \" ZK_CONNECT=${-> lib.IPS[ 'ZKIP' ]}:2181\ " " ] Specifically, referencing lib.KAFKAIMG [2] inside a GString itself is where things blow up. This is because something's going wrong with the nested lazy GString . Here's a more minimal reproduction case: def foo = "foo" def bar = "ha ${ -> foo } ha" echo "hee ${bar} hee" I'm not yet sure what inside the sandbox code is at fault here (or if it's actually somewhere off in CPS transformation), but hey, more info is useful.

          Andrew Bayer added a comment -

          It's CPS - same thing works fine in a script-security test, and when not sandboxed in a Pipeline job, fails with groovy.lang.GroovyRuntimeException: Could not find matching constructor for: org.codehaus.groovy.runtime.GStringImpl(java.lang.String, [Ljava.lang.String.

          Andrew Bayer added a comment - It's CPS - same thing works fine in a script-security test, and when not sandboxed in a Pipeline job, fails with groovy.lang.GroovyRuntimeException: Could not find matching constructor for: org.codehaus.groovy.runtime.GStringImpl(java.lang.String, [Ljava.lang.String .

          Andrew Bayer added a comment - - edited

          And found it - well, found the problem, not yet a solution.

          GString#writeTo(Writer) will end up calling InvokerHelper.write(out, c.call()) if the GString replacement value is a Closure - i.e., "in a GString ${ -> thisPart} is a Closure with the -> included". That results in a CpsClosure being created and a CpsCallableInvocation getting thrown when GString#writeTo(Writer) is called. What we'd want there is to have that CpsCallableInvocation caught properly and handled by the CPS runtime, but because it's getting thrown within the GString internals, that's not happening.

          So what, if anything, can be done about this? Well, there's an easy way to work around it for users - don't do "closures ${ -> inside } GStrings" - just do "this ${instead}.". Lazy evaluation is nice but not if it, y'know, breaks all the things. =) But in terms of actually making lazy closures inside a GString work properly? Not sure yet if that's possible. It probably would require overriding GStringImpl with our own implementation of GString#writeTo(Writer), I think? Probably not worth doing...it might make more sense to error out with a useful message if we see this sort of scenario.

          Also worth noting - the following:

          def foo = "foo"
          echo "ha ${ -> foo } ha"
          

          will barf out with a CpsCallableInvocation directly. I'm pretty sure that the more complex scenario of a nested reference is giving the unclassified error because the CpsCallableInvocation from inside is mucking up the call to new GStringImpl.

          Andrew Bayer added a comment - - edited And found it - well, found the problem, not yet a solution. GString#writeTo(Writer) will end up calling InvokerHelper.write(out, c.call()) if the GString replacement value is a Closure - i.e., "in a GString ${ -> thisPart} is a Closure with the -> included" . That results in a CpsClosure being created and a CpsCallableInvocation getting thrown when GString#writeTo(Writer) is called. What we'd want there is to have that CpsCallableInvocation caught properly and handled by the CPS runtime, but because it's getting thrown within the GString internals, that's not happening. So what, if anything, can be done about this? Well, there's an easy way to work around it for users - don't do "closures ${ -> inside } GStrings" - just do "this ${instead}." . Lazy evaluation is nice but not if it, y'know, breaks all the things. =) But in terms of actually making lazy closures inside a GString work properly? Not sure yet if that's possible. It probably would require overriding GStringImpl with our own implementation of GString#writeTo(Writer) , I think? Probably not worth doing...it might make more sense to error out with a useful message if we see this sort of scenario. Also worth noting - the following: def foo = "foo" echo "ha ${ -> foo } ha" will barf out with a CpsCallableInvocation directly. I'm pretty sure that the more complex scenario of a nested reference is giving the unclassified error because the CpsCallableInvocation from inside is mucking up the call to new GStringImpl .

          The fact of using a lazy evaluation (at the initial use case) was due first variable not being initialized on its definition, but at a later stage.

          My hacky fix, it someone needs it, was to reimplemtent the GStringImpl.toString method (creating a string from the GString strings and values) and providing that reimplementation on a NonCPS method

          Javier Delgado added a comment - The fact of using a lazy evaluation (at the initial use case) was due first variable not being initialized on its definition, but at a later stage. My hacky fix, it someone needs it, was to reimplemtent the GStringImpl.toString method (creating a string from the GString strings and values) and providing that reimplementation on a NonCPS method

          Jesse Glick added a comment -

          I see no reason to try to support closures (lazy interpolation) inside a GString. This obscure Groovy feature can be easily replaced by the more straightforward idiom of defining a closure which returns a GString constructed using eager interpolation. So I am treating this as a duplicate of JENKINS-31314: the attempt to use this idiom ought to fail with a clear diagnostic message.

          Jesse Glick added a comment - I see no reason to try to support closures (lazy interpolation) inside a GString . This obscure Groovy feature can be easily replaced by the more straightforward idiom of defining a closure which returns a GString constructed using eager interpolation. So I am treating this as a duplicate of JENKINS-31314 : the attempt to use this idiom ought to fail with a clear diagnostic message.

            abayer Andrew Bayer
            witokondoria Javier Delgado
            Votes:
            7 Vote for this issue
            Watchers:
            14 Start watching this issue

              Created:
              Updated:
              Resolved: