Skip to content

Commit 3a15430

Browse files
committed
fix(js): float.fromhex is easy to overflow, as sizeof(int) is 4 when JS
1 parent f402c2a commit 3a15430

File tree

1 file changed

+26
-18
lines changed

1 file changed

+26
-18
lines changed

src/pylib/numTypes/floats/floathex.nim

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
from std/parseutils import skipWhile, parseInt
2+
import std/parseutils # skipWhile, parseInt, parseBiggestInt
33
from std/strutils import find, initSkipTable, isSpaceAscii, toLowerAscii,
44
HexDigits
55
import std/fenv
@@ -99,9 +99,6 @@ func hexImpl*(x: float): string =
9999
template IS_SPACE(c): bool = isSpaceAscii(c)
100100

101101
func floatFromhexImpl*(s: string): float =
102-
const
103-
LONG_MAXd2 = high(int) div 2
104-
LONG_MINd2 = low(int) div 2
105102
#[For the sake of simplicity and correctness, we impose an artificial
106103
limit on ndigits, the total number of hex digits in the coefficient
107104
The limit is chosen to ensure that, writing exp for the exponent,
@@ -148,9 +145,18 @@ func floatFromhexImpl*(s: string): float =
148145
let
149146
s_hi = s.high
150147
s_end = s.len
151-
var
152-
exp: int
153-
negate = false
148+
when sizeof(int) >= 8:
149+
var exp: int
150+
const intExp = true
151+
else:
152+
var exp: BiggestInt
153+
const intExp = false
154+
type TExp = typeof(exp)
155+
const
156+
LONG_MAXd2 = high(TExp) div 2
157+
LONG_MINd2 = low(TExp) div 2
158+
var negate = false
159+
154160

155161
template raiseValueError(msg) =
156162
raise newException(ValueError, msg)
@@ -227,14 +233,16 @@ func floatFromhexImpl*(s: string): float =
227233
parse_error
228234
step
229235
while inBound and cur in '0'..'9':
230-
step
231-
let n = parseInt(s, exp, exp_start)
236+
step
237+
let n =
238+
when intExp: parseInt(s, exp, exp_start)
239+
else: parseBiggestInt(s, exp, exp_start)
232240
assert n != 0
233241
else:
234242
exp = 0
235243

236244
# for 0 <= j < ndigits, HEX_DIGIT(j) gives the jth most significant digit
237-
template HEX_DIGIT(j): int =
245+
template HEX_DIGIT(j: int): int =
238246
hex_from_char(s[
239247
if j < fdigits: coeff_end-j
240248
else: coeff_end-1-j
@@ -261,10 +269,10 @@ func floatFromhexImpl*(s: string): float =
261269
overflow_error
262270

263271
# Adjust exponent for fractional part.
264-
exp -= 4*fdigits
272+
exp -= TExp 4*fdigits
265273

266274
# top_exp = 1 more than exponent of most sig. bit of coefficient
267-
var top_exp = exp + 4*(ndigits - 1)
275+
var top_exp = exp + 4*(ndigits.TExp - 1)
268276
var digits = HEX_DIGIT(ndigits-1)
269277
while digits != 0:
270278
top_exp.inc
@@ -279,7 +287,7 @@ func floatFromhexImpl*(s: string): float =
279287

280288
# lsb = exponent of least significant bit of the *rounded* value
281289
# This is top_exp - DBL_MANT_DIG unless result is subnormal.
282-
let lsb = max(top_exp, int(DBL_MIN_EXP)) - DBL_MANT_DIG
290+
let lsb = max(top_exp, DBL_MIN_EXP.TExp) - TExp DBL_MANT_DIG
283291

284292
result = 0.0
285293
template handleInTill(till) =
@@ -288,16 +296,16 @@ func floatFromhexImpl*(s: string): float =
288296
if exp >= lsb:
289297
# no rounding required
290298
handleInTill 0
291-
result = ldexp(result, exp)
299+
result = ldexp(result, exp.int)
292300
finished
293301
# rounding required. key_digit is the index of the hex digit
294302
# containing the first bit to be rounded away.
295303
let
296-
half_eps = 1 shl ((lsb - exp - 1) mod 4)
297-
key_digit = (lsb - exp - 1) div 4
304+
half_eps = 1 shl (cast[int](lsb - exp - 1) mod 4)
305+
key_digit = int(lsb - exp - 1) div 4
298306
handleInTill key_digit+1
299307
let digit = HEX_DIGIT(key_digit)
300-
result = 16.0*result + float(digit and (16-2*half_eps))
308+
result = 16.0*result + float(digit.TExp and (16-2*half_eps))
301309

302310
# round-half-even: round up if bit lsb-1 is 1 and at least one of
303311
# bits lsb, lsb-2, lsb-3, lsb-4, ... is 1.
@@ -320,5 +328,5 @@ func floatFromhexImpl*(s: string): float =
320328
# overflow corner case:
321329
# pre-rounded value < 2**DBL_MAX_EXP; rounded=2**DBL_MAX_EXP.
322330
overflow_error
323-
result = ldexp(result, exp+4*key_digit)
331+
result = ldexp(result, int exp+4*key_digit)
324332
finished

0 commit comments

Comments
 (0)