Skip to content

[FLINK-40217][core] Reject non-finite numbers in Variant JSON conversion#28808

Open
raminqaf wants to merge 2 commits into
apache:masterfrom
raminqaf:FLINK-40217
Open

[FLINK-40217][core] Reject non-finite numbers in Variant JSON conversion#28808
raminqaf wants to merge 2 commits into
apache:masterfrom
raminqaf:FLINK-40217

Conversation

@raminqaf

Copy link
Copy Markdown
Contributor

What is the purpose of the change

PARSE_JSON accepted JSON numbers outside the double range, such as 1e400, and silently stored them as ±Infinity. Variant.toJson() then emitted bare Infinity / -Infinity tokens, which are invalid JSON and cannot be parsed back by PARSE_JSON. This closes that gap by rejecting non-finite values on both the parse and the serialize side.

Brief change log

  • BinaryVariantInternalBuilder.parseFloatingPoint() now rejects a non-finite result from getDoubleValue() with a clear parse error. PARSE_JSON('1e400') fails loudly and TRY_PARSE_JSON('1e400') returns NULL, so a parsed Variant can never hold a non-finite value.
  • BinaryVariant.toJson() now throws a VariantTypeException for non-finite DOUBLE and FLOAT values instead of appending invalid Infinity / NaN tokens. This guards the builder API, which is the only remaining way to inject a non-finite value.
  • parseJson reuses a single static JsonFactory instead of allocating one per call.

Verifying this change

This change added tests and can be verified as follows:

  • Added BinaryVariantInternalBuilderTest#testParseJsonRejectsNonFiniteNumbers, parameterized over NaN, Infinity, -Infinity, 1e400, and -1e400, asserting parseJson throws (invalid JSON tokens and finite-but-overflowing numbers alike).
  • Added BinaryVariantTest#testToJsonRejectsNonFiniteDouble and #testToJsonRejectsNonFiniteFloat, parameterized over the infinities and NaN, asserting toJson() throws instead of emitting invalid JSON.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API, i.e., is any changed class annotated with @Public(Evolving): no (both changed classes are @Internal; the user-visible effect is a semantics change to the PARSE_JSON / TRY_PARSE_JSON SQL functions on out-of-range numbers)
  • The serializers: no (the Variant binary encoding is unchanged)
  • The runtime per-record code paths (performance sensitive): yes (on the PARSE_JSON / toJson() paths; the only added cost is a constant-time finite check, and reusing JsonFactory removes a per-call allocation)
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Kubernetes/Yarn, ZooKeeper: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? no
  • If yes, how is the feature documented? not applicable

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

@flinkbot

flinkbot commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

Comment thread flink-core/src/main/java/org/apache/flink/types/variant/BinaryVariant.java Outdated
Comment thread flink-core/src/main/java/org/apache/flink/types/variant/BinaryVariant.java Outdated
Comment on lines +126 to +128
@ValueSource(strings = {"NaN", "Infinity", "-Infinity", "1e400", "-1e400"})
void testParseJsonRejectsNonFiniteNumbers(final String nonFiniteNumber) {
// NaN and the infinities are not valid JSON; 1e400 is valid JSON but overflows the double

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about length of a number (not only for float/double)

in jackson it is configured with StreamReadConstraints.DEFAULT_MAX_NUM_LEN which is by default 1000.
Means there might be issues with longer numbers

@raminqaf raminqaf Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new test that generates a number with 1001 digits.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the test. We investigated and realized that any number with a precision of >38 is parsed as double. If the number is then >Double.MAX_VALUE it will fall into the infinity exception.

PARSE_JSON accepted JSON numbers outside the double range, such as 1e400, and silently stored them as +/-Infinity. Variant.toJson() then emitted bare Infinity/-Infinity tokens, which are invalid JSON and cannot be parsed back by PARSE_JSON, so the round trip was broken.

parseFloatingPoint now rejects a non-finite result from getDoubleValue() with a clear parse error. PARSE_JSON surfaces the failure and TRY_PARSE_JSON returns NULL, so a parsed Variant can never hold a non-finite value.

As a defensive safeguard for the builder API, which can still inject non-finite values, toJson() now throws for non-finite DOUBLE and FLOAT values instead of emitting invalid tokens.
Cover the end-to-end SQL wiring for PARSE_JSON and TRY_PARSE_JSON: a JSON_STRING round trip, NULL handling, and the out-of-range number behavior. An overflowing number such as 1e400 makes PARSE_JSON fail with a TableRuntimeException, while TRY_PARSE_JSON returns NULL. The parsing semantics themselves stay covered by BinaryVariantInternalBuilderTest.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants