Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

options/ansi: better do_scanf EOF and matching error handling #1060

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading