Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,11 @@ protected T _fromString(JsonParser p, DeserializationContext ctxt,
if (dots >= 0) { // negative if not simple number
try {
if (dots == 0) {
_validateTimestampLength(p, string, false);
return _fromLong(ctxt, NumberInput.parseLong(string));
}
if (dots == 1) {
_validateTimestampLength(p, string, true);
return _fromDecimal(ctxt, NumberInput.parseBigDecimal(string, false));
}
} catch (NumberFormatException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
Expand Down Expand Up @@ -238,4 +240,27 @@ protected DateTimeException _peelDTE(DateTimeException e) {
}
return e;
}

/**
* Helper method to validate length of a stringified numeric Date/Time value
* against {@link StreamReadConstraints} limits.
*
* @param p Parser to get constraints from
* @param value Stringified numeric value to validate
* @param isFP Whether {@code value} is a floating-point (has decimal point)
* or integer number; caller knows this already so we avoid re-scanning
*
* @since 2.18.10
*/
protected void _validateTimestampLength(JsonParser p, String value, boolean isFP)
throws StreamConstraintsException
{
final int len = value.length();
StreamReadConstraints constraints = p.streamReadConstraints();
if (isFP) {
constraints.validateFPLength(len);
} else {
constraints.validateIntegerLength(len);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ protected void verifyException(Throwable e, String... matches)
throw new Error("Expected an exception with one of substrings ("+Arrays.asList(matches)+"): got one with message \""+msg+"\"");
}

protected static String repeat(String s, int count) {
StringBuilder sb = new StringBuilder(s.length() * count);
for (int i = 0; i < count; i++) {
sb.append(s);
}
return sb.toString();
}

protected static <T> Map<T, String> asMap(T key, String value) {
return Collections.singletonMap(key, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import org.junit.Test;

import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;

Expand Down Expand Up @@ -640,4 +642,40 @@ public void testISO8601ColonlessRegexDoesNotAffectNegativeYearsWithColonless() {
assertTrue("Matcher finds +0100 as an colonless offset", matcher.find());
assertEquals("Matcher groups +0100 as an colonless offset", matcher.group(), "+0100");
}

// [modules-java8#387]: StreamReadConstraints should limit numeric string lengths
// parsed via _fromString to prevent excessive BigDecimal construction.
// NOTE: values MUST be quoted -- unquoted ones are Number tokens, limits for
// which are enforced by the streaming parser and not by this deserializer.
@Test
public void testNumericStringRespectsStreamReadConstraints() throws Exception
{
final int MAX_ALLOWED_LEN = StreamReadConstraints.DEFAULT_MAX_NUM_LEN;

// Normal epoch seconds as integer should work
assertNotNull(MAPPER.readValue(q("1234567890"), Instant.class));

// Normal epoch seconds with decimal should work
assertNotNull(MAPPER.readValue(q("1234567890.123456789"), Instant.class));

// A very long integer string (exceeding default 1000-digit limit) should fail
String longInt = repeat("1", MAX_ALLOWED_LEN + 1);
try {
MAPPER.readValue(q(longInt), Instant.class);
fail("Should not pass with excessively long integer string");
} catch (StreamConstraintsException e) {
verifyException(e, "Number value length");
verifyException(e, "exceeds the maximum allowed");
}

// A very long decimal string (exceeding default 1000-char limit) should fail
String longDecimal = "1234." + repeat("9", MAX_ALLOWED_LEN);
try {
MAPPER.readValue(q(longDecimal), Instant.class);
fail("Should not pass with excessively long decimal string");
} catch (StreamConstraintsException e) {
verifyException(e, "Number value length");
verifyException(e, "exceeds the maximum allowed");
}
}
}
5 changes: 5 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Modules:
=== Releases ===
------------------------------------------------------------------------

2.18.10 (not yet released)

#387: Validate length of input in `InstantDeserializer`
(fix by @pjfanning)

2.18.9 (07-Jul-2026)
2.18.8 (28-May-2026)
2.18.7 (24-Apr-2026)
Expand Down
Loading