xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp (revision beeb37a8f3275281be305d2d1afe35ca053e21c0)
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 
verifyFormatResults(const char * format,unsigned n,const std::vector<unsigned> & computed_sizes,const std::vector<unsigned> & expected_sizes)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 
testScanf3(void * ctx,int result,bool allowGnuMalloc,const char * format,...)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, result, allowGnuMalloc, format, ap);
74   va_end(ap);
75 }
76 
testScanf2(const char * format,int scanf_result,bool allowGnuMalloc,unsigned n,va_list expected_sizes_va)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((void *)&scanf_sizes, 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 
testScanf(const char * format,unsigned n,...)92 static void testScanf(const char *format, unsigned n, ...) {
93   va_list ap;
94   va_start(ap, n);
95   testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
96   va_end(ap);
97 }
98 
testScanfPartial(const char * format,int scanf_result,unsigned n,...)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, ap);
104   va_end(ap);
105 }
106 
testScanfNoGnuMalloc(const char * format,unsigned n,...)107 static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
108   va_list ap;
109   va_start(ap, n);
110   testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
111   va_end(ap);
112 }
113 
TEST(SanitizerCommonInterceptors,Scanf)114 TEST(SanitizerCommonInterceptors, Scanf) {
115   testScanf("%d", 1, I);
116   testScanf("%d%d%d", 3, I, I, I);
117   testScanf("ab%u%dc", 2, I, I);
118   testScanf("%ld", 1, L);
119   testScanf("%llu", 1, LL);
120   testScanf("%qd", 1, LL);
121   testScanf("a %hd%hhx", 2, S, C);
122   testScanf("%c", 1, C);
123   testScanf("%lc", 1, LC);
124 
125   testScanf("%%", 0);
126   testScanf("a%%", 0);
127   testScanf("a%%b", 0);
128   testScanf("a%%%%b", 0);
129   testScanf("a%%b%%", 0);
130   testScanf("a%%%%%%b", 0);
131   testScanf("a%%%%%b", 0);
132   testScanf("a%%%%%f", 1, F);
133   testScanf("a%%%lxb", 1, L);
134   testScanf("a%lf%%%lxb", 2, D, L);
135   testScanf("%nf", 1, I);
136 
137   testScanf("%10s", 1, 11);
138   testScanf("%10c", 1, 10);
139   testScanf("%10ls", 1, 11 * LC);
140   testScanf("%10lc", 1, 10 * LC);
141   testScanf("%%10s", 0);
142   testScanf("%*10s", 0);
143   testScanf("%*d", 0);
144 
145   testScanf("%4d%8f%c", 3, I, F, C);
146   testScanf("%s%d", 2, test_buf_size, I);
147   testScanf("%[abc]", 1, test_buf_size);
148   testScanf("%4[bcdef]", 1, 5);
149   testScanf("%[]]", 1, test_buf_size);
150   testScanf("%8[^]%d0-9-]%c", 2, 9, C);
151 
152   testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
153 
154   testScanf("%*d%u", 1, I);
155 
156   testScanf("%c%d", 2, C, I);
157   testScanf("%A%lf", 2, F, D);
158 
159   testScanf("s%Las", 1, LD);
160   testScanf("%ar", 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("%a[", 0);
167   testScanf("%a[]", 0);
168   testScanf("%a[]]", 1, std::min(F, P));
169   testScanf("%a[abc]", 1, std::min(F, P));
170   testScanf("%a[^abc]", 1, std::min(F, P));
171   testScanf("%a[ab%c] %d", 0);
172   testScanf("%a[^ab%c] %d", 0);
173   testScanf("%as", 1, std::min(F, P));
174   testScanf("%aS", 1, std::min(F, P));
175   testScanf("%a13S", 1, std::min(F, P));
176   testScanf("%alS", 1, std::min(F, P));
177 
178   testScanfNoGnuMalloc("s%Las", 1, LD);
179   testScanfNoGnuMalloc("%ar", 1, F);
180   testScanfNoGnuMalloc("%a[", 1, F);
181   testScanfNoGnuMalloc("%a[]", 1, F);
182   testScanfNoGnuMalloc("%a[]]", 1, F);
183   testScanfNoGnuMalloc("%a[abc]", 1, F);
184   testScanfNoGnuMalloc("%a[^abc]", 1, F);
185   testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
186   testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
187   testScanfNoGnuMalloc("%as", 1, F);
188   testScanfNoGnuMalloc("%aS", 1, F);
189   testScanfNoGnuMalloc("%a13S", 1, F);
190   testScanfNoGnuMalloc("%alS", 1, F);
191 
192   testScanf("%5$d", 0);
193   testScanf("%md", 0);
194   testScanf("%m10s", 0);
195 
196   testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
197   testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
198   testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
199   testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
200 
201   testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
202   testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
203 
204   testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, test_buf_size);
205   testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
206                    test_buf_size);
207 }
208 
TEST(SanitizerCommonInterceptors,ScanfAllocate)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((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mc", &buf);
218     verifyFormatResults("%mc", 2, scanf_sizes, {P, 1u});
219   }
220   {
221     std::vector<unsigned> scanf_sizes;
222     testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mC", &wbuf);
223     verifyFormatResults("%mC", 2, scanf_sizes, {P, (unsigned)sizeof(wchar_t)});
224   }
225   {
226     std::vector<unsigned> scanf_sizes;
227     testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%ms", &buf);
228     verifyFormatResults("%ms", 2, scanf_sizes, {P, unsigned(strlen(buf) + 1)});
229     scanf_sizes.clear();
230     testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%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((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mS", &wbuf);
238     verifyFormatResults("%mS", 2, scanf_sizes,
239                         {P, unsigned((wcslen(wbuf) + 1) * sizeof(wchar_t))});
240   }
241 }
242 
testPrintf3(void * ctx,const char * format,...)243 static void testPrintf3(void *ctx, const char *format, ...) {
244   va_list ap;
245   va_start(ap, format);
246   printf_common(ctx, format, ap);
247   va_end(ap);
248 }
249 
testPrintf2(const char * format,unsigned n,va_list expected_sizes_va)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((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 
testPrintf(const char * format,unsigned n,...)264 static void testPrintf(const char *format, unsigned n, ...) {
265   va_list ap;
266   va_start(ap, n);
267   testPrintf2(format, n, ap);
268   va_end(ap);
269 }
270 
TEST(SanitizerCommonInterceptors,Printf)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