1//===-- asan_mem_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 <string.h>
13#include "asan_test_utils.h"
14#if defined(_GNU_SOURCE)
15#include <strings.h> // for bcmp
16#endif
17#include <vector>
18
19template<typename T>
20void MemSetOOBTestTemplate(size_t length) {
21 if (length == 0) return;
22 size_t size = Ident(sizeof(T) * length);
23 T *array = Ident((T*)malloc(size: size));
24 int element = Ident(42);
25 int zero = Ident(0);
26 void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
27 // memset interval inside array
28 MEMSET(array, element, size);
29 MEMSET(array, element, size - 1);
30 MEMSET(array + length - 1, element, sizeof(T));
31 MEMSET(array, element, 1);
32
33 // memset 0 bytes
34 MEMSET(array - 10, element, zero);
35 MEMSET(array - 1, element, zero);
36 MEMSET(array, element, zero);
37 MEMSET(array + length, 0, zero);
38 MEMSET(array + length + 1, 0, zero);
39
40 // try to memset bytes after array
41 EXPECT_DEATH(MEMSET(array, 0, size + 1),
42 RightOOBWriteMessage(0));
43 EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
44 RightOOBWriteMessage(0));
45 EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
46 RightOOBWriteMessage(0));
47 // whole interval is after
48 EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
49 RightOOBWriteMessage(sizeof(T)));
50
51 // try to memset bytes before array
52 EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
53 LeftOOBWriteMessage(1));
54 EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
55 LeftOOBWriteMessage(5));
56 if (length >= 100) {
57 // Large OOB, we find it only if the redzone is large enough.
58 EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
59 LeftOOBWriteMessage(5 * sizeof(T)));
60 }
61 // whole interval is before
62 EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
63 LeftOOBWriteMessage(2 * sizeof(T)));
64
65 // try to memset bytes both before & after
66 EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
67 LeftOOBWriteMessage(2));
68
69 free(array);
70}
71
72TEST(AddressSanitizer, MemSetOOBTest) {
73 MemSetOOBTestTemplate<char>(length: 100);
74 MemSetOOBTestTemplate<int>(length: 5);
75 MemSetOOBTestTemplate<double>(length: 256);
76 // We can test arrays of structres/classes here, but what for?
77}
78
79// Try to allocate two arrays of 'size' bytes that are near each other.
80// Strictly speaking we are not guaranteed to find such two pointers,
81// but given the structure of asan's allocator we will.
82static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
83 std::vector<uintptr_t> v;
84 bool res = false;
85 for (size_t i = 0; i < 1000U && !res; i++) {
86 v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
87 if (i == 0) continue;
88 sort(v.begin(), v.end());
89 for (size_t j = 1; j < v.size(); j++) {
90 assert(v[j] > v[j-1]);
91 if ((size_t)(v[j] - v[j-1]) < size * 2) {
92 *x2 = reinterpret_cast<char*>(v[j]);
93 *x1 = reinterpret_cast<char*>(v[j-1]);
94 res = true;
95 break;
96 }
97 }
98 }
99
100 for (size_t i = 0; i < v.size(); i++) {
101 char *p = reinterpret_cast<char *>(v[i]);
102 if (res && p == *x1) continue;
103 if (res && p == *x2) continue;
104 delete [] p;
105 }
106 return res;
107}
108
109TEST(AddressSanitizer, LargeOOBInMemset) {
110 for (size_t size = 200; size < 100000; size += size / 2) {
111 char *x1, *x2;
112 if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
113 continue;
114 // fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
115 // Do a memset on x1 with huge out-of-bound access that will end up in x2.
116 EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
117 "is located 0 bytes after");
118 delete [] x1;
119 delete [] x2;
120 return;
121 }
122 assert(0 && "Did not find two adjacent malloc-ed pointers");
123}
124
125// Same test for memcpy and memmove functions
126template <typename T, class M>
127void MemTransferOOBTestTemplate(size_t length) {
128 if (length == 0) return;
129 size_t size = Ident(sizeof(T) * length);
130 T *src = Ident((T*)malloc(size: size));
131 T *dest = Ident((T*)malloc(size: size));
132 int zero = Ident(0);
133
134 // valid transfer of bytes between arrays
135 M::transfer(dest, src, size);
136 M::transfer(dest + 1, src, size - sizeof(T));
137 M::transfer(dest, src + length - 1, sizeof(T));
138 M::transfer(dest, src, 1);
139
140 // transfer zero bytes
141 M::transfer(dest - 1, src, 0);
142 M::transfer(dest + length, src, zero);
143 M::transfer(dest, src - 1, zero);
144 M::transfer(dest, src, zero);
145
146 // try to change mem after dest
147 EXPECT_DEATH(M::transfer(dest + 1, src, size),
148 RightOOBWriteMessage(0));
149 EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
150 RightOOBWriteMessage(0));
151
152 // try to change mem before dest
153 EXPECT_DEATH(M::transfer(dest - 2, src, size),
154 LeftOOBWriteMessage(2 * sizeof(T)));
155 EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
156 LeftOOBWriteMessage(3));
157
158 // try to access mem after src
159 EXPECT_DEATH(M::transfer(dest, src + 2, size),
160 RightOOBReadMessage(0));
161 EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
162 RightOOBReadMessage(0));
163
164 // try to access mem before src
165 EXPECT_DEATH(M::transfer(dest, src - 1, size),
166 LeftOOBReadMessage(sizeof(T)));
167 EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
168 LeftOOBReadMessage(6));
169
170 // Generally we don't need to test cases where both accessing src and writing
171 // to dest address to poisoned memory.
172
173 T *big_src = Ident((T*)malloc(size: size * 2));
174 T *big_dest = Ident((T*)malloc(size: size * 2));
175 // try to change mem to both sides of dest
176 EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
177 LeftOOBWriteMessage(sizeof(T)));
178 // try to access mem to both sides of src
179 EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
180 LeftOOBReadMessage(2 * sizeof(T)));
181
182 free(src);
183 free(dest);
184 free(big_src);
185 free(big_dest);
186}
187
188class MemCpyWrapper {
189 public:
190 static void* transfer(void *to, const void *from, size_t size) {
191 return Ident(memcpy)(to, from, size);
192 }
193};
194
195TEST(AddressSanitizer, MemCpyOOBTest) {
196 MemTransferOOBTestTemplate<char, MemCpyWrapper>(length: 100);
197 MemTransferOOBTestTemplate<int, MemCpyWrapper>(length: 1024);
198}
199
200class MemMoveWrapper {
201 public:
202 static void* transfer(void *to, const void *from, size_t size) {
203 return Ident(memmove)(to, from, size);
204 }
205};
206
207TEST(AddressSanitizer, MemMoveOOBTest) {
208 MemTransferOOBTestTemplate<char, MemMoveWrapper>(length: 100);
209 MemTransferOOBTestTemplate<int, MemMoveWrapper>(length: 1024);
210}
211
212template <int (*cmpfn)(const void *, const void *, size_t)>
213void CmpOOBTestCommon() {
214 size_t size = Ident(100);
215 char *s1 = MallocAndMemsetString(size);
216 char *s2 = MallocAndMemsetString(size);
217 // Normal cmpfn calls.
218 Ident(cmpfn(s1, s2, size));
219 Ident(cmpfn(s1 + size - 1, s2 + size - 1, 1));
220 Ident(cmpfn(s1 - 1, s2 - 1, 0));
221 // One of arguments points to not allocated memory.
222 EXPECT_DEATH(Ident(cmpfn)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
223 EXPECT_DEATH(Ident(cmpfn)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
224 EXPECT_DEATH(Ident(cmpfn)(s1 + size, s2, 1), RightOOBReadMessage(0));
225 EXPECT_DEATH(Ident(cmpfn)(s1, s2 + size, 1), RightOOBReadMessage(0));
226 // Hit unallocated memory and die.
227 EXPECT_DEATH(Ident(cmpfn)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
228 EXPECT_DEATH(Ident(cmpfn)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
229 // Zero bytes are not terminators and don't prevent from OOB.
230 s1[size - 1] = '\0';
231 s2[size - 1] = '\0';
232 EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
233
234 // Even if the buffers differ in the first byte, we still assume that
235 // cmpfn may access the whole buffer and thus reporting the overflow here:
236 s1[0] = 1;
237 s2[0] = 123;
238 EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0));
239
240 free(ptr: s1);
241 free(ptr: s2);
242}
243
244TEST(AddressSanitizer, MemCmpOOBTest) { CmpOOBTestCommon<memcmp>(); }
245
246TEST(AddressSanitizer, BCmpOOBTest) {
247#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || \
248 defined(__NetBSD__) || defined(__FreeBSD__)
249 CmpOOBTestCommon<bcmp>();
250#endif
251}
252

source code of compiler-rt/lib/asan/tests/asan_mem_test.cpp