Skip to content

Commit

Permalink
options/ansi: better do_scanf EOF handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathewnd committed May 7, 2024
1 parent 2db1f93 commit 47552ad
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 15 deletions.
45 changes: 30 additions & 15 deletions options/ansi/generic/stdio-stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,10 @@ static void store_int(void *dest, unsigned int size, unsigned long long i) {

template<typename H>
static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
#define NOMATCH_CHECK(cond) if(cond) return match_count // if cond is true, matching error
#define EOF_CHECK(cond) if(cond) return match_count ? match_count : EOF // if cond is true, no more data to read
int match_count = 0;
for (; *fmt; fmt++) {

if (isspace(*fmt)) {
while (isspace(fmt[1])) fmt++;
while (isspace(handler.look_ahead()))
Expand All @@ -363,8 +364,8 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
if (*fmt == '%')
fmt++;
char c = handler.consume();
if (c != *fmt)
break;
EOF_CHECK(c == '\0');
NOMATCH_CHECK(c != *fmt);
continue;
}

Expand Down Expand Up @@ -468,8 +469,10 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
case 'i': {
bool is_negative = false;
unsigned long long res = 0;
char c = handler.look_ahead();
EOF_CHECK(c == '\0');

if((*fmt == 'i' || *fmt == 'd') && handler.look_ahead() == '-') {
if((*fmt == 'i' || *fmt == 'd') && c == '-') {
handler.consume();
is_negative = true;
}
Expand All @@ -484,26 +487,18 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
}
}

char c = handler.look_ahead();
c = handler.look_ahead();
int count = 0;
switch (base) {
case 10:
if(!isdigit(c))
return match_count;
NOMATCH_CHECK(!isdigit(c));
while (c >= '0' && c <= '9') {
handler.consume();
res = res * 10 + (c - '0');
c = handler.look_ahead();
}
break;
case 16:
if (c == '0') {
handler.consume();
c = handler.look_ahead();
if (c == 'x') {
handler.consume();
c = handler.look_ahead();
}
}
while (true) {
if (c >= '0' && c <= '9') {
handler.consume();
Expand All @@ -517,8 +512,10 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
} else {
break;
}
count++;
c = handler.look_ahead();
}
NOMATCH_CHECK(count == 0);
break;
case 8:
while (c >= '0' && c <= '7') {
Expand All @@ -527,6 +524,7 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
c = handler.look_ahead();
}
break;
// no need for a match check, the starting 0 was already consumed
}
if (dest) {
if(is_negative)
Expand All @@ -539,6 +537,8 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
case 'o': {
unsigned long long res = 0;
char c = handler.look_ahead();
EOF_CHECK(c == '\0');
NOMATCH_CHECK(!(c >= '0' && c <= '7'));
while (c >= '0' && c <= '7') {
handler.consume();
res = res * 8 + (c - '0');
Expand All @@ -552,6 +552,8 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
case 'X': {
unsigned long long res = 0;
char c = handler.look_ahead();
int count = 0;
EOF_CHECK(c == '\0');
if (c == '0') {
handler.consume();
c = handler.look_ahead();
Expand All @@ -573,8 +575,10 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
} else {
break;
}
count++;
c = handler.look_ahead();
}
NOMATCH_CHECK(count == 0);
if (dest)
store_int(dest, type, res);
break;
Expand All @@ -583,6 +587,7 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
char *typed_dest = (char *)dest;
char c = handler.look_ahead();
int count = 0;
EOF_CHECK(c == '\0');
while (c && !isspace(c)) {
handler.consume();
if (typed_dest)
Expand All @@ -592,13 +597,15 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
if (width && count >= width)
break;
}
NOMATCH_CHECK(count == 0);
if (typed_dest)
typed_dest[count] = '\0';
break;
}
case 'c': {
char *typed_dest = (char *)dest;
char c = handler.look_ahead();
EOF_CHECK(c == '\0');
int count = 0;
if (!width)
width = 1;
Expand Down Expand Up @@ -644,6 +651,7 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
char *typed_dest = (char *)dest;
int count = 0;
char c = handler.look_ahead();
EOF_CHECK(c == '\0');
while (c && (!width || count < width)) {
handler.consume();
if (!scanset[1 + c])
Expand All @@ -653,13 +661,17 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
c = handler.look_ahead();
count++;
}
NOMATCH_CHECK(count == 0);
if (typed_dest)
typed_dest[count] = '\0';
break;
}
case 'p': {
unsigned long long res = 0;
char c = handler.look_ahead();
int count = 0;
EOF_CHECK(c == '\0');

if (c == '0') {
handler.consume();
c = handler.look_ahead();
Expand All @@ -668,6 +680,7 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
c = handler.look_ahead();
}
}

while (true) {
if (c >= '0' && c <= '9') {
handler.consume();
Expand All @@ -681,8 +694,10 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) {
} else {
break;
}
count++;
c = handler.look_ahead();
}
NOMATCH_CHECK(count == 0);
void **typed_dest = (void **)dest;
*typed_dest = (void *)(uintptr_t)res;
break;
Expand Down
8 changes: 8 additions & 0 deletions tests/ansi/sscanf.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ struct format_test_cases {
{"%%", "%", 0, T_NONE, 0},
{"%c", " I am not a fan of this solution.", ' ', T_CHAR, 1},
{" %c", " CBT (capybara therapy)", 'C', T_CHAR, 1},
{"%d %d %d", " 111111 I<3Managarm 1234", 111111, T_UINT, 1},
{"%c %d", "C", 'C', T_CHAR, 1}
};

#pragma GCC diagnostic ignored "-Wformat-security"
Expand Down Expand Up @@ -137,6 +139,12 @@ int main() {
assert(!ret);
}

{
char buf[50];
int ret = sscanf("", "%s", buf);
assert(ret == EOF);
}

test_matrix();

return 0;
Expand Down

0 comments on commit 47552ad

Please sign in to comment.