perl #126582 hexfp overflow drops hi-order bits
authorJarkko Hietaniemi <jhi@iki.fi>
Fri, 6 Nov 2015 23:54:16 +0000 (18:54 -0500)
committerJarkko Hietaniemi <jhi@iki.fi>
Sat, 7 Nov 2015 13:51:57 +0000 (08:51 -0500)
t/op/hexfp.t
toke.c

index 30aaf11..e83050e 100644 (file)
@@ -10,7 +10,7 @@ use strict;
 
 use Config;
 
-plan(tests => 79);
+plan(tests => 85);
 
 # Test hexfloat literals.
 
@@ -169,9 +169,27 @@ SKIP:
 
         eval '0x1.fffffffffffffp+1024';
         like(get_warn(), qr/^Hexadecimal float: exponent overflow/);
+
+        undef $a;
+        eval '$a = 0x111.0000000000000p+0'; # 12 zeros.
+        like(get_warn(), qr/^Hexadecimal float: mantissa overflow/);
+        is($a, 273);
+
+        # The 13 zeros would be enough to push the hi-order digits
+        # off the high-end.
+
+        undef $a;
+        eval '$a = 0x111.0000000000000p+0'; # 13 zeros.
+        like(get_warn(), qr/^Hexadecimal float: mantissa overflow/);
+        is($a, 273);
+
+        undef $a;
+        eval '$a = 0x111.00000000000000p+0';  # 14 zeros.
+        like(get_warn(), qr/^Hexadecimal float: mantissa overflow/);
+        is($a, 273);
     } else {
         print "# skipping warning tests\n";
-        skip "nv_preserves_uv_bits is $Config{nv_preserves_uv_bits} not 53", 8;
+        skip "nv_preserves_uv_bits is $Config{nv_preserves_uv_bits} not 53", 14;
     }
 }
 
diff --git a/toke.c b/toke.c
index b1bdfad..9f56573 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -10470,21 +10470,21 @@ Perl_scan_num(pTHX_ const char *start, YYSTYPE* lvalp)
 #ifdef HEXFP_NV
                     NV mult = 1 / 16.0;
 #endif
-                    h++;
-                    while (isXDIGIT(*h) || *h == '_') {
+                    for (h++; (isXDIGIT(*h) || *h == '_'); h++) {
                         if (isXDIGIT(*h)) {
                             U8 b = XDIGIT_VALUE(*h);
                             total_bits += shift;
+                            if (total_bits < NV_MANT_DIG) {
 #ifdef HEXFP_UQUAD
-                            hexfp_uquad <<= shift;
-                            hexfp_uquad |= b;
-                            hexfp_frac_bits += shift;
+                                hexfp_uquad <<= shift;
+                                hexfp_uquad |= b;
+                                hexfp_frac_bits += shift;
 #else /* HEXFP_NV */
-                            hexfp_nv += b * mult;
-                            mult /= 16.0;
+                                hexfp_nv += b * mult;
+                                mult /= 16.0;
 #endif
+                            }
                         }
-                        h++;
                     }
                 }