From 2b276311ebe715354a10610c102a09e4c9be89a7 Mon Sep 17 00:00:00 2001 From: junhyeong9812 Date: Sat, 13 Jun 2026 19:33:37 +0900 Subject: [PATCH] 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 --- .../util/xml/AbstractXMLStreamReader.java | 2 +- .../util/xml/XMLEventStreamReaderTests.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/spring-core/src/main/java/org/springframework/util/xml/AbstractXMLStreamReader.java b/spring-core/src/main/java/org/springframework/util/xml/AbstractXMLStreamReader.java index 1c92c458fcd..1bba07dc5f3 100644 --- a/spring-core/src/main/java/org/springframework/util/xml/AbstractXMLStreamReader.java +++ b/spring-core/src/main/java/org/springframework/util/xml/AbstractXMLStreamReader.java @@ -190,7 +190,7 @@ abstract class AbstractXMLStreamReader implements XMLStreamReader { @Override public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) { char[] source = getTextCharacters(); - length = Math.min(length, source.length); + length = Math.min(length, source.length - sourceStart); System.arraycopy(source, sourceStart, target, targetStart, length); return length; } diff --git a/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java b/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java index 9a261226c86..0a517e7abea 100644 --- a/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java +++ b/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java @@ -21,6 +21,7 @@ import java.io.StringWriter; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stax.StAXSource; @@ -70,4 +71,23 @@ class XMLEventStreamReaderTests { 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(); + } + } + }