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