OLD | NEW |
1 //===- subzero/runtime/szrt_asan.c - AddressSanitizer Runtime -----*- C -*-===// | 1 //===- subzero/runtime/szrt_asan.c - AddressSanitizer Runtime -----*- C -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// \brief Provides the AddressSanitizer runtime. | 11 /// \brief Provides the AddressSanitizer runtime. |
12 /// | 12 /// |
13 /// Exposes functions for initializing the shadow memory region and managing it | 13 /// Exposes functions for initializing the shadow memory region and managing it |
14 /// on loads, stores, and allocations. | 14 /// on loads, stores, and allocations. |
15 /// | 15 /// |
16 //===----------------------------------------------------------------------===// | 16 //===----------------------------------------------------------------------===// |
17 | 17 |
18 #include <assert.h> | 18 #include <assert.h> |
19 #include <errno.h> | 19 #include <errno.h> |
20 #include <limits.h> | 20 #include <limits.h> |
| 21 #include <sched.h> |
21 #include <stdbool.h> | 22 #include <stdbool.h> |
22 #include <stddef.h> | 23 #include <stddef.h> |
23 #include <stdint.h> | 24 #include <stdint.h> |
24 #include <stdio.h> | 25 #include <stdio.h> |
25 #include <stdlib.h> | 26 #include <stdlib.h> |
26 #include <string.h> | 27 #include <string.h> |
27 #include <sys/mman.h> | 28 #include <sys/mman.h> |
28 | 29 |
| 30 #if _POSIX_THREADS |
| 31 |
| 32 #include <pthread.h> |
| 33 typedef pthread_mutex_t mutex_t; |
| 34 #define MUTEX_INITIALIZER (PTHREAD_MUTEX_INITIALIZER) |
| 35 #define MUTEX_LOCK(mutex) (pthread_mutex_lock(&(mutex))) |
| 36 #define MUTEX_UNLOCK(mutex) (pthread_mutex_unlock(&(mutex))) |
| 37 |
| 38 #else // !_POSIX_THREADS |
| 39 |
| 40 typedef uint32_t mutex_t; |
| 41 #define MUTEX_INITIALIZER (0) |
| 42 #define MUTEX_LOCK(mutex) \ |
| 43 while (__sync_swap((mutex), 1) != 0) { \ |
| 44 sched_yield(); \ |
| 45 } |
| 46 #define MUTEX_UNLOCK(mutex) (__sync_swap((mutex), 0)) |
| 47 |
| 48 #endif // _POSIX_THREADS |
| 49 |
29 #define RZ_SIZE (32) | 50 #define RZ_SIZE (32) |
30 #define SHADOW_SCALE_LOG2 (3) | 51 #define SHADOW_SCALE_LOG2 (3) |
31 #define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2) | 52 #define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2) |
32 #define DEBUG (0) | 53 #define DEBUG (1) |
33 | 54 |
34 // Assuming 48 bit address space on 64 bit systems | 55 // Assuming 48 bit address space on 64 bit systems |
35 #define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2)) | 56 #define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2)) |
36 #define SHADOW_LENGTH_32 (1u << (32 - SHADOW_SCALE_LOG2)) | 57 #define SHADOW_LENGTH_32 (1u << (32 - SHADOW_SCALE_LOG2)) |
37 #define WORD_SIZE (sizeof(uint32_t)) | 58 #define WORD_SIZE (sizeof(uint32_t)) |
38 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) | 59 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) |
39 | 60 |
40 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) | 61 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) |
41 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) | 62 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) |
42 | 63 |
43 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) | 64 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) |
44 #define SHADOW2MEM(p) \ | 65 #define SHADOW2MEM(p) \ |
45 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) | 66 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) |
46 | 67 |
| 68 #define QUARANTINE_MAX_SIZE ((size_t)1 << 28) // 256 MB |
| 69 |
47 #define STACK_POISON_VAL ((char)-1) | 70 #define STACK_POISON_VAL ((char)-1) |
48 #define HEAP_POISON_VAL ((char)-2) | 71 #define HEAP_POISON_VAL ((char)-2) |
49 #define GLOBAL_POISON_VAL ((char)-3) | 72 #define GLOBAL_POISON_VAL ((char)-3) |
| 73 #define FREED_POISON_VAL ((char)-4) |
50 #define MEMTYPE_INDEX(x) (-1 - (x)) | 74 #define MEMTYPE_INDEX(x) (-1 - (x)) |
51 static const char *memtype_names[] = {"stack", "heap", "global"}; | 75 static const char *memtype_names[] = {"stack", "heap", "global", "freed"}; |
52 | 76 |
53 #define ACCESS_LOAD (0) | 77 #define ACCESS_LOAD (0) |
54 #define ACCESS_STORE (1) | 78 #define ACCESS_STORE (1) |
55 static const char *access_names[] = {"load from", "store to"}; | 79 static const char *access_names[] = {"load from", "store to"}; |
56 | 80 |
57 #if DEBUG | 81 #if DEBUG |
58 #define DUMP(args...) \ | 82 #define DUMP(args...) \ |
59 do { \ | 83 do { \ |
60 printf(args); \ | 84 printf(args); \ |
61 } while (false); | 85 } while (false); |
(...skipping 10 matching lines...) Expand all Loading... |
72 void __asan_init(int, void **, int *); | 96 void __asan_init(int, void **, int *); |
73 void __asan_check_load(char *, int); | 97 void __asan_check_load(char *, int); |
74 void __asan_check_store(char *, int); | 98 void __asan_check_store(char *, int); |
75 void *__asan_malloc(size_t); | 99 void *__asan_malloc(size_t); |
76 void *__asan_calloc(size_t, size_t); | 100 void *__asan_calloc(size_t, size_t); |
77 void *__asan_realloc(char *, size_t); | 101 void *__asan_realloc(char *, size_t); |
78 void __asan_free(char *); | 102 void __asan_free(char *); |
79 void __asan_poison(char *, int, char); | 103 void __asan_poison(char *, int, char); |
80 void __asan_unpoison(char *, int); | 104 void __asan_unpoison(char *, int); |
81 | 105 |
| 106 struct quarantine_entry { |
| 107 struct quarantine_entry *next; |
| 108 size_t size; |
| 109 }; |
| 110 |
| 111 mutex_t quarantine_lock = MUTEX_INITIALIZER; |
| 112 uint64_t quarantine_size = 0; |
| 113 struct quarantine_entry *quarantine_head = NULL; |
| 114 struct quarantine_entry *quarantine_tail = NULL; |
| 115 |
82 static void __asan_error(char *ptr, int size, int access) { | 116 static void __asan_error(char *ptr, int size, int access) { |
83 char *shadow_addr = MEM2SHADOW(ptr); | 117 char *shadow_addr = MEM2SHADOW(ptr); |
84 char shadow_val = *shadow_addr; | 118 char shadow_val = *shadow_addr; |
85 if (shadow_val > 0) | 119 if (shadow_val > 0) |
86 shadow_val = *(shadow_addr + 1); | 120 shadow_val = *(shadow_addr + 1); |
87 assert(access == ACCESS_LOAD || access == ACCESS_STORE); | 121 assert(access == ACCESS_LOAD || access == ACCESS_STORE); |
88 const char *access_name = access_names[access]; | 122 const char *access_name = access_names[access]; |
89 assert(shadow_val == STACK_POISON_VAL || shadow_val == HEAP_POISON_VAL || | 123 assert(shadow_val == STACK_POISON_VAL || shadow_val == HEAP_POISON_VAL || |
90 shadow_val == GLOBAL_POISON_VAL); | 124 shadow_val == GLOBAL_POISON_VAL || shadow_val == FREED_POISON_VAL); |
91 const char *memtype = memtype_names[MEMTYPE_INDEX(shadow_val)]; | 125 const char *memtype = memtype_names[MEMTYPE_INDEX(shadow_val)]; |
92 fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, access_name, | 126 fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, access_name, |
93 memtype, ptr); | 127 memtype, ptr); |
94 abort(); | 128 abort(); |
95 } | 129 } |
96 | 130 |
97 // check only the first byte of each word unless strict | 131 // check only the first byte of each word unless strict |
98 static bool __asan_check(char *ptr, int size) { | 132 static bool __asan_check(char *ptr, int size) { |
99 assert(size == 1 || size == 2 || size == 4 || size == 8); | 133 assert(size == 1 || size == 2 || size == 4 || size == 8); |
100 char *shadow_addr = (char *)MEM2SHADOW(ptr); | 134 char *shadow_addr = (char *)MEM2SHADOW(ptr); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 if (new_alloc == NULL) | 240 if (new_alloc == NULL) |
207 return NULL; | 241 return NULL; |
208 size_t copyable = (size < old_size) ? size : old_size; | 242 size_t copyable = (size < old_size) ? size : old_size; |
209 memcpy(new_alloc, ptr, copyable); | 243 memcpy(new_alloc, ptr, copyable); |
210 __asan_free(ptr); | 244 __asan_free(ptr); |
211 return new_alloc; | 245 return new_alloc; |
212 } | 246 } |
213 | 247 |
214 void __asan_free(char *ptr) { | 248 void __asan_free(char *ptr) { |
215 DUMP("free() called on %p\n", ptr); | 249 DUMP("free() called on %p\n", ptr); |
| 250 if (ptr == NULL) |
| 251 return; |
| 252 if (*(char *)MEM2SHADOW(ptr) == FREED_POISON_VAL) { |
| 253 fprintf(stderr, "Double free of object at %p\n", ptr); |
| 254 abort(); |
| 255 } |
216 char *rz_left, *rz_right; | 256 char *rz_left, *rz_right; |
217 __asan_get_redzones(ptr, &rz_left, &rz_right); | 257 __asan_get_redzones(ptr, &rz_left, &rz_right); |
218 size_t rz_right_size = *(size_t *)rz_right; | 258 size_t rz_right_size = *(size_t *)rz_right; |
219 __asan_unpoison(rz_left, RZ_SIZE); | 259 size_t total_size = rz_right_size + (rz_right - rz_left); |
220 __asan_unpoison(rz_right, rz_right_size); | 260 __asan_poison(rz_left, total_size, FREED_POISON_VAL); |
221 free(rz_left); | 261 |
| 262 // place allocation in quarantine |
| 263 struct quarantine_entry *entry = (struct quarantine_entry *)rz_left; |
| 264 assert(entry != NULL); |
| 265 entry->next = NULL; |
| 266 entry->size = total_size; |
| 267 |
| 268 DUMP("Placing %d bytes at %p in quarantine\n", entry->size, entry); |
| 269 MUTEX_LOCK(&quarantine_lock); |
| 270 if (quarantine_tail != NULL) |
| 271 quarantine_tail->next = entry; |
| 272 quarantine_tail = entry; |
| 273 if (quarantine_head == NULL) |
| 274 quarantine_head = entry; |
| 275 quarantine_size += total_size; |
| 276 DUMP("Quarantine size is %llu\n", quarantine_size); |
| 277 |
| 278 // free old objects as necessary |
| 279 while (quarantine_size > QUARANTINE_MAX_SIZE) { |
| 280 struct quarantine_entry *freed = quarantine_head; |
| 281 assert(freed != NULL); |
| 282 __asan_unpoison((char *)freed, freed->size); |
| 283 quarantine_size -= freed->size; |
| 284 quarantine_head = freed->next; |
| 285 DUMP("Releasing %d bytes at %p from quarantine\n", freed->size, freed); |
| 286 DUMP("Quarantine size is %llu\n", quarantine_size); |
| 287 free(freed); |
| 288 } |
| 289 MUTEX_UNLOCK(&quarantine_lock); |
222 } | 290 } |
223 | 291 |
224 void __asan_poison(char *ptr, int size, char poison_val) { | 292 void __asan_poison(char *ptr, int size, char poison_val) { |
225 char *end = ptr + size; | 293 char *end = ptr + size; |
226 assert(IS_SHADOW_ALIGNED(end)); | 294 assert(IS_SHADOW_ALIGNED(end)); |
227 // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment | |
228 assert(size < 2 * RZ_SIZE); | |
229 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), | 295 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
230 MEM2SHADOW(end)); | 296 MEM2SHADOW(end)); |
231 size_t offset = SHADOW_OFFSET(ptr); | 297 size_t offset = SHADOW_OFFSET(ptr); |
232 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset; | 298 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset; |
233 ptr += SHADOW_OFFSET(size); | 299 ptr += SHADOW_OFFSET(size); |
234 assert(IS_SHADOW_ALIGNED(ptr)); | 300 assert(IS_SHADOW_ALIGNED(ptr)); |
235 int len = (end - ptr) >> SHADOW_SCALE_LOG2; | 301 int len = (end - ptr) >> SHADOW_SCALE_LOG2; |
236 memset(MEM2SHADOW(ptr), poison_val, len); | 302 memset(MEM2SHADOW(ptr), poison_val, len); |
237 } | 303 } |
238 | 304 |
239 void __asan_unpoison(char *ptr, int size) { | 305 void __asan_unpoison(char *ptr, int size) { |
240 char *end = ptr + size; | 306 char *end = ptr + size; |
241 assert(IS_SHADOW_ALIGNED(end)); | 307 assert(IS_SHADOW_ALIGNED(end)); |
242 assert(size < 2 * RZ_SIZE); | |
243 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), | 308 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
244 MEM2SHADOW(end)); | 309 MEM2SHADOW(end)); |
245 *(char *)MEM2SHADOW(ptr) = 0; | 310 *(char *)MEM2SHADOW(ptr) = 0; |
246 ptr += SHADOW_OFFSET(size); | 311 ptr += SHADOW_OFFSET(size); |
247 assert(IS_SHADOW_ALIGNED(ptr)); | 312 assert(IS_SHADOW_ALIGNED(ptr)); |
248 memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2); | 313 memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2); |
249 } | 314 } |
OLD | NEW |