Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8201138

Defect in XMLEventReader.getElementText() may cause data to be skipped, duplicated or otherwise result in a ClassCastException

    XMLWordPrintable

    Details

    • Subcomponent:
    • Resolved In Build:
      b13
    • CPU:
      x86_64
    • OS:
      windows_7

      Description

      FULL PRODUCT VERSION :
      java version "1.8.0_162"
      Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
      Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Windows 1709 (OS Build 16299.309)

      A DESCRIPTION OF THE PROBLEM :
      When called after peek(), XMLEventReader.getElementText() may skip, duplicate data, or throw ClassCastException. The defect is caused by getElementText() not properly updating local variables `type` and `data`.

      Failing unit tests for showcasing the bug were attached to the report.
      The test code relies on JUnit and Hamcrest to run.

      The error in question seems to be caused by an implementation defect in com.sun.xml.internal.stream.XMLEventReaderImpl.

      The bug, based on the source file (http://hg.openjdk.java.net/jdk8/jdk8/jaxp/file/0c49f9209035/src/com/sun/xml/internal/stream/XMLEventReaderImpl.java), can can be traced back to the following two problems:

      The `type` local variable is not updated after lines 155 and 179 with the command: `type = event.getEventType();`.
      The discrepancy between the contents of the `type` variable and the actual XML event stored in the `event` local variable may cause XMLEventReader to execute of an operation that is inconsistent with the state of the underlying XMLStreamReader.

      The `data` local variable us not reset to null after lines 148 and 177.
      This may cause previously processed text, stored in `data` to be re-appended to the buffer.






      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      *** For complete unit tests showcasing the bug, see attached executable test case ***


      Test case #1:

      Create an XMLEventReader for the following XML document:

      <?xml version=\"1.0\"?><nextEvent><!-- peeked -->aaa<![CDATA[bbb]]>ccc</nextEvent>

      Set up error condition by performing the following calls on the XMLEventReader:

      eventReader.nextEvent(); // START_DOCUMENT
      eventReader.nextEvent(); // START_ELEMENT
      eventReader.peek(); // COMMENT (peeked)

      Call `eventReader.getElementText()` to observe incorrect empty result instead of "aaabbbccc".

      Test case #2:

      Create an XMLEventReader for the following XML document:

      <?xml version=\"1.0\"?><nextEvent>aaa<!-- Comment --></nextEvent>

      Set up error condition by performing the following calls on the XMLEventReader:

      eventReader.nextEvent(); // START_DOCUMENT
      eventReader.nextEvent(); // START_ELEMENT
      eventReader.peek(); // CHARACTER (peeked)

      Call `eventReader.getElementText()` to observe ClassCastException being thrown.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Test case #1: The final call to getElementText() is expected to return "aaabbbccc".
      Test case #2: The final call to getElementText() is expected to return "aaa".
      ACTUAL -
      Test case #1: The final call to getElementText() returns an empty string.
      Test case #2: The final call to getElementText() throws ClassCastException.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Test case #1:

      Test runs, but produces incorrect results.
      (Expected: "aaabbbccc" but: was "")


      Test case #2:

      java.lang.ClassCastException: com.sun.xml.internal.stream.events.CommentEvent cannot be cast to javax.xml.stream.events.Characters
      at com.sun.xml.internal.stream.events.DummyEvent.asCharacters(Unknown Source)
      at com.sun.xml.internal.stream.XMLEventReaderImpl.getElementText(Unknown Source)
      ...

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      /*
      Dependencies: 'junit:junit:4.12', 'org.hamcrest:hamcrest-all:1.3'
      */

      import static org.hamcrest.MatcherAssert.assertThat;
      import static org.hamcrest.Matchers.equalTo;
      import static org.hamcrest.Matchers.instanceOf;

      import java.io.StringReader;

      import javax.xml.stream.FactoryConfigurationError;
      import javax.xml.stream.XMLEventReader;
      import javax.xml.stream.XMLInputFactory;
      import javax.xml.stream.XMLStreamException;
      import javax.xml.stream.events.Characters;
      import javax.xml.stream.events.Comment;
      import javax.xml.stream.events.StartDocument;
      import javax.xml.stream.events.StartElement;

      import org.junit.Test;

      public class XMLEventReaderTest {

      @Test
      public void testTypeReset() throws XMLStreamException, FactoryConfigurationError {

              String xmlData = "<?xml version=\"1.0\"?><nextEvent><!-- peeked -->aaa<![CDATA[bbb]]>ccc</nextEvent>";
              
              XMLEventReader eventReader = XMLInputFactory.newFactory().createXMLEventReader(new StringReader(xmlData));
              assertThat(eventReader.nextEvent(), instanceOf(StartDocument.class));
              assertThat(eventReader.nextEvent(), instanceOf(StartElement.class));
              assertThat(eventReader.peek(), instanceOf(Comment.class));
              assertThat(eventReader.getElementText(), equalTo("aaabbbccc")); // Assertion fails
              eventReader.close();
      }

      @Test
      public void testTypeResetAndBufferClear() throws XMLStreamException, FactoryConfigurationError {

              String xmlData = "<?xml version=\"1.0\"?><nextEvent>aaa<!-- comment --></nextEvent>";
              
              XMLEventReader eventReader = XMLInputFactory.newFactory().createXMLEventReader(new StringReader(xmlData));
              assertThat(eventReader.nextEvent(), instanceOf(StartDocument.class));
              assertThat(eventReader.nextEvent(), instanceOf(StartElement.class));
              assertThat(eventReader.peek(), instanceOf(Characters.class));
              assertThat(eventReader.getElementText(), equalTo("aaa")); // ClassCastException !
              eventReader.close();
      }

      }
      ---------- END SOURCE ----------

        Attachments

          Activity

            People

            • Assignee:
              joehw Joe Wang
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: