aboutsummaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc')
-rw-r--r--lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc259
1 files changed, 259 insertions, 0 deletions
diff --git a/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
new file mode 100644
index 000000000000..13918aff1009
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
@@ -0,0 +1,259 @@
+//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for *scanf interceptors implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size) \
+ do { \
+ ((std::vector<unsigned> *)ctx)->push_back(size); \
+ ptr = ptr; \
+ } while (0)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define SANITIZER_INTERCEPT_PRINTF 1
+#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
+
+static const unsigned I = sizeof(int);
+static const unsigned L = sizeof(long);
+static const unsigned LL = sizeof(long long);
+static const unsigned S = sizeof(short);
+static const unsigned C = sizeof(char);
+static const unsigned LC = sizeof(wchar_t);
+static const unsigned D = sizeof(double);
+static const unsigned LD = sizeof(long double);
+static const unsigned F = sizeof(float);
+static const unsigned P = sizeof(char *);
+
+static void verifyFormatResults(const char *format, unsigned n,
+ const std::vector<unsigned> &computed_sizes,
+ va_list expected_sizes) {
+ // "+ 1" because of 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])
+ << "Unexpect write size for argument " << i << ", format string '"
+ << format << "'";
+}
+
+static const char test_buf[] = "Test string.";
+static const size_t test_buf_size = sizeof(test_buf);
+
+static const unsigned SCANF_ARGS_MAX = 16;
+
+static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
+ const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ scanf_common(ctx, result, allowGnuMalloc, format, ap);
+ va_end(ap);
+}
+
+static void testScanf2(const char *format, int scanf_result,
+ bool allowGnuMalloc, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> scanf_sizes;
+ // 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,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, scanf_sizes, expected_sizes);
+}
+
+static void testScanf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, 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, /* allowGnuMalloc */ true, n, ap);
+ va_end(ap);
+}
+
+static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Scanf) {
+ testScanf("%d", 1, I);
+ testScanf("%d%d%d", 3, I, I, I);
+ testScanf("ab%u%dc", 2, I, I);
+ testScanf("%ld", 1, L);
+ testScanf("%llu", 1, LL);
+ testScanf("%qd", 1, LL);
+ testScanf("a %hd%hhx", 2, S, C);
+ testScanf("%c", 1, C);
+ testScanf("%lc", 1, LC);
+
+ testScanf("%%", 0);
+ testScanf("a%%", 0);
+ testScanf("a%%b", 0);
+ testScanf("a%%%%b", 0);
+ testScanf("a%%b%%", 0);
+ testScanf("a%%%%%%b", 0);
+ testScanf("a%%%%%b", 0);
+ testScanf("a%%%%%f", 1, F);
+ testScanf("a%%%lxb", 1, L);
+ testScanf("a%lf%%%lxb", 2, D, L);
+ testScanf("%nf", 1, I);
+
+ testScanf("%10s", 1, 11);
+ testScanf("%10c", 1, 10);
+ testScanf("%10ls", 1, 11 * LC);
+ testScanf("%10lc", 1, 10 * LC);
+ testScanf("%%10s", 0);
+ testScanf("%*10s", 0);
+ testScanf("%*d", 0);
+
+ testScanf("%4d%8f%c", 3, I, F, C);
+ testScanf("%s%d", 2, test_buf_size, I);
+ testScanf("%[abc]", 1, test_buf_size);
+ testScanf("%4[bcdef]", 1, 5);
+ testScanf("%[]]", 1, test_buf_size);
+ testScanf("%8[^]%d0-9-]%c", 2, 9, C);
+
+ testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
+
+ testScanf("%*d%u", 1, I);
+
+ 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);
+
+ // In the cases with std::min below the format spec can be interpreted as
+ // either floating-something, or (GNU extension) callee-allocated string.
+ // Our conservative implementation reports one of the two possibilities with
+ // the least store range.
+ testScanf("%a[", 0);
+ testScanf("%a[]", 0);
+ testScanf("%a[]]", 1, std::min(F, P));
+ testScanf("%a[abc]", 1, std::min(F, P));
+ testScanf("%a[^abc]", 1, std::min(F, P));
+ testScanf("%a[ab%c] %d", 0);
+ testScanf("%a[^ab%c] %d", 0);
+ testScanf("%as", 1, std::min(F, P));
+ testScanf("%aS", 1, std::min(F, P));
+ testScanf("%a13S", 1, std::min(F, P));
+ testScanf("%alS", 1, std::min(F, P));
+
+ testScanfNoGnuMalloc("s%Las", 1, LD);
+ testScanfNoGnuMalloc("%ar", 1, F);
+ testScanfNoGnuMalloc("%a[", 1, F);
+ testScanfNoGnuMalloc("%a[]", 1, F);
+ testScanfNoGnuMalloc("%a[]]", 1, F);
+ testScanfNoGnuMalloc("%a[abc]", 1, F);
+ testScanfNoGnuMalloc("%a[^abc]", 1, F);
+ testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
+ testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
+ testScanfNoGnuMalloc("%as", 1, F);
+ testScanfNoGnuMalloc("%aS", 1, F);
+ testScanfNoGnuMalloc("%a13S", 1, F);
+ testScanfNoGnuMalloc("%alS", 1, F);
+
+ testScanf("%5$d", 0);
+ testScanf("%md", 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, 3, I, I, 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, test_buf_size);
+ testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
+ test_buf_size);
+}
+
+static void testPrintf3(void *ctx, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ printf_common(ctx, format, ap);
+ va_end(ap);
+}
+
+static void testPrintf2(const char *format, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> printf_sizes;
+ // 16 args should be enough.
+ testPrintf3((void *)&printf_sizes, format,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, printf_sizes, expected_sizes);
+}
+
+static void testPrintf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testPrintf2(format, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Printf) {
+ // Only test functionality which differs from scanf
+
+ // Indexed arguments
+ testPrintf("%5$d", 0);
+ testPrintf("%.*5$d", 0);
+
+ // errno
+ testPrintf("%0-m", 0);
+
+ // Dynamic width
+ testPrintf("%*n", 1, I);
+ testPrintf("%*.10n", 1, I);
+
+ // Precision
+ testPrintf("%10.10n", 1, I);
+ testPrintf("%.3s", 1, 3);
+ testPrintf("%.20s", 1, test_buf_size);
+
+ // Dynamic precision
+ testPrintf("%.*n", 1, I);
+ testPrintf("%10.*n", 1, I);
+
+ // Dynamic precision for strings is not implemented yet.
+ testPrintf("%.*s", 1, 0);
+
+ // Checks for wide-character strings are not implemented yet.
+ testPrintf("%ls", 1, 0);
+}