]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //=-- asan_str_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 | // This file is a part of AddressSanitizer, an address sanity checker. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | #include "asan_test_utils.h" | |
14 | ||
15 | #if defined(__APPLE__) | |
16 | #include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_* | |
17 | #endif | |
18 | ||
19 | // Used for string functions tests | |
20 | static char global_string[] = "global"; | |
21 | static size_t global_string_length = 6; | |
22 | ||
5bcae85e SL |
23 | const char kStackReadUnderflow[] = |
24 | #if !GTEST_USES_SIMPLE_RE | |
25 | ASAN_PCRE_DOTALL | |
26 | "READ.*" | |
27 | #endif | |
28 | "underflows this variable"; | |
29 | const char kStackReadOverflow[] = | |
30 | #if !GTEST_USES_SIMPLE_RE | |
31 | ASAN_PCRE_DOTALL | |
32 | "READ.*" | |
33 | #endif | |
34 | "overflows this variable"; | |
35 | ||
36 | namespace { | |
37 | enum class OOBKind { | |
38 | Heap, | |
39 | Stack, | |
40 | Global, | |
41 | }; | |
42 | ||
43 | string LeftOOBReadMessage(OOBKind oob_kind, int oob_distance) { | |
44 | return oob_kind == OOBKind::Stack ? kStackReadUnderflow | |
45 | : ::LeftOOBReadMessage(oob_distance); | |
46 | } | |
47 | ||
48 | string RightOOBReadMessage(OOBKind oob_kind, int oob_distance) { | |
49 | return oob_kind == OOBKind::Stack ? kStackReadOverflow | |
50 | : ::RightOOBReadMessage(oob_distance); | |
51 | } | |
52 | } // namespace | |
53 | ||
1a4d82fc JJ |
54 | // Input to a test is a zero-terminated string str with given length |
55 | // Accesses to the bytes to the left and to the right of str | |
56 | // are presumed to produce OOB errors | |
5bcae85e | 57 | void StrLenOOBTestTemplate(char *str, size_t length, OOBKind oob_kind) { |
1a4d82fc JJ |
58 | // Normal strlen calls |
59 | EXPECT_EQ(strlen(str), length); | |
60 | if (length > 0) { | |
61 | EXPECT_EQ(length - 1, strlen(str + 1)); | |
62 | EXPECT_EQ(0U, strlen(str + length)); | |
63 | } | |
64 | // Arg of strlen is not malloced, OOB access | |
5bcae85e | 65 | if (oob_kind != OOBKind::Global) { |
1a4d82fc | 66 | // We don't insert RedZones to the left of global variables |
5bcae85e SL |
67 | EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(oob_kind, 1)); |
68 | EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(oob_kind, 5)); | |
1a4d82fc | 69 | } |
5bcae85e SL |
70 | EXPECT_DEATH(Ident(strlen(str + length + 1)), |
71 | RightOOBReadMessage(oob_kind, 0)); | |
1a4d82fc JJ |
72 | // Overwrite terminator |
73 | str[length] = 'a'; | |
74 | // String is not zero-terminated, strlen will lead to OOB access | |
5bcae85e SL |
75 | EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(oob_kind, 0)); |
76 | EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(oob_kind, 0)); | |
1a4d82fc JJ |
77 | // Restore terminator |
78 | str[length] = 0; | |
79 | } | |
80 | TEST(AddressSanitizer, StrLenOOBTest) { | |
81 | // Check heap-allocated string | |
82 | size_t length = Ident(10); | |
83 | char *heap_string = Ident((char*)malloc(length + 1)); | |
84 | char stack_string[10 + 1]; | |
85 | break_optimization(&stack_string); | |
86 | for (size_t i = 0; i < length; i++) { | |
87 | heap_string[i] = 'a'; | |
88 | stack_string[i] = 'b'; | |
89 | } | |
90 | heap_string[length] = 0; | |
91 | stack_string[length] = 0; | |
5bcae85e SL |
92 | StrLenOOBTestTemplate(heap_string, length, OOBKind::Heap); |
93 | StrLenOOBTestTemplate(stack_string, length, OOBKind::Stack); | |
94 | StrLenOOBTestTemplate(global_string, global_string_length, OOBKind::Global); | |
1a4d82fc JJ |
95 | free(heap_string); |
96 | } | |
97 | ||
2c00a5a8 XL |
98 | // 32-bit android libc++-based NDK toolchain links wcslen statically, disabling |
99 | // the interceptor. | |
100 | #if !defined(__ANDROID__) || defined(__LP64__) | |
1a4d82fc JJ |
101 | TEST(AddressSanitizer, WcsLenTest) { |
102 | EXPECT_EQ(0U, wcslen(Ident(L""))); | |
103 | size_t hello_len = 13; | |
104 | size_t hello_size = (hello_len + 1) * sizeof(wchar_t); | |
105 | EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!"))); | |
106 | wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size)); | |
107 | memcpy(heap_string, L"Hello, World!", hello_size); | |
108 | EXPECT_EQ(hello_len, Ident(wcslen(heap_string))); | |
109 | EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0)); | |
110 | free(heap_string); | |
111 | } | |
2c00a5a8 | 112 | #endif |
1a4d82fc JJ |
113 | |
114 | #if SANITIZER_TEST_HAS_STRNLEN | |
115 | TEST(AddressSanitizer, StrNLenOOBTest) { | |
116 | size_t size = Ident(123); | |
117 | char *str = MallocAndMemsetString(size); | |
118 | // Normal strnlen calls. | |
119 | Ident(strnlen(str - 1, 0)); | |
120 | Ident(strnlen(str, size)); | |
121 | Ident(strnlen(str + size - 1, 1)); | |
122 | str[size - 1] = '\0'; | |
123 | Ident(strnlen(str, 2 * size)); | |
124 | // Argument points to not allocated memory. | |
125 | EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1)); | |
126 | EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0)); | |
127 | // Overwrite the terminating '\0' and hit unallocated memory. | |
128 | str[size - 1] = 'z'; | |
129 | EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0)); | |
130 | free(str); | |
131 | } | |
132 | #endif // SANITIZER_TEST_HAS_STRNLEN | |
133 | ||
7cac9316 XL |
134 | // This test fails with the WinASan dynamic runtime because we fail to intercept |
135 | // strdup. | |
136 | #if defined(_MSC_VER) && defined(_DLL) | |
137 | #define MAYBE_StrDupOOBTest DISABLED_StrDupOOBTest | |
138 | #else | |
139 | #define MAYBE_StrDupOOBTest StrDupOOBTest | |
140 | #endif | |
141 | ||
142 | TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { | |
1a4d82fc JJ |
143 | size_t size = Ident(42); |
144 | char *str = MallocAndMemsetString(size); | |
145 | char *new_str; | |
146 | // Normal strdup calls. | |
147 | str[size - 1] = '\0'; | |
148 | new_str = strdup(str); | |
149 | free(new_str); | |
150 | new_str = strdup(str + size - 1); | |
151 | free(new_str); | |
152 | // Argument points to not allocated memory. | |
153 | EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1)); | |
154 | EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0)); | |
155 | // Overwrite the terminating '\0' and hit unallocated memory. | |
156 | str[size - 1] = 'z'; | |
157 | EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0)); | |
158 | free(str); | |
159 | } | |
160 | ||
2c00a5a8 XL |
161 | #if SANITIZER_TEST_HAS_STRNDUP |
162 | TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { | |
163 | size_t size = Ident(42); | |
164 | char *str = MallocAndMemsetString(size); | |
165 | char *new_str; | |
166 | // Normal strndup calls. | |
167 | str[size - 1] = '\0'; | |
168 | new_str = strndup(str, size - 13); | |
169 | free(new_str); | |
170 | new_str = strndup(str + size - 1, 13); | |
171 | free(new_str); | |
172 | // Argument points to not allocated memory. | |
173 | EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); | |
174 | EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); | |
175 | // Overwrite the terminating '\0' and hit unallocated memory. | |
176 | str[size - 1] = 'z'; | |
177 | EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); | |
178 | // Check handling of non 0 terminated strings. | |
179 | Ident(new_str = strndup(str + size - 1, 0)); | |
180 | free(new_str); | |
181 | Ident(new_str = strndup(str + size - 1, 1)); | |
182 | free(new_str); | |
183 | EXPECT_DEATH(Ident(strndup(str + size - 1, 2)), RightOOBReadMessage(0)); | |
184 | free(str); | |
185 | } | |
186 | #endif // SANITIZER_TEST_HAS_STRNDUP | |
187 | ||
1a4d82fc JJ |
188 | TEST(AddressSanitizer, StrCpyOOBTest) { |
189 | size_t to_size = Ident(30); | |
190 | size_t from_size = Ident(6); // less than to_size | |
191 | char *to = Ident((char*)malloc(to_size)); | |
192 | char *from = Ident((char*)malloc(from_size)); | |
193 | // Normal strcpy calls. | |
194 | strcpy(from, "hello"); | |
195 | strcpy(to, from); | |
196 | strcpy(to + to_size - from_size, from); | |
197 | // Length of "from" is too small. | |
198 | EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0)); | |
199 | // "to" or "from" points to not allocated memory. | |
200 | EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1)); | |
201 | EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1)); | |
202 | EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0)); | |
203 | EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0)); | |
204 | // Overwrite the terminating '\0' character and hit unallocated memory. | |
205 | from[from_size - 1] = '!'; | |
206 | EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0)); | |
207 | free(to); | |
208 | free(from); | |
209 | } | |
210 | ||
211 | TEST(AddressSanitizer, StrNCpyOOBTest) { | |
212 | size_t to_size = Ident(20); | |
213 | size_t from_size = Ident(6); // less than to_size | |
214 | char *to = Ident((char*)malloc(to_size)); | |
215 | // From is a zero-terminated string "hello\0" of length 6 | |
216 | char *from = Ident((char*)malloc(from_size)); | |
217 | strcpy(from, "hello"); | |
218 | // copy 0 bytes | |
219 | strncpy(to, from, 0); | |
220 | strncpy(to - 1, from - 1, 0); | |
221 | // normal strncpy calls | |
222 | strncpy(to, from, from_size); | |
223 | strncpy(to, from, to_size); | |
224 | strncpy(to, from + from_size - 1, to_size); | |
225 | strncpy(to + to_size - 1, from, 1); | |
226 | // One of {to, from} points to not allocated memory | |
227 | EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)), | |
228 | LeftOOBReadMessage(1)); | |
229 | EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)), | |
230 | LeftOOBWriteMessage(1)); | |
231 | EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)), | |
232 | RightOOBReadMessage(0)); | |
233 | EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)), | |
234 | RightOOBWriteMessage(0)); | |
235 | // Length of "to" is too small | |
236 | EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)), | |
237 | RightOOBWriteMessage(0)); | |
238 | EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)), | |
239 | RightOOBWriteMessage(0)); | |
240 | // Overwrite terminator in from | |
241 | from[from_size - 1] = '!'; | |
242 | // normal strncpy call | |
243 | strncpy(to, from, from_size); | |
244 | // Length of "from" is too small | |
245 | EXPECT_DEATH(Ident(strncpy(to, from, to_size)), | |
246 | RightOOBReadMessage(0)); | |
247 | free(to); | |
248 | free(from); | |
249 | } | |
250 | ||
251 | // Users may have different definitions of "strchr" and "index", so provide | |
252 | // function pointer typedefs and overload RunStrChrTest implementation. | |
253 | // We can't use macro for RunStrChrTest body here, as this macro would | |
254 | // confuse EXPECT_DEATH gtest macro. | |
255 | typedef char*(*PointerToStrChr1)(const char*, int); | |
256 | typedef char*(*PointerToStrChr2)(char*, int); | |
257 | ||
5bcae85e SL |
258 | template<typename StrChrFn> |
259 | static void RunStrChrTestImpl(StrChrFn *StrChr) { | |
1a4d82fc JJ |
260 | size_t size = Ident(100); |
261 | char *str = MallocAndMemsetString(size); | |
262 | str[10] = 'q'; | |
263 | str[11] = '\0'; | |
264 | EXPECT_EQ(str, StrChr(str, 'z')); | |
265 | EXPECT_EQ(str + 10, StrChr(str, 'q')); | |
266 | EXPECT_EQ(NULL, StrChr(str, 'a')); | |
267 | // StrChr argument points to not allocated memory. | |
268 | EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1)); | |
269 | EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0)); | |
270 | // Overwrite the terminator and hit not allocated memory. | |
271 | str[11] = 'z'; | |
272 | EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0)); | |
273 | free(str); | |
274 | } | |
5bcae85e SL |
275 | |
276 | // Prefer to use the standard signature if both are available. | |
277 | UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr, ...) { | |
278 | RunStrChrTestImpl(StrChr); | |
279 | } | |
280 | UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr, int) { | |
281 | RunStrChrTestImpl(StrChr); | |
1a4d82fc JJ |
282 | } |
283 | ||
284 | TEST(AddressSanitizer, StrChrAndIndexOOBTest) { | |
5bcae85e | 285 | RunStrChrTest(&strchr, 0); |
92a42be0 SL |
286 | // No index() on Windows and on Android L. |
287 | #if !defined(_WIN32) && !defined(__ANDROID__) | |
5bcae85e | 288 | RunStrChrTest(&index, 0); |
92a42be0 | 289 | #endif |
1a4d82fc JJ |
290 | } |
291 | ||
292 | TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) { | |
293 | // strcmp | |
294 | EXPECT_EQ(0, strcmp("", "")); | |
295 | EXPECT_EQ(0, strcmp("abcd", "abcd")); | |
296 | EXPECT_GT(0, strcmp("ab", "ac")); | |
297 | EXPECT_GT(0, strcmp("abc", "abcd")); | |
298 | EXPECT_LT(0, strcmp("acc", "abc")); | |
299 | EXPECT_LT(0, strcmp("abcd", "abc")); | |
300 | ||
301 | // strncmp | |
302 | EXPECT_EQ(0, strncmp("a", "b", 0)); | |
303 | EXPECT_EQ(0, strncmp("abcd", "abcd", 10)); | |
304 | EXPECT_EQ(0, strncmp("abcd", "abcef", 3)); | |
305 | EXPECT_GT(0, strncmp("abcde", "abcfa", 4)); | |
306 | EXPECT_GT(0, strncmp("a", "b", 5)); | |
307 | EXPECT_GT(0, strncmp("bc", "bcde", 4)); | |
308 | EXPECT_LT(0, strncmp("xyz", "xyy", 10)); | |
309 | EXPECT_LT(0, strncmp("baa", "aaa", 1)); | |
310 | EXPECT_LT(0, strncmp("zyx", "", 2)); | |
311 | ||
92a42be0 | 312 | #if !defined(_WIN32) // no str[n]casecmp on Windows. |
1a4d82fc JJ |
313 | // strcasecmp |
314 | EXPECT_EQ(0, strcasecmp("", "")); | |
315 | EXPECT_EQ(0, strcasecmp("zzz", "zzz")); | |
316 | EXPECT_EQ(0, strcasecmp("abCD", "ABcd")); | |
317 | EXPECT_GT(0, strcasecmp("aB", "Ac")); | |
318 | EXPECT_GT(0, strcasecmp("ABC", "ABCd")); | |
319 | EXPECT_LT(0, strcasecmp("acc", "abc")); | |
320 | EXPECT_LT(0, strcasecmp("ABCd", "abc")); | |
321 | ||
322 | // strncasecmp | |
323 | EXPECT_EQ(0, strncasecmp("a", "b", 0)); | |
324 | EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10)); | |
325 | EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3)); | |
326 | EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4)); | |
327 | EXPECT_GT(0, strncasecmp("a", "B", 5)); | |
328 | EXPECT_GT(0, strncasecmp("bc", "BCde", 4)); | |
329 | EXPECT_LT(0, strncasecmp("xyz", "xyy", 10)); | |
330 | EXPECT_LT(0, strncasecmp("Baa", "aaa", 1)); | |
331 | EXPECT_LT(0, strncasecmp("zyx", "", 2)); | |
92a42be0 | 332 | #endif |
1a4d82fc JJ |
333 | |
334 | // memcmp | |
335 | EXPECT_EQ(0, memcmp("a", "b", 0)); | |
336 | EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4)); | |
337 | EXPECT_GT(0, memcmp("\0ab", "\0ac", 3)); | |
338 | EXPECT_GT(0, memcmp("abb\0", "abba", 4)); | |
339 | EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5)); | |
340 | EXPECT_LT(0, memcmp("zza", "zyx", 3)); | |
341 | } | |
342 | ||
343 | typedef int(*PointerToStrCmp)(const char*, const char*); | |
344 | void RunStrCmpTest(PointerToStrCmp StrCmp) { | |
345 | size_t size = Ident(100); | |
346 | int fill = 'o'; | |
347 | char *s1 = MallocAndMemsetString(size, fill); | |
348 | char *s2 = MallocAndMemsetString(size, fill); | |
349 | s1[size - 1] = '\0'; | |
350 | s2[size - 1] = '\0'; | |
351 | // Normal StrCmp calls | |
352 | Ident(StrCmp(s1, s2)); | |
353 | Ident(StrCmp(s1, s2 + size - 1)); | |
354 | Ident(StrCmp(s1 + size - 1, s2 + size - 1)); | |
1a4d82fc JJ |
355 | // One of arguments points to not allocated memory. |
356 | EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1)); | |
357 | EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1)); | |
358 | EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0)); | |
359 | EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0)); | |
360 | // Hit unallocated memory and die. | |
361 | s1[size - 1] = fill; | |
362 | EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0)); | |
363 | EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0)); | |
364 | free(s1); | |
365 | free(s2); | |
366 | } | |
367 | ||
368 | TEST(AddressSanitizer, StrCmpOOBTest) { | |
369 | RunStrCmpTest(&strcmp); | |
370 | } | |
371 | ||
92a42be0 | 372 | #if !defined(_WIN32) // no str[n]casecmp on Windows. |
1a4d82fc JJ |
373 | TEST(AddressSanitizer, StrCaseCmpOOBTest) { |
374 | RunStrCmpTest(&strcasecmp); | |
375 | } | |
92a42be0 | 376 | #endif |
1a4d82fc JJ |
377 | |
378 | typedef int(*PointerToStrNCmp)(const char*, const char*, size_t); | |
379 | void RunStrNCmpTest(PointerToStrNCmp StrNCmp) { | |
380 | size_t size = Ident(100); | |
381 | char *s1 = MallocAndMemsetString(size); | |
382 | char *s2 = MallocAndMemsetString(size); | |
383 | s1[size - 1] = '\0'; | |
384 | s2[size - 1] = '\0'; | |
385 | // Normal StrNCmp calls | |
386 | Ident(StrNCmp(s1, s2, size + 2)); | |
387 | s1[size - 1] = 'z'; | |
388 | s2[size - 1] = 'x'; | |
389 | Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size)); | |
390 | s2[size - 1] = 'z'; | |
391 | Ident(StrNCmp(s1 - 1, s2 - 1, 0)); | |
392 | Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1)); | |
393 | // One of arguments points to not allocated memory. | |
394 | EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1)); | |
395 | EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1)); | |
396 | EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0)); | |
397 | EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0)); | |
398 | // Hit unallocated memory and die. | |
399 | EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0)); | |
400 | EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0)); | |
401 | free(s1); | |
402 | free(s2); | |
403 | } | |
404 | ||
405 | TEST(AddressSanitizer, StrNCmpOOBTest) { | |
406 | RunStrNCmpTest(&strncmp); | |
407 | } | |
408 | ||
92a42be0 | 409 | #if !defined(_WIN32) // no str[n]casecmp on Windows. |
1a4d82fc JJ |
410 | TEST(AddressSanitizer, StrNCaseCmpOOBTest) { |
411 | RunStrNCmpTest(&strncasecmp); | |
412 | } | |
92a42be0 SL |
413 | #endif |
414 | ||
1a4d82fc JJ |
415 | TEST(AddressSanitizer, StrCatOOBTest) { |
416 | // strcat() reads strlen(to) bytes from |to| before concatenating. | |
417 | size_t to_size = Ident(100); | |
418 | char *to = MallocAndMemsetString(to_size); | |
419 | to[0] = '\0'; | |
420 | size_t from_size = Ident(20); | |
421 | char *from = MallocAndMemsetString(from_size); | |
422 | from[from_size - 1] = '\0'; | |
423 | // Normal strcat calls. | |
424 | strcat(to, from); | |
425 | strcat(to, from); | |
426 | strcat(to + from_size, from + from_size - 2); | |
427 | // Passing an invalid pointer is an error even when concatenating an empty | |
428 | // string. | |
429 | EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1)); | |
430 | // One of arguments points to not allocated memory. | |
431 | EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1)); | |
432 | EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1)); | |
1a4d82fc JJ |
433 | EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0)); |
434 | ||
435 | // "from" is not zero-terminated. | |
436 | from[from_size - 1] = 'z'; | |
437 | EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0)); | |
438 | from[from_size - 1] = '\0'; | |
1a4d82fc | 439 | // "to" is too short to fit "from". |
92a42be0 | 440 | memset(to, 'z', to_size); |
1a4d82fc JJ |
441 | to[to_size - from_size + 1] = '\0'; |
442 | EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0)); | |
443 | // length of "to" is just enough. | |
444 | strcat(to, from + 1); | |
445 | ||
446 | free(to); | |
447 | free(from); | |
448 | } | |
449 | ||
450 | TEST(AddressSanitizer, StrNCatOOBTest) { | |
451 | // strncat() reads strlen(to) bytes from |to| before concatenating. | |
452 | size_t to_size = Ident(100); | |
453 | char *to = MallocAndMemsetString(to_size); | |
454 | to[0] = '\0'; | |
455 | size_t from_size = Ident(20); | |
456 | char *from = MallocAndMemsetString(from_size); | |
457 | // Normal strncat calls. | |
458 | strncat(to, from, 0); | |
459 | strncat(to, from, from_size); | |
460 | from[from_size - 1] = '\0'; | |
461 | strncat(to, from, 2 * from_size); | |
462 | // Catenating empty string with an invalid string is still an error. | |
463 | EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1)); | |
464 | strncat(to, from + from_size - 1, 10); | |
465 | // One of arguments points to not allocated memory. | |
466 | EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1)); | |
467 | EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1)); | |
1a4d82fc JJ |
468 | EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0)); |
469 | ||
470 | memset(from, 'z', from_size); | |
471 | memset(to, 'z', to_size); | |
472 | to[0] = '\0'; | |
473 | // "from" is too short. | |
474 | EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0)); | |
1a4d82fc JJ |
475 | // "to" is too short to fit "from". |
476 | to[0] = 'z'; | |
477 | to[to_size - from_size + 1] = '\0'; | |
478 | EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0)); | |
479 | // "to" is just enough. | |
480 | strncat(to, from, from_size - 2); | |
481 | ||
482 | free(to); | |
483 | free(from); | |
484 | } | |
485 | ||
486 | static string OverlapErrorMessage(const string &func) { | |
487 | return func + "-param-overlap"; | |
488 | } | |
489 | ||
490 | TEST(AddressSanitizer, StrArgsOverlapTest) { | |
491 | size_t size = Ident(100); | |
492 | char *str = Ident((char*)malloc(size)); | |
493 | ||
494 | // Do not check memcpy() on OS X 10.7 and later, where it actually aliases | |
495 | // memmove(). | |
496 | #if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \ | |
497 | (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) | |
498 | // Check "memcpy". Use Ident() to avoid inlining. | |
7cac9316 | 499 | #if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE |
1a4d82fc JJ |
500 | memset(str, 'z', size); |
501 | Ident(memcpy)(str + 1, str + 11, 10); | |
502 | Ident(memcpy)(str, str, 0); | |
503 | EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy")); | |
504 | EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy")); | |
7cac9316 | 505 | #endif |
1a4d82fc JJ |
506 | #endif |
507 | ||
508 | // We do not treat memcpy with to==from as a bug. | |
509 | // See http://llvm.org/bugs/show_bug.cgi?id=11763. | |
510 | // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1), | |
511 | // OverlapErrorMessage("memcpy")); | |
512 | ||
513 | // Check "strcpy". | |
514 | memset(str, 'z', size); | |
515 | str[9] = '\0'; | |
516 | strcpy(str + 10, str); | |
517 | EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy")); | |
518 | EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy")); | |
519 | strcpy(str, str + 5); | |
520 | ||
521 | // Check "strncpy". | |
522 | memset(str, 'z', size); | |
523 | strncpy(str, str + 10, 10); | |
524 | EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy")); | |
525 | EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy")); | |
526 | str[10] = '\0'; | |
527 | strncpy(str + 11, str, 20); | |
528 | EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy")); | |
529 | ||
530 | // Check "strcat". | |
531 | memset(str, 'z', size); | |
532 | str[10] = '\0'; | |
533 | str[20] = '\0'; | |
534 | strcat(str, str + 10); | |
535 | EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat")); | |
536 | str[10] = '\0'; | |
537 | strcat(str + 11, str); | |
538 | EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat")); | |
539 | EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat")); | |
540 | EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat")); | |
541 | ||
542 | // Check "strncat". | |
543 | memset(str, 'z', size); | |
544 | str[10] = '\0'; | |
545 | strncat(str, str + 10, 10); // from is empty | |
546 | EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat")); | |
547 | str[10] = '\0'; | |
548 | str[20] = '\0'; | |
549 | strncat(str + 5, str, 5); | |
550 | str[10] = '\0'; | |
551 | EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat")); | |
552 | EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat")); | |
553 | ||
554 | free(str); | |
555 | } | |
556 | ||
1a4d82fc JJ |
557 | typedef void(*PointerToCallAtoi)(const char*); |
558 | ||
559 | void RunAtoiOOBTest(PointerToCallAtoi Atoi) { | |
560 | char *array = MallocAndMemsetString(10, '1'); | |
561 | // Invalid pointer to the string. | |
562 | EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1)); | |
563 | EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1)); | |
564 | // Die if a buffer doesn't have terminating NULL. | |
565 | EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); | |
92a42be0 | 566 | // Make last symbol a terminating NULL |
1a4d82fc JJ |
567 | array[9] = '\0'; |
568 | Atoi(array); | |
1a4d82fc JJ |
569 | // Sometimes we need to detect overflow if no digits are found. |
570 | memset(array, ' ', 10); | |
571 | EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); | |
572 | array[9] = '-'; | |
573 | EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0)); | |
574 | EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0)); | |
1a4d82fc JJ |
575 | free(array); |
576 | } | |
577 | ||
92a42be0 SL |
578 | #if !defined(_WIN32) // FIXME: Fix and enable on Windows. |
579 | void CallAtoi(const char *nptr) { | |
580 | Ident(atoi(nptr)); | |
581 | } | |
582 | void CallAtol(const char *nptr) { | |
583 | Ident(atol(nptr)); | |
584 | } | |
585 | void CallAtoll(const char *nptr) { | |
586 | Ident(atoll(nptr)); | |
587 | } | |
1a4d82fc JJ |
588 | TEST(AddressSanitizer, AtoiAndFriendsOOBTest) { |
589 | RunAtoiOOBTest(&CallAtoi); | |
590 | RunAtoiOOBTest(&CallAtol); | |
591 | RunAtoiOOBTest(&CallAtoll); | |
592 | } | |
92a42be0 | 593 | #endif |
1a4d82fc | 594 | |
1a4d82fc JJ |
595 | typedef void(*PointerToCallStrtol)(const char*, char**, int); |
596 | ||
597 | void RunStrtolOOBTest(PointerToCallStrtol Strtol) { | |
598 | char *array = MallocAndMemsetString(3); | |
1a4d82fc JJ |
599 | array[0] = '1'; |
600 | array[1] = '2'; | |
601 | array[2] = '3'; | |
602 | // Invalid pointer to the string. | |
603 | EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0)); | |
604 | EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1)); | |
605 | // Buffer overflow if there is no terminating null (depends on base). | |
1a4d82fc JJ |
606 | EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); |
607 | array[2] = 'z'; | |
1a4d82fc JJ |
608 | EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0)); |
609 | // Add terminating zero to get rid of overflow. | |
610 | array[2] = '\0'; | |
611 | Strtol(array, NULL, 36); | |
1a4d82fc JJ |
612 | // Sometimes we need to detect overflow if no digits are found. |
613 | array[0] = array[1] = array[2] = ' '; | |
614 | EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); | |
615 | array[2] = '+'; | |
616 | EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); | |
617 | array[2] = '-'; | |
618 | EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0)); | |
1a4d82fc JJ |
619 | free(array); |
620 | } | |
621 | ||
92a42be0 SL |
622 | #if !defined(_WIN32) // FIXME: Fix and enable on Windows. |
623 | void CallStrtol(const char *nptr, char **endptr, int base) { | |
624 | Ident(strtol(nptr, endptr, base)); | |
625 | } | |
626 | void CallStrtoll(const char *nptr, char **endptr, int base) { | |
627 | Ident(strtoll(nptr, endptr, base)); | |
628 | } | |
1a4d82fc JJ |
629 | TEST(AddressSanitizer, StrtollOOBTest) { |
630 | RunStrtolOOBTest(&CallStrtoll); | |
631 | } | |
632 | TEST(AddressSanitizer, StrtolOOBTest) { | |
633 | RunStrtolOOBTest(&CallStrtol); | |
634 | } | |
92a42be0 | 635 | #endif |