1//===-- sanitizer_scanf_interceptor_test.cc -------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Tests for *scanf interceptors implementation in sanitizer_common.
11//
12//===----------------------------------------------------------------------===//
13#include <vector>
14
15#include "interception/interception.h"
16#include "sanitizer_test_utils.h"
17#include "sanitizer_common/sanitizer_libc.h"
18#include "gtest/gtest.h"
19
20using namespace __sanitizer;
21
22#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)                         \
23  ((std::vector<unsigned> *)ctx)->push_back(size)
24
25#include "sanitizer_common/sanitizer_common_interceptors_scanf.inc"
26
27static const char scanf_buf[] = "Test string.";
28static size_t scanf_buf_size = sizeof(scanf_buf);
29static const unsigned SCANF_ARGS_MAX = 16;
30
31static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
32                       const char *format, ...) {
33  va_list ap;
34  va_start(ap, format);
35  scanf_common(ctx, result, allowGnuMalloc, format, ap);
36  va_end(ap);
37}
38
39static void testScanf2(const char *format, int scanf_result,
40                       bool allowGnuMalloc, unsigned n,
41                       va_list expected_sizes) {
42  std::vector<unsigned> scanf_sizes;
43  // 16 args should be enough.
44  testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
45             scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
46             scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
47             scanf_buf, scanf_buf, scanf_buf, scanf_buf);
48  ASSERT_EQ(n, scanf_sizes.size()) << "Unexpected number of format arguments: '"
49                                   << format << "'";
50  for (unsigned i = 0; i < n; ++i)
51    EXPECT_EQ(va_arg(expected_sizes, unsigned), scanf_sizes[i])
52        << "Unexpect write size for argument " << i << ", format string '"
53        << format << "'";
54}
55
56static void testScanf(const char *format, unsigned n, ...) {
57  va_list ap;
58  va_start(ap, n);
59  testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
60  va_end(ap);
61}
62
63static void testScanfPartial(const char *format, int scanf_result, unsigned n,
64                             ...) {
65  va_list ap;
66  va_start(ap, n);
67  testScanf2(format, scanf_result, /* allowGnuMalloc */ true,  n, ap);
68  va_end(ap);
69}
70
71static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
72  va_list ap;
73  va_start(ap, n);
74  testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
75  va_end(ap);
76}
77
78TEST(SanitizerCommonInterceptors, Scanf) {
79  const unsigned I = sizeof(int);          // NOLINT
80  const unsigned L = sizeof(long);         // NOLINT
81  const unsigned LL = sizeof(long long);   // NOLINT
82  const unsigned S = sizeof(short);        // NOLINT
83  const unsigned C = sizeof(char);         // NOLINT
84  const unsigned D = sizeof(double);       // NOLINT
85  const unsigned LD = sizeof(long double); // NOLINT
86  const unsigned F = sizeof(float);        // NOLINT
87  const unsigned P = sizeof(char *);       // NOLINT
88
89  testScanf("%d", 1, I);
90  testScanf("%d%d%d", 3, I, I, I);
91  testScanf("ab%u%dc", 2, I, I);
92  testScanf("%ld", 1, L);
93  testScanf("%llu", 1, LL);
94  testScanf("a %hd%hhx", 2, S, C);
95  testScanf("%c", 1, C);
96
97  testScanf("%%", 0);
98  testScanf("a%%", 0);
99  testScanf("a%%b", 0);
100  testScanf("a%%%%b", 0);
101  testScanf("a%%b%%", 0);
102  testScanf("a%%%%%%b", 0);
103  testScanf("a%%%%%b", 0);
104  testScanf("a%%%%%f", 1, F);
105  testScanf("a%%%lxb", 1, L);
106  testScanf("a%lf%%%lxb", 2, D, L);
107  testScanf("%nf", 1, I);
108
109  testScanf("%10s", 1, 11);
110  testScanf("%10c", 1, 10);
111  testScanf("%%10s", 0);
112  testScanf("%*10s", 0);
113  testScanf("%*d", 0);
114
115  testScanf("%4d%8f%c", 3, I, F, C);
116  testScanf("%s%d", 2, scanf_buf_size, I);
117  testScanf("%[abc]", 1, scanf_buf_size);
118  testScanf("%4[bcdef]", 1, 5);
119  testScanf("%[]]", 1, scanf_buf_size);
120  testScanf("%8[^]%d0-9-]%c", 2, 9, C);
121
122  testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
123
124  testScanf("%*d%u", 1, I);
125
126  testScanf("%c%d", 2, C, I);
127  testScanf("%A%lf", 2, F, D);
128
129  testScanf("%ms %Lf", 2, P, LD);
130  testScanf("s%Las", 1, LD);
131  testScanf("%ar", 1, F);
132
133  // In the cases with std::min below the format spec can be interpreted as
134  // either floating-something, or (GNU extension) callee-allocated string.
135  // Our conservative implementation reports one of the two possibilities with
136  // the least store range.
137  testScanf("%a[", 0);
138  testScanf("%a[]", 0);
139  testScanf("%a[]]", 1, std::min(F, P));
140  testScanf("%a[abc]", 1, std::min(F, P));
141  testScanf("%a[^abc]", 1, std::min(F, P));
142  testScanf("%a[ab%c] %d", 0);
143  testScanf("%a[^ab%c] %d", 0);
144  testScanf("%as", 1, std::min(F, P));
145  testScanf("%aS", 1, std::min(F, P));
146  testScanf("%a13S", 1, std::min(F, P));
147  testScanf("%alS", 1, std::min(F, P));
148
149  testScanfNoGnuMalloc("s%Las", 1, LD);
150  testScanfNoGnuMalloc("%ar", 1, F);
151  testScanfNoGnuMalloc("%a[", 1, F);
152  testScanfNoGnuMalloc("%a[]", 1, F);
153  testScanfNoGnuMalloc("%a[]]", 1, F);
154  testScanfNoGnuMalloc("%a[abc]", 1, F);
155  testScanfNoGnuMalloc("%a[^abc]", 1, F);
156  testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
157  testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
158  testScanfNoGnuMalloc("%as", 1, F);
159  testScanfNoGnuMalloc("%aS", 1, F);
160  testScanfNoGnuMalloc("%a13S", 1, F);
161  testScanfNoGnuMalloc("%alS", 1, F);
162
163  testScanf("%5$d", 0);
164  testScanf("%md", 0);
165  testScanf("%m10s", 0);
166
167  testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
168  testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
169  testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
170  testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
171
172  testScanfPartial("%d%n%n%d //1\n", 1, 1, I);
173  testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
174
175  testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, scanf_buf_size);
176  testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, scanf_buf_size,
177                   scanf_buf_size);
178}
179