@@ -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