jenkinsci / groovy-sandbox

(Deprecated) Compile-time transformer to run Groovy code in a restrictive sandbox
MIT License
123 stars 60 forks source link

BUG! exception in phase 'canonicalization': NPE in SandboxTransformer #99

Closed mguillem closed 1 year ago

mguillem commented 1 year ago

Jenkins and plugins versions report

Exception parsing Jenkinsfile. The problem has been isolated in a small unit test (below). This is a regression: our Jenkinsfile have been working successfully until this change two months ago.

What Operating System are you using (both controller, and any agents involved in the problem)?

doesn't matter

Reproduction steps

Add following test to SandboxTransformerTest and execute it:

    @Test
    public void bugExceptionInCanonicalization() throws Exception {
        String script = "@groovy.transform.Field\n"
                + "private static final MY_MAP = [\n"
                + "    myKey: { changedFiles -> changedFiles.any {\n"
                + "            return it == 'foo.txt'\n"
                + "        }\n"
                + "    }\n"
                + "]";
        sandboxedSh.evaluate(script);
    }

Expected Results

a green unit test

Actual Results

Following exception:

BUG! exception in phase 'canonicalization' in source unit 'Script1.groovy' unexpected NullpointerException
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1092)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:624)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:602)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:579)
    at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:323)
    at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:293)
    at groovy.lang.GroovyShell.parseClass(GroovyShell.java:677)
    at groovy.lang.GroovyShell.parse(GroovyShell.java:689)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:573)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:612)
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:583)
    at org.kohsuke.groovy.sandbox.SandboxTransformerTest.foo0(SandboxTransformerTest.java:1116)
    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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.rules.Verifier$1.evaluate(Verifier.java:35)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:768)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.NullPointerException
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.visitReturnStatement(SandboxTransformer.java:411)
    at org.codehaus.groovy.ast.stmt.ReturnStatement.visit(ReturnStatement.java:49)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:88)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166)
    at org.kohsuke.groovy.sandbox.ScopeTrackingClassCodeExpressionTransformer.visitBlockStatement(ScopeTrackingClassCodeExpressionTransformer.java:71)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.innerTransform(SandboxTransformer.java:502)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.transform(SandboxTransformer.java:469)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.transformArguments(SandboxTransformer.java:436)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.innerTransform(SandboxTransformer.java:523)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.transform(SandboxTransformer.java:469)
    at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement(ClassCodeExpressionTransformer.java:144)
    at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:42)
    at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:88)
    at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166)
    at org.kohsuke.groovy.sandbox.ScopeTrackingClassCodeExpressionTransformer.visitBlockStatement(ScopeTrackingClassCodeExpressionTransformer.java:71)
    at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.innerTransform(SandboxTransformer.java:502)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.transform(SandboxTransformer.java:469)
    at org.codehaus.groovy.ast.expr.MapEntryExpression.transformExpression(MapEntryExpression.java:43)
    at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.transform(ClassCodeExpressionTransformer.java:90)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.innerTransform(SandboxTransformer.java:833)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.transform(SandboxTransformer.java:469)
    at org.codehaus.groovy.ast.expr.Expression.transformExpressions(Expression.java:65)
    at org.codehaus.groovy.ast.expr.MapExpression.transformExpression(MapExpression.java:63)
    at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.transform(ClassCodeExpressionTransformer.java:90)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.innerTransform(SandboxTransformer.java:833)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.transform(SandboxTransformer.java:469)
    at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitField(ClassCodeExpressionTransformer.java:70)
    at org.kohsuke.groovy.sandbox.ScopeTrackingClassCodeExpressionTransformer.visitField(ScopeTrackingClassCodeExpressionTransformer.java:64)
    at org.kohsuke.groovy.sandbox.SandboxTransformer$VisitorImpl.visitField(SandboxTransformer.java:416)
    at org.kohsuke.groovy.sandbox.SandboxTransformer.call(SandboxTransformer.java:156)
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1087)
    ... 39 more

Anything else?

The problem has probably been introduced in commit 520243213bcd8c81322e8e683daa8d555bb4f484 https://github.com/jenkinsci/groovy-sandbox/commit/520243213bcd8c81322e8e683daa8d555bb4f484#diff-2de07a9b073d0d81f913c248e08a99a237aec811fb3d54ee32a76bb4d8bb9abbR411

The unit test is working at revision 74d3a4efec72cc4e4e2d7a236936873c732cddc8.

A simple workaround consist in initializing the map with an empty map and to assign a value later.

dwnusbaum commented 1 year ago

Thanks for the bug report, and especially for the reproduction steps! See https://github.com/jenkinsci/groovy-sandbox/pull/100 for a fix.

mguillem commented 1 year ago

@dwnusbaum this was really fast! Thanks!

dwnusbaum commented 1 year ago

The fix was ultimately released in Script Security plugin version 1228.vd93135a_2fb_25.