Skip to content

Commit

Permalink
[backport] SI-4339 Event errors and attribute fix
Browse files Browse the repository at this point in the history
Improve attribute parsing and propagate errors
across event thread. Otherwise tests just hang.
This is tested, right?

This is an upstream port of scala-xml
5f2cfadeb9e8574ed66f37dc7a7a868eb129a8a9
  • Loading branch information
som-snytt committed Feb 13, 2015
1 parent ad0ddd4 commit fe7867f
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 3 deletions.
8 changes: 8 additions & 0 deletions bincompat-forward.whitelist.conf
Expand Up @@ -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
}
]
}
3 changes: 2 additions & 1 deletion src/library/scala/xml/parsing/MarkupParserCommon.scala
Expand Up @@ -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("")
Expand Down
9 changes: 7 additions & 2 deletions src/library/scala/xml/pull/XMLEventReader.scala
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
3 changes: 3 additions & 0 deletions 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/&gt;",)
Saw failure: scala.xml.parsing.FatalError: expected closing tag of foo
35 changes: 35 additions & 0 deletions 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())
}
)
}

0 comments on commit fe7867f

Please sign in to comment.