Skip to content
This repository has been archived by the owner on Nov 5, 2022. It is now read-only.

CCE when using a GString with a dynamic method pointer #93

Closed
haridsv opened this issue Sep 7, 2018 · 3 comments · Fixed by jenkinsci/workflow-cps-plugin#614
Closed

Comments

@haridsv
Copy link

haridsv commented Sep 7, 2018

When using a GString to resolve a method pointer, I am getting the below CCE:

java.lang.ClassCastException: org.codehaus.groovy.runtime.GStringImpl cannot be cast to java.lang.String
	at com.cloudbees.groovy.cps.impl.MethodPointerBlock$ContinuationImpl.done(MethodPointerBlock.java:68)
	at sun.reflect.GeneratedMethodAccessor3870.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:103)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
	at sun.reflect.GeneratedMethodAccessor209.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
	at WorkflowScript.run(WorkflowScript:50)
	at ___cps.transform___(Native Method)
	at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:60)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
	at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82)
	at sun.reflect.GeneratedMethodAccessor209.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	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:174)
	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
	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:163)
	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34)
	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59)
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58)
	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
	at java.util.concurrent.FutureTask.run(Unknown Source)
	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(Unknown Source)
	at java.util.concurrent.FutureTask.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Finished: FAILURE

To reproduce, all you need to do is to get a pointer using the obj.&"$method_name" syntax, e.g., if you have a vars/test.groovy that looks like this:

def msg() {
    echo "Hello!"
}

try the below from Jenkinsfile:

def action = 'msg'
def c = test.&"$action"
c()

As a workaround, I was able to call toString() on the GString, so for the above code to work, change it to def c = test.&("$action.toString())"

@orgi
Copy link

orgi commented Oct 23, 2018

I assume the workaround should have been. At least this works for me:

def c = test.&("$action".toString())

@dwnusbaum
Copy link
Member

I reproduced this. A patch like the following against jenkinsci/workflow-cps-plugin#612 seems to fix the issue:

diff --git a/lib/src/main/java/com/cloudbees/groovy/cps/impl/MethodPointerBlock.java b/lib/src/main/java/com/cloudbees/groovy/cps/impl/MethodPointerBlock.java
index 0aabad62..de033e1c 100644
--- a/lib/src/main/java/com/cloudbees/groovy/cps/impl/MethodPointerBlock.java
+++ b/lib/src/main/java/com/cloudbees/groovy/cps/impl/MethodPointerBlock.java
@@ -7,6 +7,7 @@ import com.cloudbees.groovy.cps.Next;
 import com.cloudbees.groovy.cps.sandbox.CallSiteTag;
 import com.cloudbees.groovy.cps.sandbox.Invoker;
 import edu.umd.cs.findbugs.annotations.NonNull;
+import groovy.lang.GString;
 import java.util.Collection;
 import java.util.Collections;
 import org.codehaus.groovy.runtime.InvokerHelper;
@@ -64,6 +65,9 @@ public class MethodPointerBlock implements CallSiteBlock {
          * Obtain a method pointer, which is really just a {@link MethodClosure}.
          */
         public Next done(Object methodName) {
+            if (methodName instanceof GString) {
+                methodName = methodName.toString();
+            }
             return k.receive(e.getInvoker().contextualize(MethodPointerBlock.this).methodPointer(lhs, (String)methodName));
         }
 
diff --git a/lib/src/test/java/com/cloudbees/groovy/cps/sandbox/SandboxInvokerTest.java b/lib/src/test/java/com/cloudbees/groovy/cps/sandbox/SandboxInvokerTest.java
index 3848bd36..9a374ec1 100644
--- a/lib/src/test/java/com/cloudbees/groovy/cps/sandbox/SandboxInvokerTest.java
+++ b/lib/src/test/java/com/cloudbees/groovy/cps/sandbox/SandboxInvokerTest.java
@@ -671,4 +671,19 @@ public class SandboxInvokerTest extends AbstractGroovyCpsTest {
                 "LinkedHashMap.asBoolean()");
     }
 
+    @Test public void dynamicMethodPointer() throws Throwable {
+        assertIntercept(
+                "def method3() {\n" +
+                "    true\n" +
+                "}\n" +
+                "def mp = this.&/method${1 + 2}/\n" +
+                "mp()",
+                true,
+                "Script1.super(Script1).setBinding(Binding)",
+                "Integer.plus(Integer)",
+                "new GStringImpl(Object[],String[])",
+                "SandboxedMethodClosure.call()",
+                "Script1.method3()");
+    }
+
 }

I will think about this a bit and either file an issue on https://issues.jenkins.io/ or open a PR with the fix.

@dwnusbaum
Copy link
Member

I am closing this, see jenkinsci/workflow-cps-plugin#614.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
3 participants