diff --git a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java index 479fba48a..e7ecd5e49 100644 --- a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java +++ b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java @@ -278,9 +278,10 @@ public String getText() throws IOException // trying to get the text for a symbol id that cannot be resolved. // stringValue() has an assert statement which could throw an throw _constructError(e.getMessage(), e); - } catch (AssertionError e) { + } catch (AssertionError | NullPointerException e) { // AssertionError if we're trying to get the text with a symbol // id less than or equals to 0. + // NullPointerException may also be thrown on invalid data String msg = e.getMessage(); if (msg == null) { msg = "UNKNOWN ROOT CAUSE"; @@ -331,34 +332,50 @@ public int getTextOffset() throws IOException { @Override public BigInteger getBigIntegerValue() throws IOException { + _verifyIsNumberToken(); return _reader.bigIntegerValue(); } @Override public BigDecimal getDecimalValue() throws IOException { + _verifyIsNumberToken(); return _reader.bigDecimalValue(); } @Override public double getDoubleValue() throws IOException { + _verifyIsNumberToken(); return _reader.doubleValue(); } @Override public float getFloatValue() throws IOException { + _verifyIsNumberToken(); return (float) _reader.doubleValue(); } @Override public int getIntValue() throws IOException { + _verifyIsNumberToken(); return _reader.intValue(); } @Override public long getLongValue() throws IOException { + _verifyIsNumberToken(); return _reader.longValue(); } + // @since 2.17 + private void _verifyIsNumberToken() throws IOException + { + if (_currToken != JsonToken.VALUE_NUMBER_INT && _currToken != JsonToken.VALUE_NUMBER_FLOAT) { + // Same as `ParserBase._parseNumericValue()` exception: + _reportError("Current token (%s) not numeric, can not use numeric value accessors", + _currToken); + } + } + @Override public NumberType getNumberType() throws IOException { diff --git a/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/fuzz/Fuzz424_65065_65126NPETest.java b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/fuzz/Fuzz424_65065_65126NPETest.java new file mode 100644 index 000000000..5b054b14e --- /dev/null +++ b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/fuzz/Fuzz424_65065_65126NPETest.java @@ -0,0 +1,48 @@ +package com.fasterxml.jackson.dataformat.ion.fuzz; + +import java.io.ByteArrayInputStream; + +import org.hamcrest.Matchers; +import org.junit.Test; + +import com.fasterxml.jackson.core.exc.StreamReadException; +import com.fasterxml.jackson.dataformat.ion.*; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +// [dataformats-binary#424] +public class Fuzz424_65065_65126NPETest +{ + @Test + public void testFuzz65065() throws Exception { + IonFactory f = IonFactory + .builderForBinaryWriters() + .build(); + + IonObjectMapper mapper = IonObjectMapper.builder(f).build(); + + try { + byte[] bytes = {(byte) -32, (byte) 1, (byte) 0, (byte) -22, (byte) 123, (byte) -112}; + mapper.readTree(f.createParser(new ByteArrayInputStream(bytes))); + fail("Should not pass (invalid content)"); + } catch (StreamReadException e) { + assertThat(e.getMessage(), Matchers.containsString("Internal `IonReader` error")); + } + } + + @Test + public void testFuzz65126() throws Exception { + IonFactory f = IonFactory + .builderForBinaryWriters() + .build(); + + try { + byte[] bytes = {(byte) 1, (byte) 0}; + f.createParser(bytes).getDecimalValue(); + fail("Should not pass (invalid content)"); + } catch (StreamReadException e) { + assertThat(e.getMessage(), Matchers.containsString("Current token (null) not numeric")); + } + } +} diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 471067b9c..3e451885f 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -287,3 +287,6 @@ Arthur Chan (@arthurscchan) (2.17.0) * Contributed #420: (ion) `IndexOutOfBoundsException` thrown by `IonReader` implementations (2.17.0) + * Contributed #424: (ion) `IonReader` throws `NullPointerException` for unchecked + invalid data + (2.17.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index bb5a266ca..fcdb42b28 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -22,6 +22,8 @@ Active maintainers: #420: (ion) `IndexOutOfBoundsException` thrown by `IonReader` implementations are not handled (contributed by Arthur C) +#424: (ion) `IonReader` throws `NullPointerException` for unchecked invalid data + (contributed by Arthur C) -(ion) Update `com.amazon.ion:ion-java` to 1.11.0 (from 1.10.5) 2.16.0 (15-Nov-2023)