1 | //===-- asan_oob_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 | // This file is a part of AddressSanitizer, an address sanity checker. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | #include "asan_test_utils.h" |
13 | |
14 | NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) { |
15 | EXPECT_EQ(0U, ((uintptr_t)p % size)); |
16 | if (size == 1) asan_write((uint8_t*)p); |
17 | else if (size == 2) asan_write((uint16_t*)p); |
18 | else if (size == 4) asan_write((uint32_t*)p); |
19 | else if (size == 8) asan_write((uint64_t*)p); |
20 | } |
21 | |
22 | template<typename T> |
23 | NOINLINE void oob_test(int size, int off) { |
24 | char *p = (char*)malloc_aaa(size); |
25 | // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n", |
26 | // sizeof(T), p, p + size, off); |
27 | asan_write((T*)(p + off)); |
28 | free_aaa(p); |
29 | } |
30 | |
31 | static std::string GetLeftOOBMessage(int off) { |
32 | char str[100]; |
33 | sprintf(s: str, format: "is located.*%d byte.*before" , off); |
34 | return str; |
35 | } |
36 | |
37 | static std::string GetRightOOBMessage(int off) { |
38 | char str[100]; |
39 | #if !defined(_WIN32) |
40 | // FIXME: Fix PR42868 and remove SEGV match. |
41 | sprintf(s: str, format: "is located.*%d byte.*after|SEGV" , off); |
42 | #else |
43 | // `|` doesn't work in googletest's regexes on Windows, |
44 | // see googletest/docs/advanced.md#regular-expression-syntax |
45 | // But it's not needed on Windows anyways. |
46 | sprintf(str, "is located.*%d byte.*after" , off); |
47 | #endif |
48 | return str; |
49 | } |
50 | |
51 | template<typename T> |
52 | void OOBTest() { |
53 | for (int size = sizeof(T); size < 20; size += 5) { |
54 | for (int i = -5; i < 0; i++) |
55 | EXPECT_DEATH(oob_test<T>(size, i), GetLeftOOBMessage(-i)); |
56 | |
57 | for (int i = 0; i < (int)(size - sizeof(T) + 1); i++) |
58 | oob_test<T>(size, i); |
59 | |
60 | for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) { |
61 | // we don't catch unaligned partially OOB accesses. |
62 | if (i % sizeof(T)) continue; |
63 | int off = i >= size ? (i - size) : 0; |
64 | EXPECT_DEATH(oob_test<T>(size, i), GetRightOOBMessage(off)); |
65 | } |
66 | } |
67 | |
68 | EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1), GetLeftOOBMessage(1)); |
69 | EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc), GetRightOOBMessage(0)); |
70 | } |
71 | |
72 | // TODO(glider): the following tests are EXTREMELY slow on Darwin: |
73 | // AddressSanitizer.OOB_char (125503 ms) |
74 | // AddressSanitizer.OOB_int (126890 ms) |
75 | // AddressSanitizer.OOBRightTest (315605 ms) |
76 | // AddressSanitizer.SimpleStackTest (366559 ms) |
77 | |
78 | TEST(AddressSanitizer, OOB_char) { |
79 | OOBTest<U1>(); |
80 | } |
81 | |
82 | TEST(AddressSanitizer, OOB_int) { |
83 | OOBTest<U4>(); |
84 | } |
85 | |
86 | TEST(AddressSanitizer, OOBRightTest) { |
87 | size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4; |
88 | for (size_t access_size = 1; access_size <= max_access_size; |
89 | access_size *= 2) { |
90 | for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) { |
91 | for (size_t offset = 0; offset <= 8; offset += access_size) { |
92 | void *p = malloc(size: alloc_size); |
93 | // allocated: [p, p + alloc_size) |
94 | // accessed: [p + offset, p + offset + access_size) |
95 | uint8_t *addr = (uint8_t*)p + offset; |
96 | if (offset + access_size <= alloc_size) { |
97 | asan_write_sized_aligned(p: addr, size: access_size); |
98 | } else { |
99 | int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0; |
100 | EXPECT_DEATH(asan_write_sized_aligned(addr, access_size), |
101 | GetRightOOBMessage(outside_bytes)); |
102 | } |
103 | free(ptr: p); |
104 | } |
105 | } |
106 | } |
107 | } |
108 | |
109 | TEST(AddressSanitizer, LargeOOBRightTest) { |
110 | size_t large_power_of_two = 1 << 19; |
111 | for (size_t i = 16; i <= 256; i *= 2) { |
112 | size_t size = large_power_of_two - i; |
113 | char *p = Ident(new char[size]); |
114 | EXPECT_DEATH(p[size] = 0, GetRightOOBMessage(0)); |
115 | delete [] p; |
116 | } |
117 | } |
118 | |
119 | TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) { |
120 | oob_test<U1>(10, -1); |
121 | } |
122 | |
123 | TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) { |
124 | oob_test<U1>(kLargeMalloc, -1); |
125 | } |
126 | |
127 | TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) { |
128 | oob_test<U1>(10, 10); |
129 | } |
130 | |
131 | TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) { |
132 | oob_test<U1>(kLargeMalloc, kLargeMalloc); |
133 | } |
134 | |