Chromium Code Reviews| 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 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 #define WORD_SIZE (sizeof(uint32_t)) | 37 #define WORD_SIZE (sizeof(uint32_t)) |
| 38 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) | 38 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) |
| 39 | 39 |
| 40 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) | 40 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) |
| 41 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) | 41 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) |
| 42 | 42 |
| 43 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) | 43 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) |
| 44 #define SHADOW2MEM(p) \ | 44 #define SHADOW2MEM(p) \ |
| 45 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) | 45 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) |
| 46 | 46 |
| 47 #define POISON_VAL (-1) | 47 #define STACK_POISON_VAL ((char)-1) |
| 48 #define HEAP_POISON_VAL ((char)-2) | |
| 49 #define GLOBAL_POISON_VAL ((char)-3) | |
| 50 | |
| 51 #define ACCESS_LOAD (0) | |
| 52 #define ACCESS_STORE (1) | |
| 48 | 53 |
| 49 #if DEBUG | 54 #if DEBUG |
| 50 #define DUMP(args...) \ | 55 #define DUMP(args...) \ |
| 51 do { \ | 56 do { \ |
| 52 printf(args); \ | 57 printf(args); \ |
| 53 } while (false); | 58 } while (false); |
| 54 #else // !DEBUG | 59 #else // !DEBUG |
| 55 #define DUMP(args...) | 60 #define DUMP(args...) |
| 56 #endif // DEBUG | 61 #endif // DEBUG |
| 57 | 62 |
| 58 static char *shadow_offset = NULL; | 63 static char *shadow_offset = NULL; |
| 59 | 64 |
| 60 static void __asan_error(char *, int); | 65 static bool __asan_check(char *, int); |
| 61 static void __asan_check(char *, int); | 66 static void __asan_error(char *, int, int); |
| 62 static void __asan_get_redzones(char *, char **, char **); | 67 static void __asan_get_redzones(char *, char **, char **); |
| 63 | 68 |
| 64 void __asan_init(int, void **, int *); | 69 void __asan_init(int, void **, int *); |
| 65 void __asan_check_load(char *, int); | 70 void __asan_check_load(char *, int); |
| 66 void __asan_check_store(char *, int); | 71 void __asan_check_store(char *, int); |
| 67 void *__asan_malloc(size_t); | 72 void *__asan_malloc(size_t); |
| 68 void *__asan_calloc(size_t, size_t); | 73 void *__asan_calloc(size_t, size_t); |
| 69 void *__asan_realloc(char *, size_t); | 74 void *__asan_realloc(char *, size_t); |
| 70 void __asan_free(char *); | 75 void __asan_free(char *); |
| 71 void __asan_poison(char *, int); | 76 void __asan_poison(char *, int, char); |
| 72 void __asan_unpoison(char *, int); | 77 void __asan_unpoison(char *, int); |
| 73 | 78 |
| 74 static void __asan_error(char *ptr, int size) { | 79 static void __asan_error(char *ptr, int size, int access) { |
| 75 fprintf(stderr, "Illegal access of %d bytes at %p\n", size, ptr); | 80 char *shadow_addr = MEM2SHADOW(ptr); |
| 81 char shadow_val = *shadow_addr; | |
| 82 if (shadow_val > 0) | |
| 83 shadow_val = *(shadow_addr + 1); | |
| 84 char *accesstype = NULL; | |
| 85 switch (access) { | |
|
Karl
2016/08/04 14:42:24
Why not use a global array with these values, and
Jim Stichnoth
2016/08/04 14:55:09
That sounds appealing, but note that it will proba
tlively
2016/08/04 17:58:22
Done.
| |
| 86 case ACCESS_LOAD: | |
| 87 accesstype = "load from"; | |
| 88 break; | |
| 89 case ACCESS_STORE: | |
| 90 accesstype = "store to"; | |
| 91 break; | |
| 92 } | |
| 93 assert(accesstype != NULL); | |
| 94 char *memtype = NULL; | |
| 95 switch (shadow_val) { | |
|
Karl
2016/08/04 14:42:24
Similar here, replace with something like:
memtyp
tlively
2016/08/04 17:58:22
Done.
| |
| 96 case STACK_POISON_VAL: | |
| 97 memtype = "stack"; | |
| 98 break; | |
| 99 case HEAP_POISON_VAL: | |
| 100 memtype = "heap"; | |
| 101 break; | |
| 102 case GLOBAL_POISON_VAL: | |
| 103 memtype = "global"; | |
| 104 break; | |
| 105 } | |
| 106 assert(memtype != NULL); | |
| 107 fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, accesstype, | |
| 108 memtype, ptr); | |
| 76 abort(); | 109 abort(); |
| 77 } | 110 } |
| 78 | 111 |
| 79 // check only the first byte of each word unless strict | 112 // check only the first byte of each word unless strict |
| 80 static void __asan_check(char *ptr, int size) { | 113 static bool __asan_check(char *ptr, int size) { |
| 81 assert(size == 1 || size == 2 || size == 4 || size == 8); | 114 assert(size == 1 || size == 2 || size == 4 || size == 8); |
| 82 char *shadow_addr = (char *)MEM2SHADOW(ptr); | 115 char *shadow_addr = (char *)MEM2SHADOW(ptr); |
| 116 char shadow_val = *shadow_addr; | |
| 83 DUMP("check %d bytes at %p: %p + %d (%d)\n", size, ptr, shadow_addr, | 117 DUMP("check %d bytes at %p: %p + %d (%d)\n", size, ptr, shadow_addr, |
| 84 (uintptr_t)ptr % SHADOW_SCALE, *shadow_addr); | 118 (uintptr_t)ptr % SHADOW_SCALE, shadow_val); |
| 85 if (size == SHADOW_SCALE) { | 119 if (size == SHADOW_SCALE) { |
| 86 if (*shadow_addr != 0) | 120 return shadow_val == 0; |
| 87 __asan_error(ptr, size); | |
| 88 return; | |
| 89 } | 121 } |
| 90 if (*shadow_addr != 0 && (char)SHADOW_OFFSET(ptr) + size > *shadow_addr) | 122 return shadow_val == 0 || (char)SHADOW_OFFSET(ptr) + size <= shadow_val; |
| 91 __asan_error(ptr, size); | |
| 92 } | 123 } |
| 93 | 124 |
| 94 static void __asan_get_redzones(char *ptr, char **left, char **right) { | 125 static void __asan_get_redzones(char *ptr, char **left, char **right) { |
| 95 char *rz_left = ptr - RZ_SIZE; | 126 char *rz_left = ptr - RZ_SIZE; |
| 96 char *rz_right = *(char **)rz_left; | 127 char *rz_right = *(char **)rz_left; |
| 97 if (left != NULL) | 128 if (left != NULL) |
| 98 *left = rz_left; | 129 *left = rz_left; |
| 99 if (right != NULL) | 130 if (right != NULL) |
| 100 *right = rz_right; | 131 *right = rz_right; |
| 101 } | 132 } |
| 102 | 133 |
| 103 void __asan_check_load(char *ptr, int size) { | 134 void __asan_check_load(char *ptr, int size) { |
| 104 // aligned single word accesses may be widened single byte accesses, but for | 135 // aligned single word accesses may be widened single byte accesses, but for |
| 105 // all else use strict check | 136 // all else use strict check |
| 106 if (size == WORD_SIZE && (uintptr_t)ptr % WORD_SIZE == 0) | 137 int check_size = |
| 107 size = 1; | 138 (size == WORD_SIZE && (uintptr_t)ptr % WORD_SIZE == 0) ? 1 : size; |
| 108 __asan_check(ptr, size); | 139 if (!__asan_check(ptr, check_size)) |
| 140 __asan_error(ptr, size, ACCESS_LOAD); | |
| 109 } | 141 } |
| 110 | 142 |
| 111 void __asan_check_store(char *ptr, int size) { | 143 void __asan_check_store(char *ptr, int size) { |
| 112 // stores may never be partially out of bounds so use strict check | 144 // stores may never be partially out of bounds so use strict check |
| 113 bool strict = true; | 145 if (!__asan_check(ptr, size)) |
| 114 __asan_check(ptr, size); | 146 __asan_error(ptr, size, ACCESS_STORE); |
| 115 } | 147 } |
| 116 | 148 |
| 117 void __asan_init(int n_rzs, void **rzs, int *rz_sizes) { | 149 void __asan_init(int n_rzs, void **rzs, int *rz_sizes) { |
| 118 // ensure the redzones are large enough to hold metadata | 150 // ensure the redzones are large enough to hold metadata |
| 119 assert(RZ_SIZE >= sizeof(void *) && RZ_SIZE >= sizeof(size_t)); | 151 assert(RZ_SIZE >= sizeof(void *) && RZ_SIZE >= sizeof(size_t)); |
| 120 assert(shadow_offset == NULL); | 152 assert(shadow_offset == NULL); |
| 121 size_t length = (IS_32_BIT) ? SHADOW_LENGTH_32 : SHADOW_LENGTH_64; | 153 size_t length = (IS_32_BIT) ? SHADOW_LENGTH_32 : SHADOW_LENGTH_64; |
| 122 int prot = PROT_READ | PROT_WRITE; | 154 int prot = PROT_READ | PROT_WRITE; |
| 123 int flags = MAP_PRIVATE | MAP_ANONYMOUS; | 155 int flags = MAP_PRIVATE | MAP_ANONYMOUS; |
| 124 int fd = -1; | 156 int fd = -1; |
| 125 off_t offset = 0; | 157 off_t offset = 0; |
| 126 shadow_offset = mmap((void *)length, length, prot, flags, fd, offset); | 158 shadow_offset = mmap((void *)length, length, prot, flags, fd, offset); |
| 127 if (shadow_offset == NULL) | 159 if (shadow_offset == NULL) |
| 128 fprintf(stderr, "unable to allocate shadow memory\n"); | 160 fprintf(stderr, "unable to allocate shadow memory\n"); |
| 129 else | 161 else |
| 130 DUMP("set up shadow memory at %p\n", shadow_offset); | 162 DUMP("set up shadow memory at %p\n", shadow_offset); |
| 131 if (mprotect(MEM2SHADOW(shadow_offset), length >> SHADOW_SCALE_LOG2, | 163 if (mprotect(MEM2SHADOW(shadow_offset), length >> SHADOW_SCALE_LOG2, |
| 132 PROT_NONE)) | 164 PROT_NONE)) |
| 133 fprintf(stderr, "could not protect bad region\n"); | 165 fprintf(stderr, "could not protect bad region\n"); |
| 134 else | 166 else |
| 135 DUMP("protected bad region\n"); | 167 DUMP("protected bad region\n"); |
| 136 | 168 |
| 137 // poison global redzones | 169 // poison global redzones |
| 138 DUMP("poisioning %d global redzones\n", n_rzs); | 170 DUMP("poisioning %d global redzones\n", n_rzs); |
| 139 for (int i = 0; i < n_rzs; i++) { | 171 for (int i = 0; i < n_rzs; i++) { |
| 140 DUMP("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]); | 172 DUMP("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]); |
| 141 __asan_poison(rzs[i], rz_sizes[i]); | 173 __asan_poison(rzs[i], rz_sizes[i], GLOBAL_POISON_VAL); |
| 142 } | 174 } |
| 143 } | 175 } |
| 144 | 176 |
| 145 void *__asan_malloc(size_t size) { | 177 void *__asan_malloc(size_t size) { |
| 146 DUMP("malloc() called with size %d\n", size); | 178 DUMP("malloc() called with size %d\n", size); |
| 147 size_t padding = | 179 size_t padding = |
| 148 (IS_SHADOW_ALIGNED(size)) ? 0 : SHADOW_SCALE - SHADOW_OFFSET(size); | 180 (IS_SHADOW_ALIGNED(size)) ? 0 : SHADOW_SCALE - SHADOW_OFFSET(size); |
| 149 size_t rz_left_size = RZ_SIZE; | 181 size_t rz_left_size = RZ_SIZE; |
| 150 size_t rz_right_size = RZ_SIZE + padding; | 182 size_t rz_right_size = RZ_SIZE + padding; |
| 151 void *rz_left; | 183 void *rz_left; |
| 152 int err = posix_memalign(&rz_left, SHADOW_SCALE, | 184 int err = posix_memalign(&rz_left, SHADOW_SCALE, |
| 153 rz_left_size + size + rz_right_size); | 185 rz_left_size + size + rz_right_size); |
| 154 if (err != 0) { | 186 if (err != 0) { |
| 155 assert(err == ENOMEM); | 187 assert(err == ENOMEM); |
| 156 return NULL; | 188 return NULL; |
| 157 } | 189 } |
| 158 void *ret = rz_left + rz_left_size; | 190 void *ret = rz_left + rz_left_size; |
| 159 void *rz_right = ret + size; | 191 void *rz_right = ret + size; |
| 160 __asan_poison(rz_left, rz_left_size); | 192 __asan_poison(rz_left, rz_left_size, HEAP_POISON_VAL); |
| 161 __asan_poison(rz_right, rz_right_size); | 193 __asan_poison(rz_right, rz_right_size, HEAP_POISON_VAL); |
| 162 // record size and location data so we can find it again | 194 // record size and location data so we can find it again |
| 163 *(void **)rz_left = rz_right; | 195 *(void **)rz_left = rz_right; |
| 164 *(size_t *)rz_right = rz_right_size; | 196 *(size_t *)rz_right = rz_right_size; |
| 165 assert((uintptr_t)ret % 8 == 0); | 197 assert((uintptr_t)ret % 8 == 0); |
| 166 return ret; | 198 return ret; |
| 167 } | 199 } |
| 168 | 200 |
| 169 void *__asan_calloc(size_t nmemb, size_t size) { | 201 void *__asan_calloc(size_t nmemb, size_t size) { |
| 170 size_t alloc_size = nmemb * size; | 202 size_t alloc_size = nmemb * size; |
| 171 void *ret = __asan_malloc(alloc_size); | 203 void *ret = __asan_malloc(alloc_size); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 197 void __asan_free(char *ptr) { | 229 void __asan_free(char *ptr) { |
| 198 DUMP("free() called on %p\n", ptr); | 230 DUMP("free() called on %p\n", ptr); |
| 199 char *rz_left, *rz_right; | 231 char *rz_left, *rz_right; |
| 200 __asan_get_redzones(ptr, &rz_left, &rz_right); | 232 __asan_get_redzones(ptr, &rz_left, &rz_right); |
| 201 size_t rz_right_size = *(size_t *)rz_right; | 233 size_t rz_right_size = *(size_t *)rz_right; |
| 202 __asan_unpoison(rz_left, RZ_SIZE); | 234 __asan_unpoison(rz_left, RZ_SIZE); |
| 203 __asan_unpoison(rz_right, rz_right_size); | 235 __asan_unpoison(rz_right, rz_right_size); |
| 204 free(rz_left); | 236 free(rz_left); |
| 205 } | 237 } |
| 206 | 238 |
| 207 void __asan_poison(char *ptr, int size) { | 239 void __asan_poison(char *ptr, int size, char poison_val) { |
| 208 char *end = ptr + size; | 240 char *end = ptr + size; |
| 209 assert(IS_SHADOW_ALIGNED(end)); | 241 assert(IS_SHADOW_ALIGNED(end)); |
| 210 // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment | 242 // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment |
| 211 assert(size < 2 * RZ_SIZE); | 243 assert(size < 2 * RZ_SIZE); |
| 212 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), | 244 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
| 213 MEM2SHADOW(end)); | 245 MEM2SHADOW(end)); |
| 214 size_t offset = SHADOW_OFFSET(ptr); | 246 size_t offset = SHADOW_OFFSET(ptr); |
| 215 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? POISON_VAL : offset; | 247 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset; |
| 216 ptr += SHADOW_OFFSET(size); | 248 ptr += SHADOW_OFFSET(size); |
| 217 assert(IS_SHADOW_ALIGNED(ptr)); | 249 assert(IS_SHADOW_ALIGNED(ptr)); |
| 218 for (; ptr != end; ptr += SHADOW_SCALE) { | 250 int len = (end - ptr) >> SHADOW_SCALE_LOG2; |
| 219 *(char *)MEM2SHADOW(ptr) = POISON_VAL; | 251 memset(MEM2SHADOW(ptr), poison_val, len); |
| 220 } | |
| 221 } | 252 } |
| 222 | 253 |
| 223 void __asan_unpoison(char *ptr, int size) { | 254 void __asan_unpoison(char *ptr, int size) { |
| 224 char *end = ptr + size; | 255 char *end = ptr + size; |
| 225 assert(IS_SHADOW_ALIGNED(end)); | 256 assert(IS_SHADOW_ALIGNED(end)); |
| 226 assert(size < 2 * RZ_SIZE); | 257 assert(size < 2 * RZ_SIZE); |
| 227 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), | 258 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
| 228 MEM2SHADOW(end)); | 259 MEM2SHADOW(end)); |
| 229 *(char *)MEM2SHADOW(ptr) = 0; | 260 *(char *)MEM2SHADOW(ptr) = 0; |
| 230 ptr += SHADOW_OFFSET(size); | 261 ptr += SHADOW_OFFSET(size); |
| 231 assert(IS_SHADOW_ALIGNED(ptr)); | 262 assert(IS_SHADOW_ALIGNED(ptr)); |
| 232 for (; ptr != end; ptr += SHADOW_SCALE) { | 263 memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2); |
| 233 *(char *)MEM2SHADOW(ptr) = 0; | |
| 234 } | |
| 235 } | 264 } |
| OLD | NEW |