mirror of git://git.musl-libc.org/musl
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
This commit is contained in:
parent
c68b26369e
commit
e898a79053
|
@ -2,6 +2,11 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.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)
|
long double strtold(const char *s1, char **p)
|
||||||
{
|
{
|
||||||
const unsigned char *s = (void *)s1;
|
const unsigned char *s = (void *)s1;
|
||||||
|
@ -11,6 +16,7 @@ long double strtold(const char *s1, char **p)
|
||||||
int nonzero = 0;
|
int nonzero = 0;
|
||||||
int radix = '.';
|
int radix = '.';
|
||||||
long e;
|
long e;
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
if (!p) p = (char **)&s1;
|
if (!p) p = (char **)&s1;
|
||||||
|
|
||||||
|
@ -41,26 +47,23 @@ long double strtold(const char *s1, char **p)
|
||||||
/* We have a real hex float */
|
/* We have a real hex float */
|
||||||
s += 2;
|
s += 2;
|
||||||
for (; isxdigit(*s); s++) {
|
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!='0') nonzero=1;
|
||||||
}
|
}
|
||||||
if (*s == radix) {
|
if (*s == radix) {
|
||||||
frac = 1.0/16.0;
|
frac = 1.0/16.0;
|
||||||
for (s++; isxdigit(*s); s++) {
|
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;
|
frac *= 1.0/16.0;
|
||||||
if (*s!='0') nonzero=1;
|
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);
|
e = strtol((void *)(s+1), (void *)&s, 10);
|
||||||
for (; e>0; e--) x *= 2.0;
|
for (; e>0; e--) x *= 2.0;
|
||||||
for (; e<0; e++) x *= 0.5;
|
for (; e<0; e++) x *= 0.5;
|
||||||
}
|
}
|
||||||
if ((nonzero && !x) || !(1.0/x))
|
goto finish;
|
||||||
errno = ERANGE;
|
|
||||||
*p = (char *)s;
|
|
||||||
return sign ? -x : x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mantissa must be non-degenerate */
|
/* Mantissa must be non-degenerate */
|
||||||
|
@ -81,13 +84,13 @@ long double strtold(const char *s1, char **p)
|
||||||
if (*s!='0') nonzero=1;
|
if (*s!='0') nonzero=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((*s|32)=='e') {
|
if ((*s|32)=='e' && valid_exp(s+1)) {
|
||||||
e = strtol((void *)++s, (void *)&s, 10);
|
e = strtol((void *)++s, (void *)&s, 10);
|
||||||
for (; e>0; e--) x *= 10.0;
|
for (; e>0; e--) x *= 10.0;
|
||||||
for (; e<0; e++) x /= 10.0;
|
for (; e<0; e++) x /= 10.0;
|
||||||
}
|
}
|
||||||
if ((nonzero && !x) || !(1.0/x))
|
finish:
|
||||||
errno = ERANGE;
|
errno = ((nonzero && !x) || !(1.0/x)) ? ERANGE : saved_errno;
|
||||||
*p = (char*)s;
|
*p = (char*)s;
|
||||||
return sign ? -x : x;
|
return sign ? -x : x;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue