--- old/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java Fri Nov 7 08:32:46 2014 +++ new/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java Fri Nov 7 08:32:46 2014 @@ -146,8 +146,9 @@ fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = (char)c; - load(1, false, true); + load(1, false, false); } if (c == '\r' && external) { int cc = fCurrentEntity.ch[fCurrentEntity.position++]; @@ -305,9 +306,10 @@ if (XML11Char.isXML11NameStart(ch)) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = ch; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { fCurrentEntity.columnNumber++; String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); return symbol; @@ -316,9 +318,10 @@ } else if (XML11Char.isXML11NameHighSurrogate(ch)) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = ch; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { --fCurrentEntity.position; --fCurrentEntity.startPosition; return null; @@ -331,10 +334,11 @@ return null; } if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(2); fCurrentEntity.ch[0] = ch; fCurrentEntity.ch[1] = ch2; offset = 0; - if (load(2, false, true)) { + if (load(2, false, false)) { fCurrentEntity.columnNumber += 2; String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2); return symbol; @@ -463,9 +467,10 @@ if (XML11Char.isXML11NCNameStart(ch)) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = ch; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { fCurrentEntity.columnNumber++; String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); return symbol; @@ -474,9 +479,10 @@ } else if (XML11Char.isXML11NameHighSurrogate(ch)) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = ch; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { --fCurrentEntity.position; --fCurrentEntity.startPosition; return null; @@ -489,10 +495,11 @@ return null; } if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(2); fCurrentEntity.ch[0] = ch; fCurrentEntity.ch[1] = ch2; offset = 0; - if (load(2, false, true)) { + if (load(2, false, false)) { fCurrentEntity.columnNumber += 2; String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2); return symbol; @@ -627,9 +634,10 @@ if (XML11Char.isXML11NCNameStart(ch)) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = ch; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { fCurrentEntity.columnNumber++; String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); qname.setValues(null, name, name, null); @@ -639,9 +647,10 @@ } else if (XML11Char.isXML11NameHighSurrogate(ch)) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = ch; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { --fCurrentEntity.startPosition; --fCurrentEntity.position; return false; @@ -654,10 +663,11 @@ return false; } if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(2); fCurrentEntity.ch[0] = ch; fCurrentEntity.ch[1] = ch2; offset = 0; - if (load(2, false, true)) { + if (load(2, false, false)) { fCurrentEntity.columnNumber += 2; String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2); qname.setValues(null, name, name, null); @@ -834,8 +844,9 @@ load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(0); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; - load(1, false, true); + load(1, false, false); fCurrentEntity.position = 0; fCurrentEntity.startPosition = 0; } @@ -975,8 +986,9 @@ load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(0); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; - load(1, false, true); + load(1, false, false); fCurrentEntity.startPosition = 0; fCurrentEntity.position = 0; } @@ -1345,8 +1357,9 @@ else if (c == '\n' && (cc == '\r' ) && fCurrentEntity.isExternal()) { // handle newlines if (fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = (char)cc; - load(1, false, true); + load(1, false, false); } int ccc = fCurrentEntity.ch[++fCurrentEntity.position]; if (ccc == '\n' || ccc == 0x85) { @@ -1407,8 +1420,9 @@ fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(0); fCurrentEntity.ch[0] = (char)c; - entityChanged = load(1, true, true); + entityChanged = load(1, true, false); if (!entityChanged) { // the load change the position to be 1, // need to restore it when entity not changed --- old/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java Fri Nov 7 08:32:47 2014 +++ new/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java Fri Nov 7 08:32:47 2014 @@ -538,8 +538,9 @@ fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = (char)c; - load(1, false, true); + load(1, false, false); } if (c == '\r' && isExternal) { if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') { @@ -670,9 +671,10 @@ int offset = fCurrentEntity.position; if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { fCurrentEntity.columnNumber++; String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1); @@ -776,10 +778,11 @@ if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) { if (++fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; offset = 0; - if (load(1, false, true)) { + if (load(1, false, false)) { fCurrentEntity.columnNumber++; //adding into symbol table. //XXX We are trying to add single character in SymbolTable?????? @@ -906,8 +909,9 @@ if (fCurrentEntity.position == fCurrentEntity.count) { load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(0); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; - load(1, false, true); + load(1, false, false); fCurrentEntity.position = 0; } @@ -1054,8 +1058,9 @@ if (fCurrentEntity.position == fCurrentEntity.count) { load(0, true, true); } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(0); fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; - load(1, false, true); + load(1, false, false); fCurrentEntity.position = 0; } @@ -1427,8 +1432,9 @@ } else if (c == '\n' && cc == '\r' && isExternal) { // handle newlines if (fCurrentEntity.position == fCurrentEntity.count) { + invokeListeners(1); fCurrentEntity.ch[0] = (char)cc; - load(1, false, true); + load(1, false, false); } fCurrentEntity.position++; if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { @@ -1502,8 +1508,9 @@ fCurrentEntity.lineNumber++; fCurrentEntity.columnNumber = 1; if (fCurrentEntity.position == fCurrentEntity.count - 1) { + invokeListeners(0); fCurrentEntity.ch[0] = (char)c; - entityChanged = load(1, true, true); + entityChanged = load(1, true, false); if (!entityChanged){ // the load change the position to be 1, // need to restore it when entity not changed --- /dev/null Fri Nov 7 08:32:49 2014 +++ new/jdk/test/javax/xml/jaxp/testng/parse/XMLEntityScannerLoad.java Fri Nov 7 08:32:48 2014 @@ -0,0 +1,52 @@ +package parse; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +/** + * JDK-8059327: XML parser returns corrupt attribute value + * https://bugs.openjdk.java.net/browse/JDK-8059327 + * + * Also: + * JDK-8061550: XMLEntityScanner can corrupt corrupt content during parsing + * https://bugs.openjdk.java.net/browse/JDK-8061550 + * + * @Summary: verify that the character cache in XMLEntityScanner is reset properly + */ + +public class XMLEntityScannerLoad { + + @Test(dataProvider = "xmls") + public void test(String xml) throws SAXException, IOException, ParserConfigurationException { + Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ChunkInputStream(xml)); + String value = d.getDocumentElement().getAttribute("a1"); + assertEquals(value, "w"); + } + + static class ChunkInputStream extends ByteArrayInputStream { + ChunkInputStream(String xml) { + super(xml.getBytes()); + } + + @Override + public synchronized int read(byte[] b, int off, int len) { + return super.read(b, off, 7); + } + } + + @DataProvider(name = "xmls") + private Object[][] xmls() { + return new Object[][] { + {""}, + {""} + }; + } +}