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-03-29 10:48:38 +02:00
parent 7f925e6be9
commit 4d1747f090
2 changed files with 30 additions and 0 deletions

View file

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

View file

@ -231,3 +231,31 @@ TEST(sscanf, testInttypes_macros) {
ASSERT_EQ(if64, 1); ASSERT_EQ(if64, 1);
ASSERT_EQ(uf64, 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);
}