NumberOverflowTest.java
package com.fasterxml.jackson.core.read;
import java.math.BigInteger;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.exc.InputCoercionException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
class NumberOverflowTest
extends JUnit5TestBase
{
private final JsonFactory FACTORY = JsonFactory.builder()
.streamReadConstraints(StreamReadConstraints.builder().maxNumberLength(1000000).build())
.build();
// NOTE: this should be long enough to trigger perf problems
// 19-
private final static int BIG_NUM_LEN = 199999;
private final static String BIG_POS_INTEGER;
static {
StringBuilder sb = new StringBuilder(BIG_NUM_LEN);
for (int i = 0; i < BIG_NUM_LEN; ++i) {
sb.append('9');
}
BIG_POS_INTEGER = sb.toString();
}
private final static String BIG_POS_DOC = "["+BIG_POS_INTEGER+"]";
private final static String BIG_NEG_DOC = "[ -"+BIG_POS_INTEGER+"]";
@Test
void simpleLongOverflow() throws Exception
{
BigInteger below = BigInteger.valueOf(Long.MIN_VALUE);
below = below.subtract(BigInteger.ONE);
BigInteger above = BigInteger.valueOf(Long.MAX_VALUE);
above = above.add(BigInteger.ONE);
String DOC_BELOW = below.toString() + " ";
String DOC_ABOVE = below.toString() + " ";
for (int mode : ALL_MODES) {
JsonParser p = createParser(FACTORY, mode, DOC_BELOW);
p.nextToken();
try {
long x = p.getLongValue();
fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
}
p.close();
p = createParser(mode, DOC_ABOVE);
p.nextToken();
try {
long x = p.getLongValue();
fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
}
p.close();
}
}
// Note: only 4 cardinal types; `short`, `byte` and `char` use same code paths
// Note: due to [jackson-core#493], we'll skip DataInput-backed parser
// [jackson-core#488]
@Test
void maliciousLongOverflow() throws Exception
{
for (int mode : ALL_STREAMING_MODES) {
for (String doc : new String[] { BIG_POS_DOC, BIG_NEG_DOC }) {
JsonParser p = createParser(FACTORY, mode, doc);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
try {
p.getLongValue();
fail("Should not pass");
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
verifyException(e, "Integer with "+BIG_NUM_LEN+" digits");
}
p.close();
}
}
}
// [jackson-core#488]
@Test
void maliciousIntOverflow() throws Exception
{
for (int mode : ALL_STREAMING_MODES) {
for (String doc : new String[] { BIG_POS_DOC, BIG_NEG_DOC }) {
JsonParser p = createParser(FACTORY, mode, doc);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
try {
p.getIntValue();
fail("Should not pass");
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
verifyException(e, "Integer with "+BIG_NUM_LEN+" digits");
}
p.close();
}
}
}
// [jackson-core#488]
@Test
void maliciousBigIntToDouble() throws Exception
{
for (int mode : ALL_STREAMING_MODES) {
final String doc = BIG_POS_DOC;
JsonParser p = createParser(FACTORY, mode, doc);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
double d = p.getDoubleValue();
assertEquals(Double.valueOf(BIG_POS_INTEGER), d);
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
}
// [jackson-core#488]
@Test
void maliciousBigIntToFloat() throws Exception
{
for (int mode : ALL_STREAMING_MODES) {
final String doc = BIG_POS_DOC;
JsonParser p = createParser(FACTORY, mode, doc);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
float f = p.getFloatValue();
assertEquals(Float.valueOf(BIG_POS_INTEGER), f);
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
}
}