[sanitizer] scanf: don't report stores that did not happen.
Respect REAL(scanf) return value and don't report memory stores that could potentially happen, but did not. llvm-svn: 174887
This commit is contained in:
parent
c5f44bc62d
commit
455c72d25e
|
|
@ -157,7 +157,8 @@ INTERCEPTOR(int, vscanf, const char *format, va_list ap) { // NOLINT
|
||||||
va_list aq;
|
va_list aq;
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
int res = REAL(vscanf)(format, ap); // NOLINT
|
int res = REAL(vscanf)(format, ap); // NOLINT
|
||||||
scanf_common(ctx, format, aq);
|
if (res > 0)
|
||||||
|
scanf_common(ctx, res, format, aq);
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +170,8 @@ INTERCEPTOR(int, vsscanf, const char *str, const char *format, // NOLINT
|
||||||
va_list aq;
|
va_list aq;
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
int res = REAL(vsscanf)(str, format, ap); // NOLINT
|
int res = REAL(vsscanf)(str, format, ap); // NOLINT
|
||||||
scanf_common(ctx, format, aq);
|
if (res > 0)
|
||||||
|
scanf_common(ctx, res, format, aq);
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
// FIXME: read of str
|
// FIXME: read of str
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -182,7 +184,8 @@ INTERCEPTOR(int, vfscanf, void *stream, const char *format, // NOLINT
|
||||||
va_list aq;
|
va_list aq;
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
int res = REAL(vfscanf)(stream, format, ap); // NOLINT
|
int res = REAL(vfscanf)(stream, format, ap); // NOLINT
|
||||||
scanf_common(ctx, format, aq);
|
if (res > 0)
|
||||||
|
scanf_common(ctx, res, format, aq);
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,10 +270,13 @@ static int scanf_get_store_size(ScanfDirective *dir) {
|
||||||
|
|
||||||
// Common part of *scanf interceptors.
|
// Common part of *scanf interceptors.
|
||||||
// Process format string and va_list, and report all store ranges.
|
// Process format string and va_list, and report all store ranges.
|
||||||
static void scanf_common(void *ctx, const char *format, va_list aq) {
|
// Stops when "consuming" n_inputs input items.
|
||||||
|
static void scanf_common(void *ctx, int n_inputs, const char *format,
|
||||||
|
va_list aq) {
|
||||||
|
CHECK_GT(n_inputs, 0);
|
||||||
const char *p = format;
|
const char *p = format;
|
||||||
|
|
||||||
while (p) {
|
while (*p && n_inputs) {
|
||||||
ScanfDirective dir;
|
ScanfDirective dir;
|
||||||
p = scanf_parse_next(p, &dir);
|
p = scanf_parse_next(p, &dir);
|
||||||
if (!p)
|
if (!p)
|
||||||
|
|
@ -293,10 +296,12 @@ static void scanf_common(void *ctx, const char *format, va_list aq) {
|
||||||
int size = scanf_get_store_size(&dir);
|
int size = scanf_get_store_size(&dir);
|
||||||
if (size == SSS_INVALID)
|
if (size == SSS_INVALID)
|
||||||
break;
|
break;
|
||||||
void *p = va_arg(aq, void *);
|
void *argp = va_arg(aq, void *);
|
||||||
|
if (dir.convSpecifier != 'n')
|
||||||
|
--n_inputs;
|
||||||
if (size == SSS_STRLEN) {
|
if (size == SSS_STRLEN) {
|
||||||
size = internal_strlen((const char *)p) + 1;
|
size = internal_strlen((const char *)argp) + 1;
|
||||||
}
|
}
|
||||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, size);
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,32 +24,44 @@ using namespace __sanitizer;
|
||||||
|
|
||||||
#include "sanitizer_common/sanitizer_common_interceptors_scanf.inc"
|
#include "sanitizer_common/sanitizer_common_interceptors_scanf.inc"
|
||||||
|
|
||||||
static void testScanf2(void *ctx, const char *format, ...) {
|
static const char scanf_buf[] = "Test string.";
|
||||||
|
static size_t scanf_buf_size = sizeof(scanf_buf);
|
||||||
|
static const unsigned SCANF_ARGS_MAX = 16;
|
||||||
|
|
||||||
|
static void testScanf3(void *ctx, int result, const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
scanf_common(ctx, format, ap);
|
scanf_common(ctx, result, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char scanf_buf[] = "Test string.";
|
static void testScanf2(const char *format, int scanf_result, unsigned n, va_list expected_sizes) {
|
||||||
static size_t scanf_buf_size = sizeof(scanf_buf);
|
|
||||||
|
|
||||||
static void testScanf(const char *format, unsigned n, ...) {
|
|
||||||
std::vector<unsigned> scanf_sizes;
|
std::vector<unsigned> scanf_sizes;
|
||||||
// 16 args should be enough.
|
// 16 args should be enough.
|
||||||
testScanf2((void *)&scanf_sizes, format,
|
testScanf3((void *)&scanf_sizes, scanf_result, format,
|
||||||
scanf_buf, scanf_buf, scanf_buf, scanf_buf,
|
scanf_buf, scanf_buf, scanf_buf, scanf_buf,
|
||||||
scanf_buf, scanf_buf, scanf_buf, scanf_buf,
|
scanf_buf, scanf_buf, scanf_buf, scanf_buf,
|
||||||
scanf_buf, scanf_buf, scanf_buf, scanf_buf,
|
scanf_buf, scanf_buf, scanf_buf, scanf_buf,
|
||||||
scanf_buf, scanf_buf, scanf_buf, scanf_buf);
|
scanf_buf, scanf_buf, scanf_buf, scanf_buf);
|
||||||
ASSERT_EQ(n, scanf_sizes.size()) <<
|
ASSERT_EQ(n, scanf_sizes.size()) <<
|
||||||
"Unexpected number of format arguments: '" << format << "'";
|
"Unexpected number of format arguments: '" << format << "'";
|
||||||
va_list ap;
|
|
||||||
va_start(ap, n);
|
|
||||||
for (unsigned i = 0; i < n; ++i)
|
for (unsigned i = 0; i < n; ++i)
|
||||||
EXPECT_EQ(va_arg(ap, unsigned), scanf_sizes[i]) <<
|
EXPECT_EQ(va_arg(expected_sizes, unsigned), scanf_sizes[i]) <<
|
||||||
"Unexpect write size for argument " << i << ", format string '" <<
|
"Unexpect write size for argument " << i << ", format string '" <<
|
||||||
format << "'";
|
format << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testScanf(const char *format, unsigned n, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, n);
|
||||||
|
testScanf2(format, SCANF_ARGS_MAX, n, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testScanfPartial(const char *format, int scanf_result, unsigned n, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, n);
|
||||||
|
testScanf2(format, scanf_result, n, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,4 +139,15 @@ TEST(SanitizerCommonInterceptors, Scanf) {
|
||||||
testScanf("%5$d", 0);
|
testScanf("%5$d", 0);
|
||||||
testScanf("%md", 0);
|
testScanf("%md", 0);
|
||||||
testScanf("%m10s", 0);
|
testScanf("%m10s", 0);
|
||||||
|
|
||||||
|
testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
|
||||||
|
testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
|
||||||
|
testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
|
||||||
|
testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
|
||||||
|
|
||||||
|
testScanfPartial("%d%n%n%d //1\n", 1, 1, I);
|
||||||
|
testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
|
||||||
|
|
||||||
|
testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, scanf_buf_size);
|
||||||
|
testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, scanf_buf_size, scanf_buf_size);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue