mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-06 01:40:28 +00:00
Don't read invalid floating-point numbers in *scanf()
Currently, we just ignore any errors from `strtod()`. They can happen either because no valid float can be parsed at all, or because the state machine recognizes only a prefix of a valid floating-point number. Fix this by making sure `strtod()` parses everything we recognized, provided it's non-empty. This requires to pop the last character off the FP buffer, which is supposed to be parsed by the next `*scanf()` directive.
This commit is contained in:
parent
5fa42012da
commit
e5d877ba4f
2 changed files with 40 additions and 13 deletions
|
@ -50,6 +50,12 @@
|
|||
} \
|
||||
c; \
|
||||
})
|
||||
#define UNBUFFER \
|
||||
({ \
|
||||
if (c != -1) { \
|
||||
fpbuf[--fpbufcur] = '\0'; \
|
||||
} \
|
||||
})
|
||||
|
||||
/**
|
||||
* String / file / stream decoder.
|
||||
|
@ -369,10 +375,11 @@ int __vcscanf(int callback(void *), //
|
|||
}
|
||||
} while ((c = BUFFER) != -1 && c != ')');
|
||||
if (c == ')') {
|
||||
c = BUFFER;
|
||||
c = READ;
|
||||
}
|
||||
goto GotFloatingPointNumber;
|
||||
} else {
|
||||
UNBUFFER;
|
||||
goto GotFloatingPointNumber;
|
||||
}
|
||||
} else {
|
||||
|
@ -410,6 +417,7 @@ int __vcscanf(int callback(void *), //
|
|||
goto Done;
|
||||
}
|
||||
} else {
|
||||
UNBUFFER;
|
||||
goto GotFloatingPointNumber;
|
||||
}
|
||||
} else {
|
||||
|
@ -462,10 +470,24 @@ int __vcscanf(int callback(void *), //
|
|||
Continue:
|
||||
continue;
|
||||
Break:
|
||||
UNBUFFER;
|
||||
break;
|
||||
} while ((c = BUFFER) != -1);
|
||||
GotFloatingPointNumber:
|
||||
fp = strtod((char *)fpbuf, NULL);
|
||||
/* An empty buffer can't be a valid float; don't even bother parsing. */
|
||||
bool valid = fpbufcur > 0;
|
||||
if (valid) {
|
||||
char *ep;
|
||||
fp = strtod((char *)fpbuf, &ep);
|
||||
/* We should have parsed the whole buffer. */
|
||||
valid = ep == (char *)fpbuf + fpbufcur;
|
||||
}
|
||||
free(fpbuf);
|
||||
fpbuf = NULL;
|
||||
fpbufcur = fpbufsize = 0;
|
||||
if (!valid) {
|
||||
goto Done;
|
||||
}
|
||||
if (!discard) {
|
||||
++items;
|
||||
void *out = va_arg(va, void *);
|
||||
|
@ -475,9 +497,6 @@ int __vcscanf(int callback(void *), //
|
|||
*(double *)out = (double)fp;
|
||||
}
|
||||
}
|
||||
free(fpbuf);
|
||||
fpbuf = NULL;
|
||||
fpbufcur = fpbufsize = 0;
|
||||
continue;
|
||||
ReportConsumed:
|
||||
n_ptr = va_arg(va, int *);
|
||||
|
|
|
@ -394,6 +394,20 @@ TEST(sscanf, floating_point_infinity_double_precision) {
|
|||
EXPECT_TRUE(isinf(g));
|
||||
}
|
||||
|
||||
TEST(sscanf, floating_point_invalid) {
|
||||
float dummy;
|
||||
EXPECT_EQ(0, sscanf("junk", "%f", &dummy));
|
||||
EXPECT_EQ(0, sscanf("e9", "%f", &dummy));
|
||||
EXPECT_EQ(0, sscanf("-e9", "%f", &dummy));
|
||||
}
|
||||
|
||||
TEST(sscanf, floating_point_invalid_double_precision) {
|
||||
double dummy;
|
||||
EXPECT_EQ(0, sscanf("junk", "%lf", &dummy));
|
||||
EXPECT_EQ(0, sscanf("e9", "%lf", &dummy));
|
||||
EXPECT_EQ(0, sscanf("-e9", "%lf", &dummy));
|
||||
}
|
||||
|
||||
TEST(sscanf, floating_point_documentation_examples) {
|
||||
float a = 666.666f, b = a, c = b, d = c, e = d, f = e, g = f, h = g, i = h,
|
||||
j = i;
|
||||
|
@ -401,7 +415,7 @@ TEST(sscanf, floating_point_documentation_examples) {
|
|||
EXPECT_EQ(2, sscanf("111.11 -2.22", "%f %f", &a, &b));
|
||||
EXPECT_EQ(3, sscanf("Nan nan(2) inF", "%f %f %f", &c, &d, &e));
|
||||
EXPECT_EQ(
|
||||
5, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk",
|
||||
2, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk",
|
||||
"%f %f %f %f %f", &f, &g, &h, &i, &j));
|
||||
|
||||
EXPECT_EQ(111.11f, a);
|
||||
|
@ -411,9 +425,6 @@ TEST(sscanf, floating_point_documentation_examples) {
|
|||
EXPECT_TRUE(isinf(e));
|
||||
EXPECT_EQ(0X1.BC70A3D70A3D7P+6f, f);
|
||||
EXPECT_TRUE(isinf(g));
|
||||
EXPECT_EQ(-0.0000000123f, h);
|
||||
EXPECT_EQ(.0f, i);
|
||||
EXPECT_EQ(.0f, j);
|
||||
}
|
||||
|
||||
TEST(sscanf, floating_point_documentation_examples_double_precision) {
|
||||
|
@ -423,7 +434,7 @@ TEST(sscanf, floating_point_documentation_examples_double_precision) {
|
|||
EXPECT_EQ(2, sscanf("111.11 -2.22", "%lf %lf", &a, &b));
|
||||
EXPECT_EQ(3, sscanf("Nan nan(2) inF", "%lf %lf %lf", &c, &d, &e));
|
||||
EXPECT_EQ(
|
||||
5, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk",
|
||||
2, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk",
|
||||
"%lf %lf %lf %lf %lf", &f, &g, &h, &i, &j));
|
||||
|
||||
EXPECT_EQ(111.11, a);
|
||||
|
@ -433,9 +444,6 @@ TEST(sscanf, floating_point_documentation_examples_double_precision) {
|
|||
EXPECT_TRUE(isinf(e));
|
||||
EXPECT_EQ(0X1.BC70A3D70A3D7P+6, f);
|
||||
EXPECT_TRUE(isinf(g));
|
||||
EXPECT_EQ(-0.0000000123, h);
|
||||
EXPECT_EQ(.0, i);
|
||||
EXPECT_EQ(.0, j);
|
||||
}
|
||||
|
||||
TEST(sscanf, luplus) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue