diff options
-rw-r--r-- | bincompat-forward.whitelist.conf | 8 | ||||
-rw-r--r-- | src/library/scala/xml/parsing/MarkupParserCommon.scala | 3 | ||||
-rwxr-xr-x | src/library/scala/xml/pull/XMLEventReader.scala | 9 | ||||
-rw-r--r-- | test/files/run/t4339.check | 3 | ||||
-rw-r--r-- | test/files/run/t4339.scala | 35 |
5 files changed, 55 insertions, 3 deletions
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index c9cf4f74b9..1c532889c2 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -187,6 +187,14 @@ filter { { matchName="scala.xml.dtd.ElementValidator.scala$xml$dtd$ElementValidator$$find$2" problemName=IncompatibleMethTypeProblem + }, + { + matchName="scala.xml.pull.ExceptionEvent" + problemName=MissingClassProblem + }, + { + matchName="scala.xml.pull.ExceptionEvent$" + problemName=MissingClassProblem } ] } diff --git a/src/library/scala/xml/parsing/MarkupParserCommon.scala b/src/library/scala/xml/parsing/MarkupParserCommon.scala index da640484e0..4dbe5aed9d 100644 --- a/src/library/scala/xml/parsing/MarkupParserCommon.scala +++ b/src/library/scala/xml/parsing/MarkupParserCommon.scala @@ -58,8 +58,9 @@ private[scala] trait MarkupParserCommon extends TokenTests { @param endCh either `'` or `"` */ def xAttributeValue(endCh: Char): String = { + require(endCh == '\'' || endCh == '"', s"Expected single or double quote, found $endCh") val buf = new StringBuilder - while (ch != endCh) { + while (ch != endCh && !eof) { // well-formedness constraint if (ch == '<') return errorAndResult("'<' not allowed in attrib value", "") else if (ch == SU) truncatedError("") diff --git a/src/library/scala/xml/pull/XMLEventReader.scala b/src/library/scala/xml/pull/XMLEventReader.scala index 428c305055..26572c9946 100755 --- a/src/library/scala/xml/pull/XMLEventReader.scala +++ b/src/library/scala/xml/pull/XMLEventReader.scala @@ -91,12 +91,16 @@ extends scala.collection.AbstractIterator[XMLEvent] override def run() { curInput = input - interruptibly { this.initialize.document() } - setEvent(POISON) + try interruptibly { this.initialize.document() } + catch { case e:Exception => setEvent(ExceptionEvent(e)) } + finally setEvent(POISON) } } } +// An internal class used to propagate exception from helper threads to API end users. +private case class ExceptionEvent(exception:Exception) extends XMLEvent + // An iterator designed for one or more producers to generate // elements, and a single consumer to iterate. Iteration will continue // until closeIterator() is called, after which point producers @@ -141,6 +145,7 @@ trait ProducerConsumerIterator[T >: Null] extends Iterator[T] { def next() = { if (eos) throw new NoSuchElementException("ProducerConsumerIterator") if (buffer == null) fillBuffer + if (buffer.isInstanceOf[ExceptionEvent]) throw buffer.asInstanceOf[ExceptionEvent].exception drainBuffer } diff --git a/test/files/run/t4339.check b/test/files/run/t4339.check new file mode 100644 index 0000000000..46eabbe42b --- /dev/null +++ b/test/files/run/t4339.check @@ -0,0 +1,3 @@ +Saw failure: scala.xml.parsing.FatalError: expected closing tag of foo +EvElemStart(null,foo, bar="baz/>",) +Saw failure: scala.xml.parsing.FatalError: expected closing tag of foo diff --git a/test/files/run/t4339.scala b/test/files/run/t4339.scala new file mode 100644 index 0000000000..bb8b847ec3 --- /dev/null +++ b/test/files/run/t4339.scala @@ -0,0 +1,35 @@ + +import scala.util.{ Try, Success, Failure } +import xml._ +import scala.io.Source.fromString +import java.io.PrintStream + +object Test extends App { + + def quietSource(text: String) = new io.Source { + override protected val iter = io.Source fromString text + override def report(pos: Int, msg: String, out: PrintStream) = () + } + def reading(text: String)(f: pull.XMLEventReader => Unit): Unit = { + val r = new pull.XMLEventReader(quietSource(text)) + try f(r) + finally r.stop() + } + def trying(body: => Unit): Unit = + Try (body) match { + case Success(_) => Console println "Expected failure" + case Failure(e) => Console println s"Saw failure: $e" + } + + val problematic = """<foo bar="baz/>""" + + trying ( + parsing.ConstructingParser.fromSource(quietSource(problematic), false).document.docElem + ) + + trying ( + reading(problematic) { r => + while (r.hasNext) println(r.next()) + } + ) +} |