Skip to content

Commit 3f29c6c

Browse files
authored
Merge pull request #125 from JacekLach/jl/negative-number-overflow
Avoid integer overflow when parsing cbor negative numbers
2 parents 13866c9 + ef2aee0 commit 3f29c6c

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,8 @@ public JsonToken nextToken() throws IOException
685685
{
686686
int v = _decode32Bits();
687687
if (v < 0) {
688-
_numberLong = ((long) v) + -1L;
688+
long unsignedBase = (long) v & 0xFFFFFFFFL;
689+
_numberLong = -unsignedBase - 1L;
689690
_numTypesValid = NR_LONG;
690691
} else {
691692
_numberInt = -v - 1;
@@ -700,7 +701,8 @@ public JsonToken nextToken() throws IOException
700701
_numberLong = -l - 1L;
701702
_numTypesValid = NR_LONG;
702703
} else {
703-
_numberBigInt = _bigNegative(l);
704+
BigInteger unsignedBase = _bigPositive(l);
705+
_numberBigInt = unsignedBase.negate().subtract(BigInteger.ONE);
704706
_numTypesValid = NR_BIGINT;
705707
}
706708
}
@@ -1158,7 +1160,8 @@ public String nextTextValue() throws IOException
11581160
{
11591161
int v = _decode32Bits();
11601162
if (v < 0) {
1161-
_numberLong = ((long) v) + -1L;
1163+
long unsignedBase = (long) v & 0xFFFFFFFFL;
1164+
_numberLong = -unsignedBase - 1L;
11621165
_numTypesValid = NR_LONG;
11631166
} else {
11641167
_numberInt = -v - 1;
@@ -1173,7 +1176,8 @@ public String nextTextValue() throws IOException
11731176
_numberLong = l;
11741177
_numTypesValid = NR_LONG;
11751178
} else {
1176-
_numberBigInt = _bigNegative(l);
1179+
BigInteger unsignedBase = _bigPositive(l);
1180+
_numberBigInt = unsignedBase.negate().subtract(BigInteger.ONE);
11771181
_numTypesValid = NR_BIGINT;
11781182
}
11791183
}

cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/parse/ParserNumbersTest.java

+32-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
public class ParserNumbersTest extends CBORTestBase
2222
{
2323
private final CBORFactory CBOR_F = cborFactory();
24-
24+
2525
public void testIntValues() throws Exception
2626
{
2727
// first, single-byte
@@ -101,6 +101,17 @@ public void testInt32Overflow() throws Exception
101101
assertEquals(exp, p.getLongValue());
102102
assertEquals(NumberType.LONG, p.getNumberType());
103103
p.close();
104+
105+
// and, combined, a negative number where the mantissa overflows a signed int32
106+
input = new byte[] {
107+
(byte) CBORConstants.PREFIX_TYPE_INT_NEG + 26, // int32, that is, 4 more bytes
108+
-1, -1, -1, -1
109+
};
110+
p = cborParser(input);
111+
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
112+
assertEquals(-1L - 0xFFFFFFFFL, p.getLongValue());
113+
assertEquals(NumberType.LONG, p.getNumberType());
114+
p.close();
104115
}
105116

106117
public void testLongValues() throws Exception
@@ -170,6 +181,21 @@ public void testInt64Overflow() throws Exception
170181
assertEquals(exp, p.getBigIntegerValue());
171182
assertEquals(NumberType.BIG_INTEGER, p.getNumberType());
172183
p.close();
184+
185+
// and, combined, a negative number where the mantissa overflows a signed int32
186+
input = new byte[] {
187+
(byte) CBORConstants.PREFIX_TYPE_INT_NEG + 27, // int32, that is, 4 more bytes
188+
-1, -1, -1, -1, -1, -1, -1, -1
189+
};
190+
p = cborParser(input);
191+
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
192+
exp = BigInteger.valueOf(Long.MAX_VALUE).shiftLeft(1)
193+
.add(BigInteger.ONE)
194+
.negate()
195+
.subtract(BigInteger.ONE);
196+
assertEquals(exp, p.getBigIntegerValue());
197+
assertEquals(NumberType.BIG_INTEGER, p.getNumberType());
198+
p.close();
173199
}
174200

175201
public void testDoubleValues() throws Exception
@@ -198,15 +224,15 @@ private void _verifyDouble(CBORFactory f, double value, boolean isNaN) throws Ex
198224
assertEquals((float) value, p.getFloatValue());
199225

200226
assertNull(p.nextToken());
201-
227+
202228
// also skip
203229
p = cborParser(f, out.toByteArray());
204230
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
205231
assertNull(p.nextToken());
206-
232+
207233
p.close();
208234
}
209-
235+
210236
public void testFloatValues() throws Exception
211237
{
212238
// first, single-byte
@@ -251,7 +277,7 @@ private void _verifyFloat(CBORFactory f, double value, boolean isNaN) throws Exc
251277
p = cborParser(f, out.toByteArray());
252278
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
253279
assertNull(p.nextToken());
254-
280+
255281
p.close();
256282
}
257283

@@ -263,7 +289,7 @@ private void _verifyHalfFloat(JsonFactory f, int i16, double value) throws IOExc
263289
};
264290

265291
boolean expNaN = Double.isNaN(value) || Double.isInfinite(value);
266-
292+
267293
JsonParser p = f.createParser(data);
268294
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
269295
assertEquals(expNaN, p.isNaN());

0 commit comments

Comments
 (0)