Honor sourceStart offset in AbstractXMLStreamReader#getTextCharacters

Prior to this commit, AbstractXMLStreamReader.getTextCharacters(int
sourceStart, char[], int, int) capped the copy length with
Math.min(length, source.length), ignoring sourceStart. When sourceStart
> 0 and sourceStart + length exceeds the text length, System.arraycopy
read past the end of the source array and threw
ArrayIndexOutOfBoundsException, contrary to the
XMLStreamReader#getTextCharacters contract (copy up to length
characters starting at sourceStart and return the number copied).

To address that, this commit caps the length by the number of
characters remaining from sourceStart.

Closes gh-36914

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
This commit is contained in:
junhyeong9812
2026-09-04 15:13:35 +02:00
committed by Sam Brannen
parent b5a358019f
commit 2b276311eb
2 changed files with 21 additions and 1 deletions
@@ -190,7 +190,7 @@ abstract class AbstractXMLStreamReader implements XMLStreamReader {
@Override @Override
public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) { public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) {
char[] source = getTextCharacters(); char[] source = getTextCharacters();
length = Math.min(length, source.length); length = Math.min(length, source.length - sourceStart);
System.arraycopy(source, sourceStart, target, targetStart, length); System.arraycopy(source, sourceStart, target, targetStart, length);
return length; return length;
} }
@@ -21,6 +21,7 @@ import java.io.StringWriter;
import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.transform.Transformer; import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stax.StAXSource;
@@ -70,4 +71,23 @@ class XMLEventStreamReaderTests {
assertThat(XmlContent.from(writer)).isSimilarTo(XML, nodeFilter); assertThat(XmlContent.from(writer)).isSimilarTo(XML, nodeFilter);
} }
@Test // gh-36914
void getTextCharactersHonorsSourceStart() throws Exception {
char[] target = new char[10];
advanceToCharacters();
// text node is "content" (7 chars); copy from index 4 with an oversized buffer
// getTextCharacters(sourceStart, ...) must not read past the source
int count = streamReader.getTextCharacters(4, target, 0, 10);
assertThat(count).isEqualTo(3);
assertThat(new String(target, 0, count)).isEqualTo("ent");
}
private void advanceToCharacters() throws Exception {
while (streamReader.getEventType() != XMLStreamConstants.CHARACTERS) {
streamReader.next();
}
}
} }