From aa57cabae2fc5abc08ab3e17b45f2890fc7c9e42 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Wed, 5 Aug 2020 12:32:17 -0700 Subject: [PATCH] [msan] Support %ms in scanf. Differential Revision: https://reviews.llvm.org/D85350 --- .../sanitizer_common_interceptors_format.inc | 6 ++++ .../tests/sanitizer_format_interceptor_test.cpp | 41 +++++++++++++++++----- compiler-rt/test/msan/scanf-allocate.cpp | 14 ++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 compiler-rt/test/msan/scanf-allocate.cpp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc index bbbedda..082398b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -340,6 +340,12 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc, size = 0; } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); + // For %ms/%mc, write the allocated output buffer as well. + if (dir.allocate) { + char *buf = *(char **)argp; + if (buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + } } } diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp index 4ed8072..fa52ccc 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp @@ -48,13 +48,13 @@ static const unsigned P = sizeof(char *); static void verifyFormatResults(const char *format, unsigned n, const std::vector &computed_sizes, - va_list expected_sizes) { - // "+ 1" because of format string + const std::vector &expected_sizes) { + // "+ 1" because of the format string ASSERT_EQ(n + 1, computed_sizes.size()) << "Unexpected number of format arguments: '" << format << "'"; for (unsigned i = 0; i < n; ++i) - EXPECT_EQ(va_arg(expected_sizes, unsigned), computed_sizes[i + 1]) + EXPECT_EQ(expected_sizes[i], computed_sizes[i + 1]) << "Unexpect write size for argument " << i << ", format string '" << format << "'"; } @@ -74,8 +74,11 @@ static void testScanf3(void *ctx, int result, bool allowGnuMalloc, static void testScanf2(const char *format, int scanf_result, bool allowGnuMalloc, unsigned n, - va_list expected_sizes) { - std::vector scanf_sizes; + va_list expected_sizes_va) { + std::vector scanf_sizes, expected_sizes; + for (unsigned i = 0; i < n; ++i) + expected_sizes.push_back(va_arg(expected_sizes_va, unsigned)); + // 16 args should be enough. testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format, test_buf, test_buf, test_buf, test_buf, test_buf, test_buf, @@ -151,7 +154,6 @@ TEST(SanitizerCommonInterceptors, Scanf) { testScanf("%c%d", 2, C, I); testScanf("%A%lf", 2, F, D); - testScanf("%ms %Lf", 2, P, LD); testScanf("s%Las", 1, LD); testScanf("%ar", 1, F); @@ -202,6 +204,26 @@ TEST(SanitizerCommonInterceptors, Scanf) { test_buf_size); } +TEST(SanitizerCommonInterceptors, ScanfAllocate) { + const char *buf = "123456"; + + // Can not use testScanf() because this case needs a valid pointer to a string + // in the scanf argument. + { + std::vector scanf_sizes; + testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%ms", &buf); + verifyFormatResults("%ms", 2, scanf_sizes, + {P, (unsigned)(strlen(buf) + 1)}); + } + + { + std::vector scanf_sizes; + testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mc", &buf); + verifyFormatResults("%mc", 2, scanf_sizes, + {P, (unsigned)(strlen(buf) + 1)}); + } +} + static void testPrintf3(void *ctx, const char *format, ...) { va_list ap; va_start(ap, format); @@ -210,8 +232,11 @@ static void testPrintf3(void *ctx, const char *format, ...) { } static void testPrintf2(const char *format, unsigned n, - va_list expected_sizes) { - std::vector printf_sizes; + va_list expected_sizes_va) { + std::vector printf_sizes, expected_sizes; + for (unsigned i = 0; i < n; ++i) + expected_sizes.push_back(va_arg(expected_sizes_va, unsigned)); + // 16 args should be enough. testPrintf3((void *)&printf_sizes, format, test_buf, test_buf, test_buf, test_buf, test_buf, test_buf, diff --git a/compiler-rt/test/msan/scanf-allocate.cpp b/compiler-rt/test/msan/scanf-allocate.cpp new file mode 100644 index 0000000..a525b0c --- /dev/null +++ b/compiler-rt/test/msan/scanf-allocate.cpp @@ -0,0 +1,14 @@ +// RUN: %clangxx_msan -O0 %s -o %t && %run %t >%t.out 2>&1 +// FileCheck %s <%t.out + +#include +#include +#include + +int main(int argc, char **argv) { + char *str; + sscanf("#string#", "%ms", &str); + printf("str = %s\n", str); + __msan_check_mem_is_initialized(str, strlen(str) + 1); + // CHECK: #string# +} -- 2.7.4