Skip to content

Commit

Permalink
Limit exponent range in number parsing.
Browse files Browse the repository at this point in the history
Reported by XmiliaH.

(cherry-picked from commit e560487)

When parsing exponent powers greater than (1 << 16) * 10 == (65536 *
10), the exponent values are cut without handling any values greater.
This patch fixes the behaviour, but restricts the power maximum value by
`STRSCAN_MAXEXP` (1 << 20).

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#9145
  • Loading branch information
Mike Pall authored and Buristan committed Nov 21, 2023
1 parent fef60a1 commit cf5d403
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/lj_strscan.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#define STRSCAN_MAXDIG 800 /* 772 + extra are sufficient. */
#define STRSCAN_DDIG (STRSCAN_DIG/2)
#define STRSCAN_DMASK (STRSCAN_DDIG-1)
#define STRSCAN_MAXEXP (1 << 20)

/* Helpers for circular buffer. */
#define DNEXT(a) (((a)+1) & STRSCAN_DMASK)
Expand Down Expand Up @@ -449,6 +450,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, MSize len, TValue *o,
if (dig) {
ex = (int32_t)(dp-(p-1)); dp = p-1;
while (ex < 0 && *dp-- == '0') ex++, dig--; /* Skip trailing zeros. */
if (ex <= -STRSCAN_MAXEXP) return STRSCAN_ERROR;
if (base == 16) ex *= 4;
}
}
Expand All @@ -462,7 +464,8 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, MSize len, TValue *o,
if (!lj_char_isdigit(*p)) return STRSCAN_ERROR;
xx = (*p++ & 15);
while (lj_char_isdigit(*p)) {
if (xx < 65536) xx = xx * 10 + (*p & 15);
xx = xx * 10 + (*p & 15);
if (xx >= STRSCAN_MAXEXP) return STRSCAN_ERROR;
p++;
}
ex += negx ? -(int32_t)xx : (int32_t)xx;
Expand Down
29 changes: 29 additions & 0 deletions test/tarantool-tests/lj-788-limit-exponents-range.test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
local tap = require('tap')

-- Test file to demonstrate incorrect behaviour of exponent number
-- form parsing.
-- See also: https://github.com/LuaJIT/LuaJIT/issues/788.
local test = tap.test('lj-788-limit-exponents-range')
test:plan(2)

-- Before the patch, the powers greater than (1 << 16) * 10
-- (655360) were parsed incorrectly. After the patch, powers
-- greater than 1 << 20 (1048576 `STRSCAN_MAXEXP`) are considered
-- invalid. See <src/lj_strscan.c> for details.
-- Choose the first value between these values and the second
-- value bigger than `STRSCAN_MAXEXP` to check parsing correctness
-- for the first one, and `STRSCAN_ERROR` for the second case.
local PARSABLE_EXP_POWER = 1000000
local TOO_LARGE_EXP_POWER = 1050000

local function form_exp_string(n)
return '0.' .. string.rep('0', n - 1) .. '1e' .. tostring(n)
end

test:is(tonumber(form_exp_string(PARSABLE_EXP_POWER)), 1,
'correct parsing of large exponent')

test:is(tonumber(form_exp_string(TOO_LARGE_EXP_POWER)), nil,
'too big exponent power is not parsed')

test:done(true)

0 comments on commit cf5d403

Please sign in to comment.