Skip to content

Commit

Permalink
LibC: Fix bug in scanf() family where we'd capture invalid data.
Browse files Browse the repository at this point in the history
  • Loading branch information
awesomekling committed Mar 20, 2019
1 parent 951377e commit cdb82f6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 50 deletions.
66 changes: 16 additions & 50 deletions LibC/scanf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
#include <string.h>
#include <ctype.h>

#define MAXLN 512

static const char* determine_base(const char* p, int& base)
{
if (p[0] == '0') {
Expand Down Expand Up @@ -119,54 +117,13 @@ int atob(unsigned int* vp, const char* p, int base)
return 0;
}

static int vfscanf(FILE*, const char*, va_list);
static int vsscanf(const char*, const char*, va_list);

#define ISSPACE " \t\n\r\f\v"

int scanf(const char* fmt, ...)
{
int count;
va_list ap;

va_start(ap, fmt);
count = vfscanf(stdin, fmt, ap);
va_end(ap);
return count;
}

int fscanf(FILE *fp, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vfscanf(fp, fmt, ap);
va_end(ap);
return count;
}

int sscanf(const char *buf, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vsscanf(buf, fmt, ap);
va_end(ap);
return count;
}

static int vfscanf(FILE *fp, const char* fmt, va_list ap)
{
char buf[MAXLN + 1];
if (!fgets(buf, MAXLN, fp))
return -1;
int count = vsscanf(buf, fmt, ap);
return count;
}

static int vsscanf(const char *buf, const char *s, va_list ap)
int vsscanf(const char *buf, const char *s, va_list ap)
{
int base = 10;
char *t;
char tmp[MAXLN];
char tmp[BUFSIZ];
bool noassign = false;
int count = 0;
int width = 0;
Expand Down Expand Up @@ -220,16 +177,25 @@ static int vsscanf(const char *buf, const char *s, va_list ap)
else if (*s == 'b')
base = 2;
if (!width) {
if (isspace(*(s + 1)) || *(s + 1) == 0)
if (isspace(*(s + 1)) || *(s + 1) == 0) {
width = strcspn(buf, ISSPACE);
else
width = strchr(buf, *(s + 1)) - buf;
} else {
auto* p = strchr(buf, *(s+1));
if (p)
width = p - buf;
else {
noassign = true;
width = 0;
}
}
}
strncpy(tmp, buf, width);
tmp[width] = '\0';
buf += width;
if (!noassign)
atob(va_arg(ap, uint32_t*), tmp, base);
if (!noassign) {
if (!atob(va_arg(ap, uint32_t*), tmp, base))
noassign = true;
}
}
if (!noassign)
++count;
Expand Down
36 changes: 36 additions & 0 deletions LibC/stdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,5 +424,41 @@ int remove(const char* pathname)
return rmdir(pathname);
}

int scanf(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vfscanf(stdin, fmt, ap);
va_end(ap);
return count;
}

int fscanf(FILE* stream, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vfscanf(stream, fmt, ap);
va_end(ap);
return count;
}

int sscanf(const char* buffer, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int count = vsscanf(buffer, fmt, ap);
va_end(ap);
return count;
}

int vfscanf(FILE* stream, const char* fmt, va_list ap)
{
char buffer[BUFSIZ];
if (!fgets(buffer, sizeof(buffer) - 1, stream))
return -1;
return vsscanf(buffer, fmt, ap);
}


}

2 changes: 2 additions & 0 deletions LibC/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ void perror(const char*);
int scanf(const char* fmt, ...);
int sscanf (const char* str, const char* fmt, ...);
int fscanf(FILE*, const char* fmt, ...);
int vfscanf(FILE*, const char*, va_list);
int vsscanf(const char*, const char*, va_list);
int setvbuf(FILE*, char* buf, int mode, size_t);
void setbuf(FILE*, char* buf);
void setlinebuf(FILE*);
Expand Down

0 comments on commit cdb82f6

Please sign in to comment.