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