[JIRA] (JENKINS-57085) Stack Traces with complex file names cannot be deserialized by XStream

2 views
Skip to first unread message

dnusbaum@cloudbees.com (JIRA)

unread,
Apr 17, 2019, 9:48:02 AM4/17/19
to jenkinsc...@googlegroups.com
Devin Nusbaum created an issue
 
Jenkins / Bug JENKINS-57085
Stack Traces with complex file names cannot be deserialized by XStream
Issue Type: Bug Bug
Assignee: Unassigned
Components: core
Created: 2019-04-17 13:47
Labels: pipeline
Priority: Minor Minor
Reporter: Devin Nusbaum

Not sure about component, might be groovy-cps, might be upstream Groovy, might be upstream XStream, but nice to have tracking ticket here anyway. Marked as core for now assuming we'd need to backport a fix from some upstream library.

Problem:

If XStream is used to deserialize a StackTraceElement containing a complex file name, such as the following one seen in a stack trace in a Declarative Pipeline, the exception will be unable to be deserialized:

org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/Users/dnusbaum/.m2/repository/org/jenkinsci/plugins/pipeline-model-definition/1.3.7/pipeline-model-definition-1.3.7.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)

The file name for this example is:

jar:file:/Users/dnusbaum/.m2/repository/org/jenkinsci/plugins/pipeline-model-definition/1.3.7/pipeline-model-definition-1.3.7.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy

Example exception:

com.thoughtworks.xstream.converters.ConversionException: Could not parse StackTraceElement : org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/Users/dnusbaum/.m2/repository/org/jenkinsci/plugins/pipeline-model-definition/1.3.7/pipeline-model-definition-1.3.7.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)
---- Debugging information ----
class               : java.lang.StackTraceElement
required-type       : java.lang.StackTraceElement
converter-type      : com.thoughtworks.xstream.converters.SingleValueConverterWrapper
wrapped-converter   : com.thoughtworks.xstream.converters.extended.StackTraceElementConverter
path                : /Tag/actions/wf.a.ErrorAction/error/stackTrace/trace[26]
line number         : 46
class[1]            : [Ljava.lang.StackTraceElement;
converter-type[1]   : com.thoughtworks.xstream.converters.collections.ArrayConverter
class[2]            : hudson.AbortException
converter-type[2]   : com.thoughtworks.xstream.converters.extended.ThrowableConverter
class[3]            : org.jenkinsci.plugins.workflow.actions.ErrorAction
converter-type[3]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
class[4]            : [Lhudson.model.Action;
class[5]            : org.jenkinsci.plugins.workflow.support.storage.SimpleXStreamFlowNodeStorage$Tag
version             : 1.4.7-jenkins-1
-------------------------------
	at com.thoughtworks.xstream.converters.extended.StackTraceElementConverter.fromString(StackTraceElementConverter.java:93)
	at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.fromString(SingleValueConverterWrapper.java:41)
	at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.unmarshal(SingleValueConverterWrapper.java:49)

The reason this happens is that XStream uses a regex to extract the file name from the serialized format, and that regex assumes the file name does not contain a colon. However, in some cases stack traces for Groovy code contain the full path to the jar. I am not yet sure exactly why this is. CompilationUnit.java appears to have fixed this exact issue 14 years ago, but perhaps this is specific to MethodLocation in groovy-cps. Here is an excerpt of the serialized stack trace in case it helps identify the source of the file name:

...
<trace>WorkflowScript.run(WorkflowScript:14)</trace>
<trace>org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/Users/dnusbaum/Projects/pipeline-graph-analysis-plugin/work/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)</trace>
...
<trace>org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(jar:file:/Users/dnusbaum/Projects/pipeline-graph-analysis-plugin/work/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:248)</trace>
<trace>___cps.transform___(Native Method)</trace>
<trace>com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)</trace>
...
<trace>org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:182)</trace>

Impact:

I first noticed this for a Declarative Pipeline, and the effect was that actions for FlowNodes failed to be deserialized after restarting Jenkins, so RobustReflectionConverter just nulled out the actions, which changed the visualization of the Pipeline in Blue Ocean because ErrorActions were no longer present on the nodes, so stages that actually failed were displayed as successful.

I imagine there could be other similar issues for restarted Pipelines. I have only encountered stack traces with these kinds of file names in Declarative Pipelines, but perhaps non-Pipeline code could be affected by the same issue.

Solution

This could be fixed with a patch to XStream like this, but I think it would be better to figure out what code is emitting these stack traces in the first place and modify that code in a similar way to https://github.com/apache/groovy/commit/4c42d503f6592c6ecc511c30bb49599316a937ff, unless displaying these kinds of file names in stack traces is normal in other contexts as well.

Add Comment Add Comment
 
