1//===-- sanitizer_format_interceptor_test.cpp -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Tests for *scanf interceptors implementation in sanitizer_common.
10//
11//===----------------------------------------------------------------------===//
12#include <wchar.h>
13
14#include <algorithm>
15#include <vector>
16
17#include "gtest/gtest.h"
18#include "interception/interception.h"
19#include "sanitizer_common/sanitizer_common.h"
20#include "sanitizer_common/sanitizer_libc.h"
21#include "sanitizer_test_utils.h"
22
23using namespace __sanitizer;
24
25#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size) \
26 do { \
27 ((std::vector<unsigned> *)ctx)->push_back(size); \
28 ptr = ptr; \
29 } while (0)
30
31#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
32 COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
33
34#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
35 COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
36
37#define SANITIZER_INTERCEPT_PRINTF 1
38#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
39
40static const unsigned I = sizeof(int);
41static const unsigned Z = sizeof(size_t);
42static const unsigned L = sizeof(long);
43static const unsigned LL = sizeof(long long);
44static const unsigned S = sizeof(short);
45static const unsigned C = sizeof(char);
46static const unsigned LC = sizeof(wchar_t);
47static const unsigned D = sizeof(double);
48static const unsigned LD = sizeof(long double);
49static const unsigned F = sizeof(float);
50static const unsigned P = sizeof(char *);
51
52static void verifyFormatResults(const char *format, unsigned n,
53 const std::vector<unsigned> &computed_sizes,
54 const std::vector<unsigned> &expected_sizes) {
55 // "+ 1" because of the format string
56 ASSERT_EQ(n + 1,
57 computed_sizes.size()) << "Unexpected number of format arguments: '"
58 << format << "'";
59 for (unsigned i = 0; i < n; ++i)
60 EXPECT_EQ(expected_sizes[i], computed_sizes[i + 1])
61 << "Unexpect write size for argument " << i << ", format string '"
62 << format << "'";
63}
64
65static const char test_buf[] = "Test string.";
66static const size_t test_buf_size = sizeof(test_buf);
67
68static const unsigned SCANF_ARGS_MAX = 16;
69
70static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
71 const char *format, ...) {
72 va_list ap;
73 va_start(ap, format);
74 scanf_common(ctx, n_inputs: result, allowGnuMalloc, format, aq: ap);
75 va_end(ap);
76}
77
78static void testScanf2(const char *format, int scanf_result,
79 bool allowGnuMalloc, unsigned n,
80 va_list expected_sizes_va) {
81 std::vector<unsigned> scanf_sizes, expected_sizes;
82 for (unsigned i = 0; i < n; ++i)
83 expected_sizes.push_back(va_arg(expected_sizes_va, unsigned));
84
85 // 16 args should be enough.
86 testScanf3(ctx: (void *)&scanf_sizes, result: scanf_result, allowGnuMalloc, format,
87 test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
88 test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
89 test_buf, test_buf, test_buf, test_buf);
90 verifyFormatResults(format, n, scanf_sizes, expected_sizes);
91}
92
93static void testScanf(const char *format, unsigned n, ...) {
94 va_list ap;
95 va_start(ap, n);
96 testScanf2(format, scanf_result: SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, expected_sizes_va: ap);
97 va_end(ap);
98}
99
100static void testScanfPartial(const char *format, int scanf_result, unsigned n,
101 ...) {
102 va_list ap;
103 va_start(ap, n);
104 testScanf2(format, scanf_result, /* allowGnuMalloc */ true, n, expected_sizes_va: ap);
105 va_end(ap);
106}
107
108static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
109 va_list ap;
110 va_start(ap, n);
111 testScanf2(format, scanf_result: SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, expected_sizes_va: ap);
112 va_end(ap);
113}
114
115TEST(SanitizerCommonInterceptors, Scanf) {
116 testScanf(format: "%d", n: 1, I);
117 testScanf(format: "%zx", n: 1, Z);
118 testScanf(format: "%zd", n: 1, Z);
119 testScanf(format: "%d%d%d", n: 3, I, I, I);
120 testScanf(format: "ab%u%dc", n: 2, I, I);
121 testScanf(format: "%ld", n: 1, L);
122 testScanf(format: "%llu", n: 1, LL);
123 testScanf(format: "%qd", n: 1, LL);
124 testScanf(format: "a %hd%hhx", n: 2, S, C);
125 testScanf(format: "%c", n: 1, C);
126 testScanf(format: "%lc", n: 1, LC);
127
128 testScanf(format: "%%", n: 0);
129 testScanf(format: "a%%", n: 0);
130 testScanf(format: "a%%b", n: 0);
131 testScanf(format: "a%%%%b", n: 0);
132 testScanf(format: "a%%b%%", n: 0);
133 testScanf(format: "a%%%%%%b", n: 0);
134 testScanf(format: "a%%%%%f", n: 1, F);
135 testScanf(format: "a%%%lxb", n: 1, L);
136 testScanf(format: "a%lf%%%lxb", n: 2, D, L);
137 testScanf(format: "%nf", n: 1, I);
138
139 testScanf(format: "%10s", n: 1, 11);
140 testScanf(format: "%10c", n: 1, 10);
141 testScanf(format: "%10ls", n: 1, 11 * LC);
142 testScanf(format: "%10lc", n: 1, 10 * LC);
143 testScanf(format: "%%10s", n: 0);
144 testScanf(format: "%*10s", n: 0);
145 testScanf(format: "%*d", n: 0);
146
147 testScanf(format: "%4d%8f%c", n: 3, I, F, C);
148 testScanf(format: "%s%d", n: 2, test_buf_size, I);
149 testScanf(format: "%[abc]", n: 1, test_buf_size);
150 testScanf(format: "%4[bcdef]", n: 1, 5);
151 testScanf(format: "%[]]", n: 1, test_buf_size);
152 testScanf(format: "%8[^]%d0-9-]%c", n: 2, 9, C);
153
154 testScanf(format: "%*[^:]%n:%d:%1[ ]%n", n: 4, I, I, 2, I);
155
156 testScanf(format: "%*d%u", n: 1, I);
157
158 testScanf(format: "%c%d", n: 2, C, I);
159 testScanf(format: "%A%lf", n: 2, F, D);
160
161 testScanf(format: "s%Las", n: 1, LD);
162 testScanf(format: "%ar", n: 1, F);
163
164 // In the cases with std::min below the format spec can be interpreted as
165 // either floating-something, or (GNU extension) callee-allocated string.
166 // Our conservative implementation reports one of the two possibilities with
167 // the least store range.
168 testScanf(format: "%a[", n: 0);
169 testScanf(format: "%a[]", n: 0);
170 testScanf(format: "%a[]]", n: 1, std::min(a: F, b: P));
171 testScanf(format: "%a[abc]", n: 1, std::min(a: F, b: P));
172 testScanf(format: "%a[^abc]", n: 1, std::min(a: F, b: P));
173 testScanf(format: "%a[ab%c] %d", n: 0);
174 testScanf(format: "%a[^ab%c] %d", n: 0);
175 testScanf(format: "%as", n: 1, std::min(a: F, b: P));
176 testScanf(format: "%aS", n: 1, std::min(a: F, b: P));
177 testScanf(format: "%a13S", n: 1, std::min(a: F, b: P));
178 testScanf(format: "%alS", n: 1, std::min(a: F, b: P));
179
180 testScanfNoGnuMalloc(format: "s%Las", n: 1, LD);
181 testScanfNoGnuMalloc(format: "%ar", n: 1, F);
182 testScanfNoGnuMalloc(format: "%a[", n: 1, F);
183 testScanfNoGnuMalloc(format: "%a[]", n: 1, F);
184 testScanfNoGnuMalloc(format: "%a[]]", n: 1, F);
185 testScanfNoGnuMalloc(format: "%a[abc]", n: 1, F);
186 testScanfNoGnuMalloc(format: "%a[^abc]", n: 1, F);
187 testScanfNoGnuMalloc(format: "%a[ab%c] %d", n: 3, F, C, I);
188 testScanfNoGnuMalloc(format: "%a[^ab%c] %d", n: 3, F, C, I);
189 testScanfNoGnuMalloc(format: "%as", n: 1, F);
190 testScanfNoGnuMalloc(format: "%aS", n: 1, F);
191 testScanfNoGnuMalloc(format: "%a13S", n: 1, F);
192 testScanfNoGnuMalloc(format: "%alS", n: 1, F);
193
194 testScanf(format: "%5$d", n: 0);
195 testScanf(format: "%md", n: 0);
196 testScanf(format: "%m10s", n: 0);
197
198 testScanfPartial(format: "%d%d%d%d //1\n", scanf_result: 1, n: 1, I);
199 testScanfPartial(format: "%d%d%d%d //2\n", scanf_result: 2, n: 2, I, I);
200 testScanfPartial(format: "%d%d%d%d //3\n", scanf_result: 3, n: 3, I, I, I);
201 testScanfPartial(format: "%d%d%d%d //4\n", scanf_result: 4, n: 4, I, I, I, I);
202
203 testScanfPartial(format: "%d%n%n%d //1\n", scanf_result: 1, n: 3, I, I, I);
204 testScanfPartial(format: "%d%n%n%d //2\n", scanf_result: 2, n: 4, I, I, I, I);
205
206 testScanfPartial(format: "%d%n%n%d %s %s", scanf_result: 3, n: 5, I, I, I, I, test_buf_size);
207 testScanfPartial(format: "%d%n%n%d %s %s", scanf_result: 4, n: 6, I, I, I, I, test_buf_size,
208 test_buf_size);
209
210#if defined(__GLIBC__)
211 testScanf(format: "%b", n: 1, I);
212 testScanf(format: "%zb", n: 1, Z);
213 testScanf(format: "a%%%%%b", n: 1, I);
214#else
215 testScanf("a%%%%%b", 0);
216#endif
217}
218
219TEST(SanitizerCommonInterceptors, ScanfAllocate) {
220 const char *buf = "123456";
221 const wchar_t *wbuf = L"123";
222
223 // Can not use testScanf() because this case needs a valid pointer to a string
224 // in the scanf argument.
225 {
226 std::vector<unsigned> scanf_sizes;
227 testScanf3(ctx: (void *)&scanf_sizes, result: 2, /*allowGnuMalloc=*/false, format: "%mc", &buf);
228 verifyFormatResults("%mc", 2, scanf_sizes, {P, 1u});
229 }
230 {
231 std::vector<unsigned> scanf_sizes;
232 testScanf3(ctx: (void *)&scanf_sizes, result: 2, /*allowGnuMalloc=*/false, format: "%mC", &wbuf);
233 verifyFormatResults("%mC", 2, scanf_sizes, {P, (unsigned)sizeof(wchar_t)});
234 }
235 {
236 std::vector<unsigned> scanf_sizes;
237 testScanf3(ctx: (void *)&scanf_sizes, result: 2, /*allowGnuMalloc=*/false, format: "%ms", &buf);
238 verifyFormatResults("%ms", 2, scanf_sizes, {P, unsigned(strlen(buf) + 1)});
239 scanf_sizes.clear();
240 testScanf3(ctx: (void *)&scanf_sizes, result: 2, /*allowGnuMalloc=*/false, format: "%m[0-9]",
241 &buf);
242 verifyFormatResults("%m[0-9]", 2, scanf_sizes,
243 {P, unsigned(strlen(buf) + 1)});
244 }
245 {
246 std::vector<unsigned> scanf_sizes;
247 testScanf3(ctx: (void *)&scanf_sizes, result: 2, /*allowGnuMalloc=*/false, format: "%mS", &wbuf);
248 verifyFormatResults("%mS", 2, scanf_sizes,
249 {P, unsigned((wcslen(s: wbuf) + 1) * sizeof(wchar_t))});
250 }
251}
252
253static void testPrintf3(void *ctx, const char *format, ...) {
254 va_list ap;
255 va_start(ap, format);
256 printf_common(ctx, format, aq: ap);
257 va_end(ap);
258}
259
260static void testPrintf2(const char *format, unsigned n,
261 va_list expected_sizes_va) {
262 std::vector<unsigned> printf_sizes, expected_sizes;
263 for (unsigned i = 0; i < n; ++i)
264 expected_sizes.push_back(va_arg(expected_sizes_va, unsigned));
265
266 // 16 args should be enough.
267 testPrintf3(ctx: (void *)&printf_sizes, format,
268 test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
269 test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
270 test_buf, test_buf, test_buf, test_buf);
271 verifyFormatResults(format, n, printf_sizes, expected_sizes);
272}
273
274static void testPrintf(const char *format, unsigned n, ...) {
275 va_list ap;
276 va_start(ap, n);
277 testPrintf2(format, n, expected_sizes_va: ap);
278 va_end(ap);
279}
280
281TEST(SanitizerCommonInterceptors, Printf) {
282 // Only test functionality which differs from scanf
283
284 // Indexed arguments
285 testPrintf("%5$d", 0);
286 testPrintf("%.*5$d", 0);
287
288 // errno
289 testPrintf("%0-m", 0);
290
291 // Dynamic width
292 testPrintf("%*n", 1, I);
293 testPrintf("%*.10n", 1, I);
294
295 // Precision
296 testPrintf("%10.10n", 1, I);
297 testPrintf("%.3s", 1, 3);
298 testPrintf("%.20s", 1, test_buf_size);
299
300 // Dynamic precision
301 testPrintf("%.*n", 1, I);
302 testPrintf("%10.*n", 1, I);
303
304 // Dynamic precision for strings is not implemented yet.
305 testPrintf("%.*s", 1, 0);
306
307 // Checks for wide-character strings are not implemented yet.
308 testPrintf("%ls", 1, 0);
309
310 testPrintf("%m", 0);
311 testPrintf("%m%s", 1, test_buf_size);
312 testPrintf("%s%m%s", 2, test_buf_size, test_buf_size);
313}
314

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp