Chromium Code Reviews| Index: runtime/szrt_asan.c |
| diff --git a/runtime/szrt_asan.c b/runtime/szrt_asan.c |
| index 8600ed5ddf86253b0c6486b648635416fb87f544..1155ba05b2d3353ea711622fef40b799802240eb 100644 |
| --- a/runtime/szrt_asan.c |
| +++ b/runtime/szrt_asan.c |
| @@ -18,6 +18,7 @@ |
| #include <assert.h> |
| #include <errno.h> |
| #include <limits.h> |
| +#include <sched.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| @@ -26,10 +27,30 @@ |
| #include <string.h> |
| #include <sys/mman.h> |
| +#if _POSIX_THREADS |
| + |
| +#include <pthread.h> |
| +typedef pthread_mutex_t mutex_t; |
| +#define MUTEX_INITIALIZER (PTHREAD_MUTEX_INITIALIZER) |
| +#define MUTEX_LOCK(mutex) (pthread_mutex_lock(&(mutex))) |
| +#define MUTEX_UNLOCK(mutex) (pthread_mutex_unlock(&(mutex))) |
| + |
| +#else // !_POSIX_THREADS |
| + |
| +typedef uint32_t mutex_t; |
| +#define MUTEX_INITIALIZER (0) |
| +#define MUTEX_LOCK(mutex) \ |
| + while (__sync_swap((mutex), 1) != 0) { \ |
| + sched_yield(); \ |
| + } |
| +#define MUTEX_UNLOCK(mutex) (__sync_swap((mutex), 0)) |
| + |
| +#endif // _POSIX_THREADS |
| + |
| #define RZ_SIZE (32) |
| #define SHADOW_SCALE_LOG2 (3) |
| #define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2) |
| -#define DEBUG (0) |
| +#define DEBUG (1) |
| // Assuming 48 bit address space on 64 bit systems |
| #define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2)) |
| @@ -44,11 +65,14 @@ |
| #define SHADOW2MEM(p) \ |
| ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) |
| +#define QUARANTINE_MAX_SIZE ((size_t)1 << 28) // 256 MB |
| + |
| #define STACK_POISON_VAL ((char)-1) |
| #define HEAP_POISON_VAL ((char)-2) |
| #define GLOBAL_POISON_VAL ((char)-3) |
| +#define FREED_POISON_VAL ((char)-4) |
| #define MEMTYPE_INDEX(x) (-1 - (x)) |
| -static const char *memtype_names[] = {"stack", "heap", "global"}; |
| +static const char *memtype_names[] = {"stack", "heap", "global", "freed"}; |
| #define ACCESS_LOAD (0) |
| #define ACCESS_STORE (1) |
| @@ -79,6 +103,16 @@ void __asan_free(char *); |
| void __asan_poison(char *, int, char); |
| void __asan_unpoison(char *, int); |
| +struct quarantine_entry { |
| + struct quarantine_entry *next; |
| + size_t size; |
| +}; |
| + |
| +mutex_t quarantine_lock = MUTEX_INITIALIZER; |
| +uint64_t quarantine_size = 0; |
| +struct quarantine_entry *quarantine_head = NULL; |
| +struct quarantine_entry *quarantine_tail = NULL; |
| + |
| static void __asan_error(char *ptr, int size, int access) { |
| char *shadow_addr = MEM2SHADOW(ptr); |
| char shadow_val = *shadow_addr; |
| @@ -87,7 +121,7 @@ static void __asan_error(char *ptr, int size, int access) { |
| assert(access == ACCESS_LOAD || access == ACCESS_STORE); |
| const char *access_name = access_names[access]; |
| assert(shadow_val == STACK_POISON_VAL || shadow_val == HEAP_POISON_VAL || |
| - shadow_val == GLOBAL_POISON_VAL); |
| + shadow_val == GLOBAL_POISON_VAL || shadow_val == FREED_POISON_VAL); |
| const char *memtype = memtype_names[MEMTYPE_INDEX(shadow_val)]; |
| fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, access_name, |
| memtype, ptr); |
| @@ -213,19 +247,48 @@ void *__asan_realloc(char *ptr, size_t size) { |
| void __asan_free(char *ptr) { |
| DUMP("free() called on %p\n", ptr); |
| + if (ptr == NULL) |
| + return; |
| char *rz_left, *rz_right; |
| __asan_get_redzones(ptr, &rz_left, &rz_right); |
| size_t rz_right_size = *(size_t *)rz_right; |
| - __asan_unpoison(rz_left, RZ_SIZE); |
| - __asan_unpoison(rz_right, rz_right_size); |
| - free(rz_left); |
| + size_t total_size = rz_right_size + (rz_right - rz_left); |
|
Karl
2016/08/10 16:15:46
Can't this code also be used to check for a double
tlively
2016/08/10 17:17:57
Done.
|
| + __asan_poison(rz_left, total_size, FREED_POISON_VAL); |
| + |
| + // place allocation in quarantine |
| + struct quarantine_entry *entry = (struct quarantine_entry *)rz_left; |
| + assert(entry != NULL); |
| + entry->next = NULL; |
| + entry->size = total_size; |
| + |
| + DUMP("Placing %d bytes at %p in quarantine\n", entry->size, entry); |
| + MUTEX_LOCK(&quarantine_lock); |
| + if (quarantine_tail != NULL) |
| + quarantine_tail->next = entry; |
| + quarantine_tail = entry; |
| + if (quarantine_head == NULL) |
| + quarantine_head = entry; |
| + quarantine_size += total_size; |
| + DUMP("Quarantine size is %llu\n", quarantine_size); |
| + DUMP("Quarantine max size is %zu\n", QUARANTINE_MAX_SIZE); |
| + |
| + // free old objects as necessary |
| + while (quarantine_size > QUARANTINE_MAX_SIZE) { |
| + struct quarantine_entry *freed = quarantine_head; |
| + assert(freed != NULL); |
| + __asan_unpoison((char *)freed, freed->size); |
| + quarantine_size -= freed->size; |
| + quarantine_head = freed->next; |
| + DUMP("Releasing %d bytes at %p from quarantine\n", freed->size, freed); |
| + DUMP("Quarantine size is %llu\n", quarantine_size); |
| + free(freed); |
| + } |
| + MUTEX_UNLOCK(&quarantine_lock); |
| } |
| void __asan_poison(char *ptr, int size, char poison_val) { |
| char *end = ptr + size; |
| assert(IS_SHADOW_ALIGNED(end)); |
| - // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment |
| - assert(size < 2 * RZ_SIZE); |
| DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
| MEM2SHADOW(end)); |
| size_t offset = SHADOW_OFFSET(ptr); |
| @@ -239,7 +302,6 @@ void __asan_poison(char *ptr, int size, char poison_val) { |
| void __asan_unpoison(char *ptr, int size) { |
| char *end = ptr + size; |
| assert(IS_SHADOW_ALIGNED(end)); |
| - assert(size < 2 * RZ_SIZE); |
| DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
| MEM2SHADOW(end)); |
| *(char *)MEM2SHADOW(ptr) = 0; |