This message was sent by Atlassian Jira (v7.11.2#711002-sha1:fdc329d)

dnusbaum@cloudbees.com (JIRA)

unread,
Apr 17, 2019, 11:10:02 AM4/17/19
to jenkinsc...@googlegroups.com
Devin Nusbaum updated an issue
Change By: Devin Nusbaum
Not sure about component, might be groovy-cps, might be upstream Groovy, might be upstream XStream, but nice to have tracking ticket here anyway. Marked as core for now assuming we'd need to backport a fix from some upstream library.

*Problem:*


If XStream is used to deserialize a {{StackTraceElement}} containing a complex file name, such as the following one seen in a stack trace in a Declarative Pipeline, the exception will be unable to be deserialized:
{noformat}
org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/Users/dnusbaum/.m2/repository/org/jenkinsci/plugins/pipeline-model-definition/1.3.7/pipeline-model-definition-1.3.7.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)
{noformat}

The file name for this example is:
{noformat}
jar:file:/Users/dnusbaum/.m2/repository/org/jenkinsci/plugins/pipeline-model-definition/1.3.7/pipeline-model-definition-1.3.7.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy
{noformat}

Example exception:

{noformat}

com.thoughtworks.xstream.converters.ConversionException: Could not parse StackTraceElement : org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/Users/dnusbaum/.m2/repository/org/jenkinsci/plugins/pipeline-model-definition/1.3.7/pipeline-model-definition-1.3.7.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)
---- Debugging information ----
class               : java.lang.StackTraceElement
required-type       : java.lang.StackTraceElement
converter-type      : com.thoughtworks.xstream.converters.SingleValueConverterWrapper
wrapped-converter   : com.thoughtworks.xstream.converters.extended.StackTraceElementConverter
path                : /Tag/actions/wf.a.ErrorAction/error/stackTrace/trace[26]
line number         : 46
class[1]            : [Ljava.lang.StackTraceElement;
converter-type[1]   : com.thoughtworks.xstream.converters.collections.ArrayConverter
class[2]            : hudson.AbortException
converter-type[2]   : com.thoughtworks.xstream.converters.extended.ThrowableConverter
class[3]            : org.jenkinsci.plugins.workflow.actions.ErrorAction
converter-type[3]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
class[4]            : [Lhudson.model.Action;
class[5]            : org.jenkinsci.plugins.workflow.support.storage.SimpleXStreamFlowNodeStorage$Tag
version             : 1.4.7-jenkins-1
-------------------------------
at com.thoughtworks.xstream.converters.extended.StackTraceElementConverter.fromString(StackTraceElementConverter.java:93)
at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.fromString(SingleValueConverterWrapper.java:41)
at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.unmarshal(SingleValueConverterWrapper.java:49)
{noformat}

The reason this happens is that XStream uses a regex to extract the file name from the serialized format, and that regex assumes the file name does not contain a colon. However, in some cases stack traces for Groovy code contain the full path to the jar. I am not yet sure exactly why this is. [CompilationUnit.java|https://github.com/apache/groovy/blame/master/src/main/java/org/codehaus/groovy/control/CompilationUnit.java#L851-L852] appears to have fixed this exact issue 14 years ago, but perhaps this is specific to [MethodLocation|https://github.com/cloudbees/groovy-cps/blob/846d8d8eed10c57063d50894d2949e9a8fd21ae0/lib/src/main/java/com/cloudbees/groovy/cps/MethodLocation.java] in groovy-cps. Here is an excerpt of the serialized stack trace in case it helps identify the source of the file name:

{noformat}

...
<trace>WorkflowScript.run(WorkflowScript:14)</trace>
<trace>org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/Users/dnusbaum/Projects/pipeline-graph-analysis-plugin/work/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)</trace>
...
<trace>org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(jar:file:/Users/dnusbaum/Projects/pipeline-graph-analysis-plugin/work/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:248)</trace>
<trace>___cps.transform___(Native Method)</trace>
<trace>com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)</trace>
...
<trace>org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:182)</trace>
{noformat}

*
Reproduction Steps:*

# Start an instance of Jenkins with Blue Ocean and Declarative Pipeline installed.
# Create a new Pipeline with the following script:
{code}
pipeline {
  agent none
  stages {
    stage('Fails') {
      steps {
        error 'oops'
      }
    }
  }
}
{code}
# Run the build and view the visualization in Blue Ocean.
# Observe that the stage {{Fails}} is shown as failing.
# Restart Jenkins
# Open the visualization for the previous build.
# Observe that the stage {{Fails}} is shown as succeeding.

*
Impact:*


I first noticed this for a Declarative Pipeline, and the effect was that actions for {{FlowNodes}} failed to be deserialized after restarting Jenkins, so {{RobustReflectionConverter}} just nulled out the actions, which changed the visualization of the Pipeline in Blue Ocean because {{ErrorActions}} were no longer present on the nodes, so stages that actually failed were displayed as successful.

I imagine there could be other similar issues for restarted Pipelines. I have only encountered stack traces with these kinds of file names in Declarative Pipelines, but perhaps non-Pipeline code could be affected by the same issue.

*Solution*: 

