Skip to content

Fix undefined double-to-int casts when encoding a number value (#5303) - #5309

Open
1820893135-pixel wants to merge 1 commit into
jerryscript-project:masterfrom
1820893135-pixel:fix-number-cast-ub
Open

1820893135-pixel wants to merge 1 commit into
jerryscript-project:masterfrom
1820893135-pixel:fix-number-cast-ub

Conversation

@1820893135-pixel

Copy link
Copy Markdown

Three helpers in ecma-helpers-value.c converted a double to
ecma_integer_value_t and only then tested the result:

ecma_integer_value_t integer_value = (ecma_integer_value_t) ecma_number;

if ((ecma_number_t) integer_value == ecma_number && ...)

The cast is already undefined behaviour when the double is outside the
ecma_integer_value_t range, so the round-trip check cannot guard it. Under
-fsanitize=undefined (the OSS-Fuzz configuration) this traps:

ecma-helpers-value.c:572:40: runtime error: 1.5e+300 is outside the range of
representable values of type 'int'

The same pattern appears in all three functions, and a value such as 1.5e300
walks from one to the next:

function line
ecma_make_number_value 572
ecma_update_float_number 1021
ecma_value_assign_number 1073

The reported input is a snapshot containing an oversized number literal, which
reaches ecma_make_number_value() through
ecma_snapshot_get_literal(); the value then flows into ecma_update_float_number()
and ecma_value_assign_number(), so fixing only the first site just moves the
trap to the next one.

Fix

Move the range test in front of the cast in each function. Values outside the
range fall through to ecma_create_float_number(), which is what happened for
every value the round-trip check rejected.

Testing

Extends tests/unit-core/test-api-value-type.c with numbers outside the
ecma_integer_value_t range (1e308, -1e308, 1.5e300, -1.5e10, 1e18)
that must round-trip as float values, plus a small integer that must still
behave as before.

Fixes #5303.

Three helpers in ecma-helpers-value.c converted a double to
ecma_integer_value_t and only then checked whether the result was in
range:

    ecma_integer_value_t integer_value = (ecma_integer_value_t) ecma_number;
    if ((ecma_number_t) integer_value == ecma_number && ...)

The cast is already undefined behaviour when the double is outside the
ecma_integer_value_t range, so the check comes too late.  Under
-fsanitize=undefined (the OSS-Fuzz configuration) this traps:

    ecma-helpers-value.c:572:40: runtime error: 1.5e+300 is outside the
    range of representable values of type 'int'

Reached from ecma_make_number_value (line 572), ecma_update_float_number
(line 1021) and ecma_value_assign_number (line 1073); a value such as
1.5e300 walks from one to the next, so all three need the same treatment.

Move the range test in front of the cast in each function.  Values
outside the range fall through to ecma_create_float_number(), which is
what happened for every value the existing round-trip check rejected.

JerryScript-DCO-1.0-Signed-off-by: 1820893135-pixel <1820893135@qq.com>

This branch has not been deployed

No deployments
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.

[Bug]ecma_make_number_value casts out-of-range double to integer -> UBSan float-cast-overflow (SIGILL) (CWE-681)

1 participant