diff --git a/libc/stdio/vcscanf.c b/libc/stdio/vcscanf.c index c11a21e49..bf2b9ff36 100644 --- a/libc/stdio/vcscanf.c +++ b/libc/stdio/vcscanf.c @@ -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 *); diff --git a/test/libc/stdio/sscanf_test.c b/test/libc/stdio/sscanf_test.c index 571617715..295706748 100644 --- a/test/libc/stdio/sscanf_test.c +++ b/test/libc/stdio/sscanf_test.c @@ -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) {