safeclib/sscanf_s.c

96 lines
2.8 KiB
C

EXPORT int sscanf_s(const char *restrict buffer, const char *restrict fmt, ...) {
va_list ap;
int ret;
#if defined(HAVE_STRSTR)
char *p;
#endif
const char *temp_fmt = fmt;
if (unlikely(buffer == NULL)) {
invoke_safe_str_constraint_handler("sscanf_s: buffer is null", NULL, ESNULLP);
errno = ESNULLP;
return EOF;
}
if (unlikely(fmt == NULL)) {
invoke_safe_str_constraint_handler("sscanf_s: fmt is null", NULL, ESNULLP);
errno = ESNULLP;
return EOF;
}
#if defined(HAVE_STRSTR)
if (unlikely((p = strstr((char *)fmt, "%n")))) {
if ((p - fmt == 0) || *(p - 1) != '%') {
invoke_safe_str_constraint_handler("sscanf_s: illegal %n", NULL, EINVAL);
errno = EINVAL;
return EOF;
}
}
#elif defined(HAVE_STRCHR)
/* Assuming 'flen' is the length of 'fmt' */
size_t flen = strlen(fmt);
if (unlikely((p = strchr(fmt, flen, 'n')))) {
if (((p - fmt >= 1) && *(p - 1) == '%') && ((p - fmt == 1) || *(p - 2) != '%')) {
invoke_safe_str_constraint_handler("sscanf_s: illegal %n", NULL, EINVAL);
errno = EINVAL;
return EOF;
}
}
#endif
va_start(ap, fmt);
while (*temp_fmt) {
if (*temp_fmt == '%') {
temp_fmt++;
if (*temp_fmt == 's') {
char *buf = va_arg(ap, char*);
rsize_t bufsize = va_arg(ap, rsize_t);
if (!buf || bufsize > RSIZE_MAX) {
va_end(ap);
invoke_safe_str_constraint_handler("sscanf_s: buffer error", NULL, EINVAL);
errno = EINVAL;
return EOF;
}
temp_fmt++;
} else if (*temp_fmt == 'c' || *temp_fmt == '[') {
char *buf = va_arg(ap, char*);
rsize_t bufsize = va_arg(ap, rsize_t);
if (bufsize != 1) {
va_end(ap);
invoke_safe_str_constraint_handler("sscanf_s: buffer size error", NULL, EINVAL);
errno = EINVAL;
return EOF;
}
temp_fmt++;
} else {
temp_fmt++;
}
} else {
temp_fmt++;
}
}
va_end(ap);
va_start(ap, fmt);
ret = vsscanf(buffer, fmt, ap);
va_end(ap);
if (unlikely(ret < 0)) {
char errstr[128] = "sscanf_s: ";
strcat(errstr, strerror(errno));
invoke_safe_str_constraint_handler(errstr, NULL, errno);
}
return ret;
}
void test_sscanf_s() {
const char *input = "cherry 789";
char buf[10];
int num;
assert(sscanf_s(input, "%9s %d", buf, sizeof(buf), &num) == 2);
assert(strcmp(buf, "cherry") == 0);
assert(num == 789);
}