https://issues.apache.org/bugzilla/show_bug.cgi?id=57341
Bug ID: 57341 Summary: JUnitReport task causes OutOfMemoryError/StackOverflowError at junit_frames.br$dash$replace() Product: Ant Version: 1.9.4 Hardware: PC Status: NEW Severity: critical Priority: P2 Component: AntUnit Assignee: notifications@ant.apache.org Reporter: ryan.benn...@the-logic-group.com While performing a JUnitReport task, our build server started consistently reporting Stack Overflow errors: build.xml:773: The following error occurred while executing this line: build.xml:923: java.lang.StackOverflowError at com.sun.org.apache.xml.internal.serializer.ToStream.processDirty(ToStream.java:1571) at com.sun.org.apache.xml.internal.serializer.ToStream.characters(ToStream.java:1489) at com.sun.org.apache.xml.internal.serializer.ToHTMLStream.characters(ToHTMLStream.java:1529) at com.sun.org.apache.xml.internal.serializer.ToStream.characters(ToStream.java:1614) at com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.characters(AbstractTranslet.java:621) at junit_frames.br$dash$replace() at junit_frames.br$dash$replace() at junit_frames.br$dash$replace() ... at junit_frames.br$dash$replace() x1000 I tested locally and got a slightly different result: build.xml:923: java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:2694) at java.lang.String.<init>(String.java:203) at java.lang.String.substring(String.java:1877) at com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary.substring_afterF(BasisLibrary.java:329) at junit_frames.br$dash$replace() at junit_frames.br$dash$replace() at junit_frames.br$dash$replace() ... at junit_frames.br$dash$replace() x1000 Monitoring the build on my workstation, Java Mission Control showed the memory spiking to over 1.47GB before I got the out of memory error. I had a look at the br-replace template in the $ANT_HOME/etc/junit-frames.xsl and $ANT_HOME/etc/junit-noframes.xsl files and it is performing a recursive replace of line returns one by one, so as soon as you perform a br-replace on a file with more line returns than your stack limit, you're going to get this error, unless you run out of memory first. I managed to reimplement the br-replace template to be less stack/heap intensive. After trying unsuccessfully to use the java String.replace/replaceAll and StringUtils.replace functions that are used elsewhere (which seem to have issues, possibly JVM dependent) I went for a plain XSLT 1.0 implementation using a binary-subdivision approach that splits the string approximately evenly on the nearest line break on large strings: <xsl:template name="br-replace"> <xsl:param name="word"/> <xsl:param name="splitlimit">32</xsl:param> <xsl:variable name="secondhalflen" select="(string-length($word)+(string-length($word) mod 2)) div 2"/> <xsl:variable name="secondhalfword" select="substring($word, $secondhalflen)"/> <!-- When word is very big, a recursive replace is very heap/stack expensive, so subdivide on line break after middle of string --> <xsl:choose> <xsl:when test="(string-length($word) > $splitlimit) and (contains($secondhalfword, '
'))"> <xsl:variable name="secondhalfend" select="substring-after($secondhalfword, '
')"/> <xsl:variable name="firsthalflen" select="string-length($word) - $secondhalflen"/> <xsl:variable name="firsthalfword" select="substring($word, 1, $firsthalflen)"/> <xsl:variable name="firsthalfend" select="substring-before($secondhalfword, '
')"/> <xsl:call-template name="br-replace"> <xsl:with-param name="word" select="concat($firsthalfword,$firsthalfend)"/> </xsl:call-template> <br/> <xsl:call-template name="br-replace"> <xsl:with-param name="word" select="$secondhalfend"/> </xsl:call-template> </xsl:when> <xsl:when test="contains($word, '
')"> <xsl:value-of select="substring-before($word, '
')"/> <br/> <xsl:call-template name="br-replace"> <xsl:with-param name="word" select="substring-after($word, '
')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$word"/> </xsl:otherwise> </xsl:choose> </xsl:template> This implementation is much more heap/stack friendly. JMC only reported a peak of 621MB, compared to the 1.47GB it hit before overflowing. -- You are receiving this mail because: You are the assignee for the bug.