mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-10-26 19:16:41 +00:00
* Fix reading the same symbol twice when using `{f,}scanf()`
PR #924 appears to use `unget()` subtly incorrectly when parsing
floating point numbers. The rest of the code only uses `unget()`
immediately followed by `goto Done;` to return back the symbol that
can't possibly belong to the directive we're processing.
With floating-point, however, the ungot characters could very well
be valid for the *next* directive, so we will essentially read them
twice. It can't be seen in `sscanf()` tests because `unget()` is a
no-op there, but the test I added for `fscanf()` fails like this:
...
EXPECT_EQ(0xDEAD, i1)
need 57005 (or 0xdead) =
got 908973 (or 0x000ddead)
...
EXPECT_EQ(0xBEEF, i2)
need 48879 (or 0xbeef) =
got 769775 (or 0x000bbeef)
This means we read 0xDDEAD instead of 0xDEAD and 0xBBEEF instead of
0xBEEF. I checked that both musl and glibc read 0xDEAD/0xBEEF, as
expected.
Fix the failing test by removing the unneeded `unget()` calls.
* 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.
* Make `%c` parsing in `*scanf()` respect the C standard
Currently, `%c`-style directives always succeed even if there
are actually fewer characters in the input than requested.
Before the fix, the added test fails like this:
...
EXPECT_EQ(2, sscanf("ab", "%c %c %c", &c2, &c3, &c4))
need 2 (or 0x02 or '\2' or ENOENT) =
got 3 (or 0x03 or '\3' or ESRCH)
...
EXPECT_EQ(0, sscanf("abcd", "%5c", s2))
need 0 (or 0x0 or '\0') =
got 1 (or 0x01 or '\1' or EPERM)
musl and glibc pass this test.
|
||
|---|---|---|
| .. | ||
| BUILD.mk | ||
| crypt_test.c | ||
| devrand_test.c | ||
| dirstream_test.c | ||
| dtoa_test.c | ||
| dumphexc_test.c | ||
| ecvt_test.c | ||
| fds_torture_test.c | ||
| fgetln_test.c | ||
| fgets_test.c | ||
| fgetwc_test.c | ||
| fmemopen_test.c | ||
| fmt_test.c | ||
| fprintf_test.c | ||
| fputc_test.c | ||
| fputs_test.c | ||
| fread_test.c | ||
| freopen_test.c | ||
| fscanf_test.c | ||
| fseeko_test.c | ||
| ftell_test.c | ||
| fwrite_test.c | ||
| getdelim_test.c | ||
| getentropy_test.c | ||
| gz_test.c | ||
| iconv_test.c | ||
| joinstrlist_test.c | ||
| memory_test.c | ||
| mt19937_test.c | ||
| palandprintf_test.c | ||
| popen_test.c | ||
| rand_test.c | ||
| rngset_test.c | ||
| snprintf_test.c | ||
| sprintf_s.inc | ||
| sprintf_s_test.c | ||
| sscanf_test.c | ||
| tmpfile_test.c | ||
| ungetc_test.c | ||
| vappendf_test.c | ||
| zipdir_test.c | ||