make floatscan correctly set errno for overflow/underflow
[musl] / src / internal / floatscan.c
index dbe0798..aa962f4 100644 (file)
@@ -24,6 +24,8 @@
 
 #define MASK (KMAX-1)
 
+#define CONCAT2(x,y) x ## y
+#define CONCAT(x,y) CONCAT2(x,y)
 
 static long long scanexp(FILE *f, int pok)
 {
@@ -63,6 +65,8 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po
        int gotdig = 0, gotrad = 0;
        int rp;
        int e2;
+       int emax = -emin-bits+3;
+       int denormal = 0;
        long double y;
        long double frac=0;
        long double bias=0;
@@ -250,6 +254,7 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po
        if (bits > LDBL_MANT_DIG+e2-emin) {
                bits = LDBL_MANT_DIG+e2-emin;
                if (bits<0) bits=0;
+               denormal = 1;
        }
 
        /* Calculate bias term to force rounding, move out lower bits */
@@ -280,11 +285,18 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po
        y += frac;
        y -= bias;
 
-       y = scalbnl(y, e2);
-
-       if (!y) errno = ERANGE;
+       if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) {
+               if (fabs(y) >= CONCAT(0x1p, LDBL_MANT_DIG)) {
+                       if (denormal && bits==LDBL_MANT_DIG+e2-emin)
+                               denormal = 0;
+                       y *= 0.5;
+                       e2++;
+               }
+               if (e2+LDBL_MANT_DIG>emax || (denormal && frac))
+                       errno = ERANGE;
+       }
 
-       return y;
+       return scalbnl(y, e2);
 }
 
 static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok)