diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-04-03 18:44:37 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-04-03 18:44:37 -0400 |
commit | e898a790538ba4c1b7fdb0d16e1cc4c98dd84185 (patch) | |
tree | 2c5466e01de852178243588dea075efe99676696 /src/stdlib/strtold.c | |
parent | c68b26369e89ead7511ef113850035775c5d183d (diff) | |
download | musl-e898a790538ba4c1b7fdb0d16e1cc4c98dd84185.tar.gz musl-e898a790538ba4c1b7fdb0d16e1cc4c98dd84185.tar.bz2 musl-e898a790538ba4c1b7fdb0d16e1cc4c98dd84185.tar.xz musl-e898a790538ba4c1b7fdb0d16e1cc4c98dd84185.zip |
fix various bugs in strtold:
0e10000000000000000000000000000000 was setting ERANGE
exponent char e/p was considered part of the match even if not
followed by a valid decimal value
"1e +10" was parsed as "1e+10"
hex digits were misinterpreted as 0..5 instead of 10..15
Diffstat (limited to 'src/stdlib/strtold.c')
-rw-r--r-- | src/stdlib/strtold.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c index 73f2b082..ec464c15 100644 --- a/src/stdlib/strtold.c +++ b/src/stdlib/strtold.c @@ -2,6 +2,11 @@ #include <errno.h> #include <ctype.h> +static int valid_exp(const unsigned char *s) +{ + return isdigit(*s) || ((s[0]=='+'||s[0]=='-') && isdigit(s[1])); +} + long double strtold(const char *s1, char **p) { const unsigned char *s = (void *)s1; @@ -11,6 +16,7 @@ long double strtold(const char *s1, char **p) int nonzero = 0; int radix = '.'; long e; + int saved_errno = errno; if (!p) p = (char **)&s1; @@ -41,26 +47,23 @@ long double strtold(const char *s1, char **p) /* We have a real hex float */ s += 2; for (; isxdigit(*s); s++) { - x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a'); + x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a'+10); if (*s!='0') nonzero=1; } if (*s == radix) { frac = 1.0/16.0; for (s++; isxdigit(*s); s++) { - x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a'); + x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a'+10); frac *= 1.0/16.0; if (*s!='0') nonzero=1; } } - if ((*s|32) == 'p') { + if ((*s|32) == 'p' && valid_exp(s+1)) { e = strtol((void *)(s+1), (void *)&s, 10); for (; e>0; e--) x *= 2.0; for (; e<0; e++) x *= 0.5; } - if ((nonzero && !x) || !(1.0/x)) - errno = ERANGE; - *p = (char *)s; - return sign ? -x : x; + goto finish; } /* Mantissa must be non-degenerate */ @@ -81,13 +84,13 @@ long double strtold(const char *s1, char **p) if (*s!='0') nonzero=1; } } - if ((*s|32)=='e') { + if ((*s|32)=='e' && valid_exp(s+1)) { e = strtol((void *)++s, (void *)&s, 10); for (; e>0; e--) x *= 10.0; for (; e<0; e++) x /= 10.0; } - if ((nonzero && !x) || !(1.0/x)) - errno = ERANGE; +finish: + errno = ((nonzero && !x) || !(1.0/x)) ? ERANGE : saved_errno; *p = (char*)s; return sign ? -x : x; } |