Skip to content

Commit

Permalink
Fix #508
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jan 17, 2019
1 parent 35f3ab4 commit c4dd84e
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 35 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ JSON library.
#496: Create `StreamWriteFeature` to take over non-json-specific `JsonGenerator.Feature`s
#502: Make `DefaultPrettyPrinter.createInstance()` to fail for sub-classes
#506: Add missing type parameter for `TypeReference` in `ObjectCodec`
#508: Add new exception type `InputCoercionException` to be used for failed coercions
like overflow for `int`

2.9.8 (15-Dec-2018)

Expand Down
14 changes: 8 additions & 6 deletions src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ private void _parseSlowInt(int expType) throws IOException
} else {
// 16-Oct-2018, tatu: Need to catch "too big" early due to [jackson-core#488]
if ((expType == NR_INT) || (expType == NR_LONG)) {
_reportTooLongInt(expType, numStr);
_reportTooLongIntegral(expType, numStr);
}
if ((expType == NR_DOUBLE) || (expType == NR_FLOAT)) {
_numberDouble = NumberInput.parseDouble(numStr);
Expand All @@ -864,11 +864,13 @@ private void _parseSlowInt(int expType) throws IOException
}

// @since 2.9.8
protected void _reportTooLongInt(int expType, String rawNum) throws IOException
protected void _reportTooLongIntegral(int expType, String rawNum) throws IOException
{
final String numDesc = _longIntegerDesc(rawNum);
_reportError("Numeric value (%s) out of range of %s", numDesc,
(expType == NR_LONG) ? "long" : "int");
if (expType == NR_INT) {
reportOverflowInt(rawNum);
} else {
reportOverflowLong(rawNum);
}
}

/*
Expand All @@ -884,7 +886,7 @@ protected void convertNumberToInt() throws IOException
// Let's verify it's lossless conversion by simple roundtrip
int result = (int) _numberLong;
if (((long) result) != _numberLong) {
_reportError("Numeric value ("+getText()+") out of range of int");
reportOverflowInt(getText(), currentToken());
}
_numberInt = result;
} else if ((_numTypesValid & NR_BIGINT) != 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.math.BigInteger;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.exc.InputCoercionException;
import com.fasterxml.jackson.core.io.JsonEOFException;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
Expand Down Expand Up @@ -540,18 +541,64 @@ protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonPar
_reportError(msg);
}

/**
* Method called to throw an exception for input token that looks like a number
* based on first character(s), but is not valid according to rules of format.
* In case of JSON this also includes invalid forms like positive sign and
* leading zeroes.
*/
protected void reportInvalidNumber(String msg) throws JsonParseException {
_reportError("Invalid numeric value: "+msg);
}

/**
* Method called to throw an exception for integral (not floating point) input
* token with value outside of Java signed 32-bit range when requested as {@link int}.
* Result will be {@link InputCoercionException} being thrown.
*/
protected void reportOverflowInt() throws IOException {
_reportError(String.format("Numeric value (%s) out of range of int (%d - %s)",
_longIntegerDesc(getText()), Integer.MIN_VALUE, Integer.MAX_VALUE));
reportOverflowInt(getText());
}

// @since 2.10
protected void reportOverflowInt(String numDesc) throws IOException {
reportOverflowInt(numDesc, JsonToken.VALUE_NUMBER_INT);
}

// @since 2.10
protected void reportOverflowInt(String numDesc, JsonToken inputType) throws IOException {
_reportInputCoercion(String.format("Numeric value (%s) out of range of int (%d - %s)",
_longIntegerDesc(numDesc), Integer.MIN_VALUE, Integer.MAX_VALUE),
inputType, Integer.TYPE);
}

/**
* Method called to throw an exception for integral (not floating point) input
* token with value outside of Java signed 64-bit range when requested as {@link long}.
* Result will be {@link InputCoercionException} being thrown.
*/
protected void reportOverflowLong() throws IOException {
_reportError(String.format("Numeric value (%s) out of range of long (%d - %s)",
_longIntegerDesc(getText()), Long.MIN_VALUE, Long.MAX_VALUE));
reportOverflowLong(getText());
}

// @since 2.10
protected void reportOverflowLong(String numDesc) throws IOException {
reportOverflowLong(numDesc, JsonToken.VALUE_NUMBER_INT);
}

// @since 2.10
protected void reportOverflowLong(String numDesc, JsonToken inputType) throws IOException {
_reportInputCoercion(String.format("Numeric value (%s) out of range of long (%d - %s)",
_longIntegerDesc(numDesc), Long.MIN_VALUE, Long.MAX_VALUE),
inputType, Long.TYPE);
}

/**
* @since 2.10
*/
protected void _reportInputCoercion(String msg, JsonToken inputType, Class<?> targetType)
throws InputCoercionException {
throw new InputCoercionException(this, msg, inputType, targetType);
}

// @since 2.9.8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public class InputCoercionException extends StreamReadException {
* sets processor (accessible via {@link #getProcessor()}) to
* specified parser.
*/
public InputCoercionException(JsonParser p, JsonToken inputType, Class<?> targetType,
String msg) {
public InputCoercionException(JsonParser p, String msg,
JsonToken inputType, Class<?> targetType) {
super(p, msg);
_inputType = inputType;
_targetType = targetType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import java.math.BigInteger;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.core.async.AsyncTestBase;
import com.fasterxml.jackson.core.exc.InputCoercionException;
import com.fasterxml.jackson.core.testsupport.AsyncReaderWrapper;
import com.fasterxml.jackson.core.JsonToken;

Expand Down Expand Up @@ -72,8 +72,10 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
long small = -1L + Integer.MIN_VALUE;
p = createParser(String.valueOf(small));
Expand All @@ -83,8 +85,10 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}

// double -> error
Expand All @@ -94,17 +98,21 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
p = createParser(String.valueOf(small)+".0");
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
assertEquals((double) small, p.getDoubleValue());
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}

// BigInteger -> error
Expand All @@ -114,17 +122,21 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
p = createParser(String.valueOf(small));
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(BigInteger.valueOf(small), p.getBigIntegerValue());
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
}

Expand Down Expand Up @@ -176,8 +188,10 @@ public void testToLongFailing() throws Exception
try {
p.getLongValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Long.TYPE, e.getTargetType());
}
BigInteger small = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.TEN);
p = createParser(String.valueOf(small));
Expand All @@ -186,8 +200,10 @@ public void testToLongFailing() throws Exception
try {
p.getLongValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Long.TYPE, e.getTargetType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.exc.InputCoercionException;

public class NumberCoercionTest extends BaseTest
{
Expand Down Expand Up @@ -66,8 +67,10 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
long small = -1L + Integer.MIN_VALUE;
p = createParser(mode, String.valueOf(small));
Expand All @@ -77,8 +80,10 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}

// double -> error
Expand All @@ -88,17 +93,21 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
p = createParser(mode, String.valueOf(small)+".0");
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
assertEquals((double) small, p.getDoubleValue());
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}

// BigInteger -> error
Expand All @@ -108,17 +117,21 @@ public void testToIntFailing() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
p = createParser(mode, String.valueOf(small));
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(BigInteger.valueOf(small), p.getBigIntegerValue());
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Integer.TYPE, e.getTargetType());
}
}
}
Expand Down Expand Up @@ -175,8 +188,10 @@ public void testToLongFailing() throws Exception
try {
p.getLongValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Long.TYPE, e.getTargetType());
}
BigInteger small = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.TEN);
p = createParser(mode, String.valueOf(small));
Expand All @@ -185,8 +200,10 @@ public void testToLongFailing() throws Exception
try {
p.getLongValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
assertEquals(JsonToken.VALUE_NUMBER_INT, e.getInputType());
assertEquals(Long.TYPE, e.getTargetType());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.math.BigInteger;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.exc.InputCoercionException;

public class NumberOverflowTest
extends com.fasterxml.jackson.core.BaseTest
Expand Down Expand Up @@ -39,7 +40,7 @@ public void testSimpleLongOverflow() throws Exception
try {
long x = p.getLongValue();
fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
}
p.close();
Expand All @@ -49,7 +50,7 @@ public void testSimpleLongOverflow() throws Exception
try {
long x = p.getLongValue();
fail("Expected an exception for underflow (input "+p.getText()+"): instead, got long value: "+x);
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
}
p.close();
Expand All @@ -70,7 +71,7 @@ public void testMaliciousLongOverflow() throws Exception
try {
p.getLongValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of long");
verifyException(e, "Integer with "+BIG_NUM_LEN+" digits");
}
Expand All @@ -90,7 +91,7 @@ public void testMaliciousIntOverflow() throws Exception
try {
p.getIntValue();
fail("Should not pass");
} catch (JsonParseException e) {
} catch (InputCoercionException e) {
verifyException(e, "out of range of int");
verifyException(e, "Integer with "+BIG_NUM_LEN+" digits");
}
Expand Down
Loading

0 comments on commit c4dd84e

Please sign in to comment.