Skip to content

Commit e42db3f

Browse files
authored
Validate read() parameters in MergedStream and UTF32Reader implementations (#1544)
1 parent 3ca7c5e commit e42db3f

File tree

5 files changed

+113
-8
lines changed

5 files changed

+113
-8
lines changed

pom.xml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
<parent>
99
<groupId>tools.jackson</groupId>
1010
<artifactId>jackson-base</artifactId>
11-
<version>3.2.0-SNAPSHOT</version>
11+
<version>3.1.0-SNAPSHOT</version>
1212
</parent>
1313
<groupId>tools.jackson.core</groupId>
1414
<artifactId>jackson-core</artifactId>
1515
<name>Jackson-core</name>
16-
<version>3.2.0-SNAPSHOT</version>
16+
<version>3.1.0-SNAPSHOT</version>
1717
<packaging>jar</packaging>
1818
<description>Core Jackson processing abstractions (aka Streaming API), implementation for JSON</description>
1919
<inceptionYear>2007</inceptionYear>
@@ -48,7 +48,13 @@
4848
<javac.src.version>17</javac.src.version>
4949
<javac.target.version>17</javac.target.version>
5050

51-
<!-- Baseline Android SDK compatibility from `jackson-base` -->
51+
<!-- Baseline Android SDK compatibility:
52+
53+
* Jackson 3.0 compatible with Android SDK 26 and up
54+
-->
55+
<version.android.sdk>34</version.android.sdk>
56+
<version.android.sdk.signature>0.12.0</version.android.sdk.signature>
57+
<version.plugin.animal-sniffer>1.27</version.plugin.animal-sniffer>
5258

5359
<osgi.export>tools.jackson.core;version=${project.version},
5460
tools.jackson.core.*;version=${project.version}
@@ -60,7 +66,7 @@ tools.jackson.core.*;version=${project.version}
6066
<packageVersion.package>${project.groupId}.json</packageVersion.package>
6167

6268
<!-- for Reproducible Builds -->
63-
<project.build.outputTimestamp>2026-02-23T20:59:39Z</project.build.outputTimestamp>
69+
<project.build.outputTimestamp>2026-01-28T03:43:50Z</project.build.outputTimestamp>
6470

6571
<!-- for validation of JaCoCo execution -->
6672
<jacocoStrict>false</jacocoStrict>
@@ -363,11 +369,20 @@ tools.jackson.core.*;version=${project.version}
363369

364370
<!-- 16-Nov-2022, tatu: [core#838] add verification of compatibility
365371
wrt Android SDK versions using AnimalSniffer with "gummy bears" signatures.
372+
To be run from CI, but manually with:
373+
mvn clean package animal-sniffer:check
366374
-->
367-
<!-- 24-Feb-2026, tatu [core#1545] Starting with 3.2, use common defaults -->
368375
<plugin>
369376
<groupId>org.codehaus.mojo</groupId>
370377
<artifactId>animal-sniffer-maven-plugin</artifactId>
378+
<version>${version.plugin.animal-sniffer}</version>
379+
<configuration>
380+
<signature>
381+
<groupId>com.toasttab.android</groupId>
382+
<artifactId>gummy-bears-api-${version.android.sdk}</artifactId>
383+
<version>${version.android.sdk.signature}</version>
384+
</signature>
385+
</configuration>
371386
</plugin>
372387
</plugins>
373388
</build>

src/main/java/tools/jackson/core/io/MergedStream.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tools.jackson.core.io;
22

33
import java.io.*;
4+
import java.util.Objects;
45

56
/**
67
* Simple {@link InputStream} implementation that is used to "unwind" some
@@ -69,6 +70,8 @@ public int available() throws IOException {
6970

7071
@Override
7172
public int read(byte[] b, int off, int len) throws IOException {
73+
Objects.requireNonNull(b, "b");
74+
Objects.checkFromIndexSize(off, len, b.length);
7275
if (_b != null) {
7376
int avail = _end - _ptr;
7477
if (len > avail) {

src/main/java/tools/jackson/core/io/UTF32Reader.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tools.jackson.core.io;
22

33
import java.io.*;
4+
import java.util.Objects;
45

56

67
/**
@@ -112,13 +113,14 @@ public int read() throws IOException {
112113
@Override
113114
public int read(char[] cbuf, int start, int len) throws IOException
114115
{
115-
// Already EOF?
116-
if (_buffer == null) { return -1; }
117-
if (len < 1) { return len; }
116+
Objects.requireNonNull(cbuf, "cbuf");
118117
// Let's then ensure there's enough room...
119118
if (start < 0 || len < 0 || start > (cbuf.length - len)) {
120119
reportBounds(cbuf, start, len);
121120
}
121+
// Already EOF?
122+
if (_buffer == null) { return -1; }
123+
if (len < 1) { return len; }
122124

123125
int outPtr = start;
124126
final int outEnd = len+start;

src/test/java/tools/jackson/core/unittest/io/MergedStreamTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,40 @@ void simple() throws Exception
5454

5555
ms.close();
5656
}
57+
58+
@Test
59+
void parameterValidation() throws Exception
60+
{
61+
IOContext ctxt = testIOContext();
62+
byte[] first = ctxt.allocReadIOBuffer();
63+
System.arraycopy("ABC".getBytes("UTF-8"), 0, first, 0, 3);
64+
byte[] second = "DEF".getBytes("UTF-8");
65+
66+
MergedStream ms = new MergedStream(ctxt, new ByteArrayInputStream(second),
67+
first, 0, 3);
68+
byte[] buffer = new byte[10];
69+
70+
// Test null byte array
71+
assertThrows(NullPointerException.class, () -> {
72+
ms.read(null, 0, 5);
73+
});
74+
75+
// Test negative offset
76+
assertThrows(IndexOutOfBoundsException.class, () -> {
77+
ms.read(buffer, -1, 5);
78+
});
79+
80+
// Test negative length
81+
assertThrows(IndexOutOfBoundsException.class, () -> {
82+
ms.read(buffer, 0, -1);
83+
});
84+
85+
// Test offset + length > array length
86+
assertThrows(IndexOutOfBoundsException.class, () -> {
87+
ms.read(buffer, 5, 10);
88+
});
89+
90+
ms.close();
91+
ctxt.close();
92+
}
5793
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package tools.jackson.core.unittest.io;
2+
3+
import java.io.*;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
import tools.jackson.core.io.UTF32Reader;
8+
import tools.jackson.core.unittest.*;
9+
10+
import static org.junit.jupiter.api.Assertions.*;
11+
12+
class UTF32ReaderTest
13+
extends JacksonCoreTestBase
14+
{
15+
@Test
16+
void parameterValidation() throws Exception
17+
{
18+
byte[] input = new byte[] {
19+
0x00, 0x00, 0x00, 0x41, // 'A'
20+
0x00, 0x00, 0x00, 0x42, // 'B'
21+
0x00, 0x00, 0x00, 0x43 // 'C'
22+
};
23+
UTF32Reader reader = new UTF32Reader(null, new ByteArrayInputStream(input), true,
24+
input, 0, input.length, true);
25+
char[] buffer = new char[10];
26+
27+
// Test null char array
28+
assertThrows(NullPointerException.class, () -> {
29+
reader.read(null, 0, 5);
30+
});
31+
32+
// Test negative offset
33+
assertThrows(IndexOutOfBoundsException.class, () -> {
34+
reader.read(buffer, -1, 5);
35+
});
36+
37+
// Test negative length
38+
assertThrows(IndexOutOfBoundsException.class, () -> {
39+
reader.read(buffer, 0, -1);
40+
});
41+
42+
// Test offset + length > array length
43+
assertThrows(IndexOutOfBoundsException.class, () -> {
44+
reader.read(buffer, 5, 10);
45+
});
46+
47+
reader.close();
48+
}
49+
}

0 commit comments

Comments
 (0)