Fix scanf x specifier with string of 0 ()

The C standard states that, in the context of an x conversion
specifier given to scanf:
> Matches an optionally signed hexadecimal integer, whose format is
> the same as expected for the subject sequence of the strtoul
> function with the value 16 for the base argument.
- C standard, 7.23.6.2.11. The fscanf function

Cosmopolitan fails to do this, as 0 should be parsed as a 0 by such an
invocation of strtoul. Instead, cosmopolitan errors out as though such
input is invalid, which is wrong.

This means that a program such as this:

 #include <stdio.h>
 #undef NDEBUG
 #include <assert.h>

int main()
{
    int v = 0;
    assert(sscanf("0", "%x", &v) == 1);
}

will not run correctly on cosmpolitan, instead failing the assertion.

This patch fixes this, along with the associated GitHub issue,
https://github.com/jart/cosmopolitan/issues/778
This commit is contained in:
Gabriel Ravier 2023-04-15 15:25:35 +02:00 committed by GitHub
parent 12e07798df
commit 9a5d69c842
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 0 deletions
libc/fmt
test/libc/fmt

View file

@ -174,6 +174,8 @@ int vcscanf(int callback(void *), int unget(int, void *), void *arg,
c = callback(arg);
if (c == prefix || c == prefix + ('a' - 'A')) {
c = callback(arg);
} else if (c == -1) {
c = '0';
}
}
DecodeNumber:

View file

@ -231,3 +231,31 @@ TEST(sscanf, testInttypes_macros) {
ASSERT_EQ(if64, 1);
ASSERT_EQ(uf64, 1);
}
TEST(sscanf, test0) {
int v;
v = 0xFFFFFFFF;
ASSERT_EQ(sscanf("0", "%x", &v), 1);
ASSERT_EQ(v, 0);
v = 0xFFFFFFFF;
ASSERT_EQ(sscanf("0", "%X", &v), 1);
ASSERT_EQ(v, 0);
v = 0xFFFFFFFF;
ASSERT_EQ(sscanf("0", "%d", &v), 1);
ASSERT_EQ(v, 0);
v = 0xFFFFFFFF;
ASSERT_EQ(sscanf("0", "%o", &v), 1);
ASSERT_EQ(v, 0);
v = 0xFFFFFFFF;
ASSERT_EQ(sscanf("0", "%u", &v), 1);
ASSERT_EQ(v, 0);
v = 0xFFFFFFFF;
ASSERT_EQ(sscanf("0", "%b", &v), 1);
ASSERT_EQ(v, 0);
}