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

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

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      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)
      

        Attachments

          Issue Links

            Activity

            Hide
            jglick 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.

            Show
            jglick 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.
            Hide
            abayer 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.

            Show
            abayer 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.
            Hide
            abayer 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.

            Show
            abayer 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 .
            Hide
            abayer 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.

            Show
            abayer 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 .
            Hide
            witokondoria 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

            Show
            witokondoria 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

              People

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

                Dates

                • Created:
                  Updated: