Skip to content

Commit f5ab6e9

Browse files
committed
Merge branch 'master' of github.com:FasterXML/jackson-databind
2 parents 52b78fd + 93d5c1a commit f5ab6e9

File tree

4 files changed

+157
-21
lines changed

4 files changed

+157
-21
lines changed

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Project: jackson-databind
55

66
2.9.4 (not yet released)
77

8+
#1729: Integer bounds verification when calling `TokenBuffer.getIntValue()`
9+
(reported by Kevin G)
810
#1854: NPE deserializing collection with `@JsonCreator` and `ACCEPT_CASE_INSENSITIVE_PROPERTIES`
911
(reported by rue-jw@github)
1012
#1855: Blacklist for more serialization gadgets (dbcp/tomcat, spring)

src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,16 +1554,22 @@ public float getFloatValue() throws IOException {
15541554
@Override
15551555
public int getIntValue() throws IOException
15561556
{
1557-
// optimize common case:
1558-
if (_currToken == JsonToken.VALUE_NUMBER_INT) {
1559-
return ((Number) _currentObject()).intValue();
1557+
Number n = (_currToken == JsonToken.VALUE_NUMBER_INT) ?
1558+
((Number) _currentObject()) : getNumberValue();
1559+
if ((n instanceof Integer) || _smallerThanInt(n)) {
1560+
return n.intValue();
15601561
}
1561-
return getNumberValue().intValue();
1562+
return _convertNumberToInt(n);
15621563
}
15631564

15641565
@Override
15651566
public long getLongValue() throws IOException {
1566-
return getNumberValue().longValue();
1567+
Number n = (_currToken == JsonToken.VALUE_NUMBER_INT) ?
1568+
((Number) _currentObject()) : getNumberValue();
1569+
if ((n instanceof Long) || _smallerThanLong(n)) {
1570+
return n.longValue();
1571+
}
1572+
return _convertNumberToLong(n);
15671573
}
15681574

15691575
@Override
@@ -1604,6 +1610,79 @@ public final Number getNumberValue() throws IOException {
16041610
+value.getClass().getName());
16051611
}
16061612

1613+
private final boolean _smallerThanInt(Number n) {
1614+
return (n instanceof Short) || (n instanceof Byte);
1615+
}
1616+
1617+
private final boolean _smallerThanLong(Number n) {
1618+
return (n instanceof Integer) || (n instanceof Short) || (n instanceof Byte);
1619+
}
1620+
1621+
/* 02-Jan-2017, tatu: Modified from method(s) in `ParserBase`
1622+
*/
1623+
1624+
protected int _convertNumberToInt(Number n) throws IOException
1625+
{
1626+
if (n instanceof Long) {
1627+
long l = n.longValue();
1628+
int result = (int) l;
1629+
if (((long) result) != l) {
1630+
reportOverflowInt();
1631+
}
1632+
return result;
1633+
}
1634+
if (n instanceof BigInteger) {
1635+
BigInteger big = (BigInteger) n;
1636+
if (BI_MIN_INT.compareTo(big) > 0
1637+
|| BI_MAX_INT.compareTo(big) < 0) {
1638+
reportOverflowInt();
1639+
}
1640+
} else if ((n instanceof Double) || (n instanceof Float)) {
1641+
double d = n.doubleValue();
1642+
// Need to check boundaries
1643+
if (d < MIN_INT_D || d > MAX_INT_D) {
1644+
reportOverflowInt();
1645+
}
1646+
return (int) d;
1647+
} else if (n instanceof BigDecimal) {
1648+
BigDecimal big = (BigDecimal) n;
1649+
if (BD_MIN_INT.compareTo(big) > 0
1650+
|| BD_MAX_INT.compareTo(big) < 0) {
1651+
reportOverflowInt();
1652+
}
1653+
} else {
1654+
_throwInternal();
1655+
}
1656+
return n.intValue();
1657+
}
1658+
1659+
protected long _convertNumberToLong(Number n) throws IOException
1660+
{
1661+
if (n instanceof BigInteger) {
1662+
BigInteger big = (BigInteger) n;
1663+
if (BI_MIN_LONG.compareTo(big) > 0
1664+
|| BI_MAX_LONG.compareTo(big) < 0) {
1665+
reportOverflowLong();
1666+
}
1667+
} else if ((n instanceof Double) || (n instanceof Float)) {
1668+
double d = n.doubleValue();
1669+
// Need to check boundaries
1670+
if (d < MIN_LONG_D || d > MAX_LONG_D) {
1671+
reportOverflowLong();
1672+
}
1673+
return (int) d;
1674+
} else if (n instanceof BigDecimal) {
1675+
BigDecimal big = (BigDecimal) n;
1676+
if (BD_MIN_LONG.compareTo(big) > 0
1677+
|| BD_MAX_LONG.compareTo(big) < 0) {
1678+
reportOverflowLong();
1679+
}
1680+
} else {
1681+
_throwInternal();
1682+
}
1683+
return n.longValue();
1684+
}
1685+
16071686
/*
16081687
/**********************************************************
16091688
/* Public API, access to token information, other

src/test/java/com/fasterxml/jackson/databind/convert/TestArrayConversions.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@ public class TestArrayConversions
1414
final static String OVERFLOW_MSG_BYTE = "out of range of Java byte";
1515
final static String OVERFLOW_MSG = "overflow";
1616

17-
final ObjectMapper mapper = new ObjectMapper();
17+
final static String OVERFLOW_MSG_INT = "out of range of int";
18+
final static String OVERFLOW_MSG_LONG = "out of range of long";
19+
20+
final ObjectMapper MAPPER = new ObjectMapper();
1821

1922
public void testNullXform() throws Exception
2023
{
2124
/* when given null, null should be returned without conversion
2225
* (Java null has no type)
2326
*/
24-
assertNull(mapper.convertValue(null, Integer.class));
25-
assertNull(mapper.convertValue(null, String.class));
26-
assertNull(mapper.convertValue(null, byte[].class));
27+
assertNull(MAPPER.convertValue(null, Integer.class));
28+
assertNull(MAPPER.convertValue(null, String.class));
29+
assertNull(MAPPER.convertValue(null, byte[].class));
2730
}
2831

2932
/**
@@ -72,7 +75,7 @@ public void testIntArrayToX() throws Exception
7275

7376
List<Number> expNums = _numberList(data, data.length);
7477
// Alas, due to type erasure, need to use TypeRef, not just class
75-
List<Integer> actNums = mapper.convertValue(data, new TypeReference<List<Integer>>() {});
78+
List<Integer> actNums = MAPPER.convertValue(data, new TypeReference<List<Integer>>() {});
7679
assertEquals(expNums, actNums);
7780
}
7881

@@ -84,43 +87,42 @@ public void testLongArrayToX() throws Exception
8487
verifyLongArrayConversion(data, int[].class);
8588

8689
List<Number> expNums = _numberList(data, data.length);
87-
List<Long> actNums = mapper.convertValue(data, new TypeReference<List<Long>>() {});
90+
List<Long> actNums = MAPPER.convertValue(data, new TypeReference<List<Long>>() {});
8891
assertEquals(expNums, actNums);
8992
}
9093

9194
public void testOverflows()
9295
{
9396
// Byte overflow
9497
try {
95-
mapper.convertValue(new int[] { 1000 }, byte[].class);
98+
MAPPER.convertValue(new int[] { 1000 }, byte[].class);
9699
} catch (IllegalArgumentException e) {
97100
verifyException(e, OVERFLOW_MSG_BYTE);
98101
}
99102
// Short overflow
100103
try {
101-
mapper.convertValue(new int[] { -99999 }, short[].class);
104+
MAPPER.convertValue(new int[] { -99999 }, short[].class);
102105
} catch (IllegalArgumentException e) {
103106
verifyException(e, OVERFLOW_MSG);
104107
}
105108
// Int overflow
106109
try {
107-
mapper.convertValue(new long[] { Long.MAX_VALUE }, int[].class);
110+
MAPPER.convertValue(new long[] { Long.MAX_VALUE }, int[].class);
108111
} catch (IllegalArgumentException e) {
109-
verifyException(e, OVERFLOW_MSG);
112+
verifyException(e, OVERFLOW_MSG_INT);
110113
}
111114
// Longs need help of BigInteger...
112115
BigInteger biggie = BigInteger.valueOf(Long.MAX_VALUE);
113116
biggie.add(BigInteger.ONE);
114117
List<BigInteger> l = new ArrayList<BigInteger>();
115118
l.add(biggie);
116119
try {
117-
mapper.convertValue(l, int[].class);
120+
MAPPER.convertValue(l, long[].class);
118121
} catch (IllegalArgumentException e) {
119-
verifyException(e, OVERFLOW_MSG);
122+
verifyException(e, OVERFLOW_MSG_LONG);
120123
}
121-
122124
}
123-
125+
124126
/*
125127
/********************************************************
126128
/* Helper methods
@@ -171,7 +173,7 @@ private <T> T _convert(Object input, Class<T> outputType)
171173
// must be a primitive array, like "int[].class"
172174
if (!outputType.isArray()) throw new IllegalArgumentException();
173175
if (!outputType.getComponentType().isPrimitive()) throw new IllegalArgumentException();
174-
T result = mapper.convertValue(input, outputType);
176+
T result = MAPPER.convertValue(input, outputType);
175177
// sanity check first:
176178
assertNotNull(result);
177179
assertEquals(outputType, result.getClass());

src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.UUID;
77

88
import com.fasterxml.jackson.core.*;
9+
import com.fasterxml.jackson.core.JsonParser.NumberType;
910
import com.fasterxml.jackson.core.io.SerializedString;
1011
import com.fasterxml.jackson.core.util.JsonParserSequence;
1112

@@ -120,7 +121,59 @@ public void testSimpleNumberWrites() throws IOException
120121
p.close();
121122
buf.close();
122123
}
123-
124+
125+
// [databind#1729]
126+
public void testNumberOverflowInt() throws IOException
127+
{
128+
try (TokenBuffer buf = new TokenBuffer(null, false)) {
129+
long big = 1L + Integer.MAX_VALUE;
130+
buf.writeNumber(big);
131+
try (JsonParser p = buf.asParser()) {
132+
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
133+
assertEquals(NumberType.LONG, p.getNumberType());
134+
try {
135+
p.getIntValue();
136+
fail("Expected failure for `int` overflow");
137+
} catch (JsonParseException e) {
138+
verifyException(e, "Numeric value ("+big+") out of range of int");
139+
}
140+
}
141+
}
142+
// and ditto for coercion.
143+
try (TokenBuffer buf = new TokenBuffer(null, false)) {
144+
long big = 1L + Integer.MAX_VALUE;
145+
buf.writeNumber(String.valueOf(big));
146+
try (JsonParser p = buf.asParser()) {
147+
// NOTE: oddity of buffering, no inspection of "real" type if given String...
148+
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
149+
try {
150+
p.getIntValue();
151+
fail("Expected failure for `int` overflow");
152+
} catch (JsonParseException e) {
153+
verifyException(e, "Numeric value ("+big+") out of range of int");
154+
}
155+
}
156+
}
157+
}
158+
159+
public void testNumberOverflowLong() throws IOException
160+
{
161+
try (TokenBuffer buf = new TokenBuffer(null, false)) {
162+
BigInteger big = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
163+
buf.writeNumber(big);
164+
try (JsonParser p = buf.asParser()) {
165+
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
166+
assertEquals(NumberType.BIG_INTEGER, p.getNumberType());
167+
try {
168+
p.getLongValue();
169+
fail("Expected failure for `long` overflow");
170+
} catch (JsonParseException e) {
171+
verifyException(e, "Numeric value ("+big+") out of range of long");
172+
}
173+
}
174+
}
175+
}
176+
124177
public void testParentContext() throws IOException
125178
{
126179
TokenBuffer buf = TokenBuffer.forGeneration();

0 commit comments

Comments
 (0)