This could be fixed with a patch to XStream like [this|https://github.com/x-stream/xstream/compare/master...dwnusbaum:stack-traces], but I think it would be better to figure out what code is emitting these stack traces in the first place and modify that code in a similar way to https://github.com/apache/groovy/commit/4c42d503f6592c6ecc511c30bb49599316a937ff, unless displaying these kinds of file names in stack traces is normal in other contexts as well.

jglick@cloudbees.com (JIRA)

unread,
Apr 23, 2019, 10:17:02 AM4/23/19
to jenkinsc...@googlegroups.com
Jesse Glick updated an issue

Offhand it sounds like groovy-cps is creating poor bytecode, and XStream is also behaving poorly. Ideally both would be fixed. Probably best to focus on groovy-cps to start with, since getting fixes into upstream XStream could take a while. (We have a fork anyway, but I would rather not add to the diff.)

Change By: Jesse Glick
Component/s: workflow-cps-plugin
Labels: pipeline xstream

jglick@cloudbees.com (JIRA)

unread,
Apr 24, 2019, 4:11:01 PM4/24/19
to jenkinsc...@googlegroups.com

jglick@cloudbees.com (JIRA)

unread,
Apr 24, 2019, 4:37:02 PM4/24/19
to jenkinsc...@googlegroups.com
Jesse Glick commented on Bug JENKINS-57085
 
Re: Stack Traces with complex file names cannot be deserialized by XStream

Filed the XStream patch to start with, since it was easy enough.

jglick@cloudbees.com (JIRA)

unread,
Apr 25, 2019, 8:09:02 AM4/25/19
to jenkinsc...@googlegroups.com
Jesse Glick started work on Bug JENKINS-57085
 
Change By: Jesse Glick
Status: Open In Progress

jglick@cloudbees.com (JIRA)

unread,
Apr 25, 2019, 9:32:02 AM4/25/19
to jenkinsc...@googlegroups.com

It is most easily visible with Declarative but not limited to that. Using

@Library('github.com/jglick/sample-pipeline-library@JENKINS-57085-diag') _
com.github.jglick.sample.Err.fail(this)

which calls

package com.github.jglick.sample
class Err {
    static void fail(script) {
        script.error 'oops'
    }
}

you can see

<wf.a.ErrorAction plugin="workfl...@2.33">
  <error class="hudson.AbortException">
    <detailMessage>oops</detailMessage>
    <stackTrace>
      <trace>org.jenkinsci.plugins.workflow.steps.ErrorStep$Execution.run(ErrorStep.java:63)</trace>
      <!-- … -->
      <trace>org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)</trace>
      <!-- … -->
      <trace>com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)</trace>
      <trace>com.github.jglick.sample.Err.fail(file:/…/jobs/p/builds/…/libs/github.com/jglick/sample-pipeline-library/src/com/github/jglick/sample/Err.groovy:4)</trace>
      <trace>WorkflowScript.run(WorkflowScript:2)</trace>
      <trace>___cps.transform___(Native Method)</trace>
      <trace>com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57)</trace>
      <!-- … -->

jglick@cloudbees.com (JIRA)

unread,
Apr 25, 2019, 10:54:02 AM4/25/19
to jenkinsc...@googlegroups.com

For SourceUnit.name to have this form seems normal:

/**
 * Initializes the SourceUnit from the specified URL.
 */
public SourceUnit(URL source, CompilerConfiguration configuration, GroovyClassLoader loader, ErrorCollector er) {
    this(source.toExternalForm(), new URLReaderSource(source, configuration), configuration, loader, er);
}

CpsTransformer.makeBuilder then compiles it into a runtime construction of a MethodLocation with a URL as its fileName, from which later a StackTraceElement would be constructed.

jglick@cloudbees.com (JIRA)

unread,
Apr 25, 2019, 12:10:31 PM4/25/19
to jenkinsc...@googlegroups.com

Solved with test in workflow-cps-global-lib, but manually confirmed that the fix also corrects stack traces for the original Declarative example. (I did not bother to go through the full reproduction case involving Blue Ocean.)

jglick@cloudbees.com (JIRA)

unread,
Apr 25, 2019, 12:10:35 PM4/25/19
to jenkinsc...@googlegroups.com

jglick@cloudbees.com (JIRA)

unread,
Apr 25, 2019, 12:11:01 PM4/25/19
to jenkinsc...@googlegroups.com
 
Re: Stack Traces with complex file names cannot be deserialized by XStream

Solved with test in workflow-cps-global-lib, but manually confirmed that the fix also corrects stack traces for the original Declarative example. (I did not bother to go through the full reproduction case involving Blue Ocean.)

dnusbaum@cloudbees.com (JIRA)

unread,
May 10, 2019, 4:31:02 PM5/10/19
to jenkinsc...@googlegroups.com
Devin Nusbaum updated Bug JENKINS-57085
 

A fix for this issue was just released in Pipeline: Groovy 2.68.

Change By: Devin Nusbaum
Status: In Review Resolved
Resolution: Fixed
Released As: workflow-cps 2.68, groovy-cps 1.27
Reply all
Reply to author
Forward
0 new messages