From 4940b6a1dd7184b695f60cd6647531ecf4df3dc4 Mon Sep 17 00:00:00 2001 From: terma Date: Tue, 11 Nov 2014 00:05:24 -0500 Subject: [PATCH 1/4] SI-4520 Tests for OOE in XML parser --- jvm/src/test/scala/scala/xml/XMLTest.scala | 47 +++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/jvm/src/test/scala/scala/xml/XMLTest.scala b/jvm/src/test/scala/scala/xml/XMLTest.scala index 201557503..25495396a 100644 --- a/jvm/src/test/scala/scala/xml/XMLTest.scala +++ b/jvm/src/test/scala/scala/xml/XMLTest.scala @@ -633,7 +633,7 @@ class XMLTestJVM { import scala.xml.parsing._ @UnitTest def dontLoop: Unit = { - val xml = " " + val xml = " " val sink = new PrintStream(new ByteArrayOutputStream()) (Console withOut sink) { (Console withErr sink) { @@ -765,4 +765,49 @@ class XMLTestJVM { val formatted = pp.format(x) assertEquals(x, XML.loadString(formatted)) } + + @UnitTest(expected = classOf[FatalError]) + def shouldThrowFatalErrorWhenCantFindRequestedXToken { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + x.xToken('b') + } + + @UnitTest(expected = classOf[FatalError]) + def shouldThrowFatalErrorWhenCantFindRequestedXCharData { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + x.xCharData + } + + @UnitTest(expected = classOf[FatalError]) + def shouldThrowFatalErrorWhenCantFindRequestedXComment { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + x.xComment + } + + @UnitTest(expected = classOf[FatalError]) + def shouldThrowFatalErrorWhenCantFindRequestedXmlProcInstr { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + x.xmlProcInstr() + } + + @Ignore("Ignored for future fix, currently throw OOE because of infinity MarkupParserCommon:66") + @UnitTest(expected = classOf[FatalError]) + def shouldThrowFatalErrorWhenCantFindRequestedXAttributeValue { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + x.xAttributeValue() + } + + @Ignore("Ignored for future fix, currently return unexpected result") + @UnitTest(expected = classOf[FatalError]) + def shouldThrowFatalErrorWhenCantFindRequestedXEntityValue { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + assertEquals("a/>", x.xEntityValue()) + } + } From 6f76dd1ce872b34596de213b37506993fe023e2b Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Sun, 15 Apr 2018 12:59:07 -0400 Subject: [PATCH 2/4] Refactor Artem Stasiuk's OOE parser tests Shorten test names and minimize string literals. --- jvm/src/test/scala/scala/xml/XMLTest.scala | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/jvm/src/test/scala/scala/xml/XMLTest.scala b/jvm/src/test/scala/scala/xml/XMLTest.scala index 25495396a..94ae21a2a 100644 --- a/jvm/src/test/scala/scala/xml/XMLTest.scala +++ b/jvm/src/test/scala/scala/xml/XMLTest.scala @@ -767,47 +767,46 @@ class XMLTestJVM { } @UnitTest(expected = classOf[FatalError]) - def shouldThrowFatalErrorWhenCantFindRequestedXToken { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) - - x.xToken('b') + def xTokenFailure { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("a"), false) + assertEquals((): Unit, x.xToken('b')) } @UnitTest(expected = classOf[FatalError]) - def shouldThrowFatalErrorWhenCantFindRequestedXCharData { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + def xCharDataFailure { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) x.xCharData } @UnitTest(expected = classOf[FatalError]) - def shouldThrowFatalErrorWhenCantFindRequestedXComment { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + def xCommentFailure { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) x.xComment } @UnitTest(expected = classOf[FatalError]) - def shouldThrowFatalErrorWhenCantFindRequestedXmlProcInstr { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + def xmlProcInstrFailure { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("aa"), false) - x.xmlProcInstr() + assertEquals(new UnprefixedAttribute("aa", Text(""), Null), x.xmlProcInstr) } @Ignore("Ignored for future fix, currently throw OOE because of infinity MarkupParserCommon:66") @UnitTest(expected = classOf[FatalError]) - def shouldThrowFatalErrorWhenCantFindRequestedXAttributeValue { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + def xAttributeValueFailure { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) - x.xAttributeValue() + x.xAttributeValue } @Ignore("Ignored for future fix, currently return unexpected result") @UnitTest(expected = classOf[FatalError]) - def shouldThrowFatalErrorWhenCantFindRequestedXEntityValue { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + def xEntityValueFailure { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) - assertEquals("a/>", x.xEntityValue()) + x.xEntityValue } } From 239e3ede2262321b476a3d6faa96f2c6d6f828c1 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Sun, 15 Apr 2018 13:12:07 -0400 Subject: [PATCH 3/4] Fix OOM in parser Add eof checks to: - MarkupParser.xEntityValue - MarkupParser.xComment - MarkupParser.systemLiteral - MarkupParser.pubidLiteral - MarkupParser.notationDecl - MarkupParserCommon.xAttributeValue - MarkupParserCommon.xTakeUntil --- jvm/src/test/scala/scala/xml/XMLTest.scala | 34 +++++++++++++------ .../scala/xml/parsing/MarkupParser.scala | 4 +-- .../xml/parsing/MarkupParserCommon.scala | 8 ++--- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/jvm/src/test/scala/scala/xml/XMLTest.scala b/jvm/src/test/scala/scala/xml/XMLTest.scala index 94ae21a2a..f8e1cdec4 100644 --- a/jvm/src/test/scala/scala/xml/XMLTest.scala +++ b/jvm/src/test/scala/scala/xml/XMLTest.scala @@ -766,8 +766,8 @@ class XMLTestJVM { assertEquals(x, XML.loadString(formatted)) } - @UnitTest(expected = classOf[FatalError]) - def xTokenFailure { + @UnitTest + def xTokenTest { val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("a"), false) assertEquals((): Unit, x.xToken('b')) } @@ -786,27 +786,39 @@ class XMLTestJVM { x.xComment } - @UnitTest(expected = classOf[FatalError]) - def xmlProcInstrFailure { + @UnitTest + def xmlProcInstrTest { val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("aa"), false) assertEquals(new UnprefixedAttribute("aa", Text(""), Null), x.xmlProcInstr) } - @Ignore("Ignored for future fix, currently throw OOE because of infinity MarkupParserCommon:66") @UnitTest(expected = classOf[FatalError]) - def xAttributeValueFailure { + def notationDeclFailure { val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) - x.xAttributeValue + x.notationDecl } - @Ignore("Ignored for future fix, currently return unexpected result") - @UnitTest(expected = classOf[FatalError]) - def xEntityValueFailure { + @UnitTest + def pubidLiteralTest { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + + assertEquals("", x.pubidLiteral) + } + + @UnitTest + def xAttributeValueTest { + val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("'"), false) + + assertEquals("", x.xAttributeValue) + } + + @UnitTest + def xEntityValueTest { val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) - x.xEntityValue + assertEquals("", x.xEntityValue) } } diff --git a/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala b/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala index 81d5b82cc..0b2f0d567 100755 --- a/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala +++ b/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala @@ -397,7 +397,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests { } else sb.append(ch) nextch() } - throw truncatedError("broken comment") + truncatedError("broken comment") } /* todo: move this into the NodeBuilder class */ @@ -928,7 +928,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests { new PublicID(pubID, sysID) } else { reportSyntaxError("PUBLIC or SYSTEM expected") - scala.sys.error("died parsing notationdecl") + truncatedError("died parsing notationdecl") } xSpaceOpt() xToken('>') diff --git a/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala b/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala index a6b2ec187..00d94a4fe 100644 --- a/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala +++ b/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala @@ -19,7 +19,7 @@ import Utility.SU * All members should be accessed through those. */ private[scala] trait MarkupParserCommon extends TokenTests { - protected def unreachable = scala.sys.error("Cannot be reached.") + protected def unreachable = truncatedError("Cannot be reached.") // type HandleType // MarkupHandler, SymbolicXMLBuilder type InputType // Source, CharArrayReader @@ -62,7 +62,7 @@ private[scala] trait MarkupParserCommon extends TokenTests { val buf = new StringBuilder while (ch != endCh && !eof) { // well-formedness constraint - if (ch == '<') return errorAndResult("'<' not allowed in attrib value", "") + if (ch == '<') reportSyntaxError("'<' not allowed in attrib value") else if (ch == SU) truncatedError("") else buf append ch_returning_nextch } @@ -241,11 +241,11 @@ private[scala] trait MarkupParserCommon extends TokenTests { val head = until.head val rest = until.tail - while (true) { + while (!eof) { if (ch == head && peek(rest)) return handler(positioner(), sb.toString) else if (ch == SU || eof) - truncatedError("") // throws TruncatedXMLControl in compiler + truncatedError(s"died parsing until $until") // throws TruncatedXMLControl in compiler sb append ch nextch() From e696ee671447c5f45801b80f18591cd8e92ee8b3 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Sun, 15 Apr 2018 21:02:47 -0400 Subject: [PATCH 4/4] Silence test output ConstructingParser --- jvm/src/test/scala/scala/xml/XMLTest.scala | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/jvm/src/test/scala/scala/xml/XMLTest.scala b/jvm/src/test/scala/scala/xml/XMLTest.scala index f8e1cdec4..401f0e00a 100644 --- a/jvm/src/test/scala/scala/xml/XMLTest.scala +++ b/jvm/src/test/scala/scala/xml/XMLTest.scala @@ -766,57 +766,62 @@ class XMLTestJVM { assertEquals(x, XML.loadString(formatted)) } + def toSource(s: String) = new scala.io.Source { + val iter = s.iterator + override def reportError(pos: Int, msg: String, out: java.io.PrintStream = Console.err): Unit = {} + } + @UnitTest def xTokenTest { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("a"), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource("a"), false) assertEquals((): Unit, x.xToken('b')) } @UnitTest(expected = classOf[FatalError]) def xCharDataFailure { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource(""), false) x.xCharData } @UnitTest(expected = classOf[FatalError]) def xCommentFailure { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource(""), false) x.xComment } @UnitTest def xmlProcInstrTest { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("aa"), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource("aa"), false) assertEquals(new UnprefixedAttribute("aa", Text(""), Null), x.xmlProcInstr) } @UnitTest(expected = classOf[FatalError]) def notationDeclFailure { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource(""), false) x.notationDecl } @UnitTest def pubidLiteralTest { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource(""), false) assertEquals("", x.pubidLiteral) } @UnitTest def xAttributeValueTest { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString("'"), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource("'"), false) assertEquals("", x.xAttributeValue) } @UnitTest def xEntityValueTest { - val x = xml.parsing.ConstructingParser.fromSource(io.Source.fromString(""), false) + val x = xml.parsing.ConstructingParser.fromSource(toSource(""), false) assertEquals("", x.xEntityValue) }