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 | |
23 | using 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 | |
40 | static const unsigned I = sizeof(int); |
41 | static const unsigned Z = sizeof(size_t); |
42 | static const unsigned L = sizeof(long); |
43 | static const unsigned LL = sizeof(long long); |
44 | static const unsigned S = sizeof(short); |
45 | static const unsigned C = sizeof(char); |
46 | static const unsigned LC = sizeof(wchar_t); |
47 | static const unsigned D = sizeof(double); |
48 | static const unsigned LD = sizeof(long double); |
49 | static const unsigned F = sizeof(float); |
50 | static const unsigned P = sizeof(char *); |
51 | |
52 | static 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 | |
65 | static const char test_buf[] = "Test string." ; |
66 | static const size_t test_buf_size = sizeof(test_buf); |
67 | |
68 | static const unsigned SCANF_ARGS_MAX = 16; |
69 | |
70 | static 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 | |
78 | static 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 | |
93 | static 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 | |
100 | static 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 | |
108 | static 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 | |
115 | TEST(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 | |
219 | TEST(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 | |
253 | static 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 | |
260 | static 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 | |
274 | static 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 | |
281 | TEST(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 | |