Skip to content

Commit bd5b5b5

Browse files
committed
grok_bin_oct_hex: Improve overflow detection
The new scheme is is what toke.c already uses for the same purpose, and I think is cleaner
1 parent c202865 commit bd5b5b5

File tree

1 file changed

+10
-5
lines changed

1 file changed

+10
-5
lines changed

numeric.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,6 @@ Perl_grok_bin_oct_hex(pTHX_ const char *start,
497497
bool overflowed = FALSE;
498498
NV value_nv = 0;
499499
const PERL_UINT_FAST8_T base = 1 << shift; /* 2, 8, or 16 */
500-
const UV max_div= UV_MAX / base; /* Value above which, the next digit
501-
processed would overflow */
502500

503501
for (; s < e; s++) {
504502
if (generic_isCC_(*s, class_bit)) {
@@ -507,9 +505,16 @@ Perl_grok_bin_oct_hex(pTHX_ const char *start,
507505
With gcc seems to be much straighter code than old scan_hex.
508506
(khw suspects that adding a LIKELY() just above would do the
509507
same thing) */
510-
redo:
511-
if (LIKELY(value <= max_div)) {
512-
value = (value << shift) | XDIGIT_VALUE(*s);
508+
redo: ;
509+
510+
/* Make room for the next digit */
511+
UV tentative_value = value << shift;
512+
513+
/* If shiftng back doesn't yield the previous value, it was
514+
* because a bit got shifted off the left end, so overflowed.
515+
* But if it worked, add the new digit. */
516+
if (LIKELY((tentative_value >> shift) == value)) {
517+
value = tentative_value | XDIGIT_VALUE(*s);
513518
/* Note XDIGIT_VALUE() is branchless, works on binary
514519
* and octal as well, so can be used here, without
515520
* slowing those down */

0 commit comments

Comments
 (0)