Index: runtime/szrt_asan.c |
diff --git a/runtime/szrt_asan.c b/runtime/szrt_asan.c |
index b1cf9d1dd524d305a7818d5e64544d0b668ced85..8600ed5ddf86253b0c6486b648635416fb87f544 100644 |
--- a/runtime/szrt_asan.c |
+++ b/runtime/szrt_asan.c |
@@ -44,7 +44,15 @@ |
#define SHADOW2MEM(p) \ |
((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) |
-#define POISON_VAL (-1) |
+#define STACK_POISON_VAL ((char)-1) |
+#define HEAP_POISON_VAL ((char)-2) |
+#define GLOBAL_POISON_VAL ((char)-3) |
+#define MEMTYPE_INDEX(x) (-1 - (x)) |
+static const char *memtype_names[] = {"stack", "heap", "global"}; |
+ |
+#define ACCESS_LOAD (0) |
+#define ACCESS_STORE (1) |
+static const char *access_names[] = {"load from", "store to"}; |
#if DEBUG |
#define DUMP(args...) \ |
@@ -57,8 +65,8 @@ |
static char *shadow_offset = NULL; |
-static void __asan_error(char *, int); |
-static void __asan_check(char *, int); |
+static bool __asan_check(char *, int); |
+static void __asan_error(char *, int, int); |
static void __asan_get_redzones(char *, char **, char **); |
void __asan_init(int, void **, int *); |
@@ -68,27 +76,35 @@ void *__asan_malloc(size_t); |
void *__asan_calloc(size_t, size_t); |
void *__asan_realloc(char *, size_t); |
void __asan_free(char *); |
-void __asan_poison(char *, int); |
+void __asan_poison(char *, int, char); |
void __asan_unpoison(char *, int); |
-static void __asan_error(char *ptr, int size) { |
- fprintf(stderr, "Illegal access of %d bytes at %p\n", size, ptr); |
+static void __asan_error(char *ptr, int size, int access) { |
+ char *shadow_addr = MEM2SHADOW(ptr); |
+ char shadow_val = *shadow_addr; |
+ if (shadow_val > 0) |
+ shadow_val = *(shadow_addr + 1); |
+ 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); |
+ 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); |
abort(); |
} |
// check only the first byte of each word unless strict |
-static void __asan_check(char *ptr, int size) { |
+static bool __asan_check(char *ptr, int size) { |
assert(size == 1 || size == 2 || size == 4 || size == 8); |
char *shadow_addr = (char *)MEM2SHADOW(ptr); |
+ char shadow_val = *shadow_addr; |
DUMP("check %d bytes at %p: %p + %d (%d)\n", size, ptr, shadow_addr, |
- (uintptr_t)ptr % SHADOW_SCALE, *shadow_addr); |
+ (uintptr_t)ptr % SHADOW_SCALE, shadow_val); |
if (size == SHADOW_SCALE) { |
- if (*shadow_addr != 0) |
- __asan_error(ptr, size); |
- return; |
+ return shadow_val == 0; |
} |
- if (*shadow_addr != 0 && (char)SHADOW_OFFSET(ptr) + size > *shadow_addr) |
- __asan_error(ptr, size); |
+ return shadow_val == 0 || (char)SHADOW_OFFSET(ptr) + size <= shadow_val; |
} |
static void __asan_get_redzones(char *ptr, char **left, char **right) { |
@@ -103,15 +119,16 @@ static void __asan_get_redzones(char *ptr, char **left, char **right) { |
void __asan_check_load(char *ptr, int size) { |
// aligned single word accesses may be widened single byte accesses, but for |
// all else use strict check |
- if (size == WORD_SIZE && (uintptr_t)ptr % WORD_SIZE == 0) |
- size = 1; |
- __asan_check(ptr, size); |
+ int check_size = |
+ (size == WORD_SIZE && (uintptr_t)ptr % WORD_SIZE == 0) ? 1 : size; |
+ if (!__asan_check(ptr, check_size)) |
+ __asan_error(ptr, size, ACCESS_LOAD); |
} |
void __asan_check_store(char *ptr, int size) { |
// stores may never be partially out of bounds so use strict check |
- bool strict = true; |
- __asan_check(ptr, size); |
+ if (!__asan_check(ptr, size)) |
+ __asan_error(ptr, size, ACCESS_STORE); |
} |
void __asan_init(int n_rzs, void **rzs, int *rz_sizes) { |
@@ -138,7 +155,7 @@ void __asan_init(int n_rzs, void **rzs, int *rz_sizes) { |
DUMP("poisioning %d global redzones\n", n_rzs); |
for (int i = 0; i < n_rzs; i++) { |
DUMP("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]); |
- __asan_poison(rzs[i], rz_sizes[i]); |
+ __asan_poison(rzs[i], rz_sizes[i], GLOBAL_POISON_VAL); |
} |
} |
@@ -157,8 +174,8 @@ void *__asan_malloc(size_t size) { |
} |
void *ret = rz_left + rz_left_size; |
void *rz_right = ret + size; |
- __asan_poison(rz_left, rz_left_size); |
- __asan_poison(rz_right, rz_right_size); |
+ __asan_poison(rz_left, rz_left_size, HEAP_POISON_VAL); |
+ __asan_poison(rz_right, rz_right_size, HEAP_POISON_VAL); |
// record size and location data so we can find it again |
*(void **)rz_left = rz_right; |
*(size_t *)rz_right = rz_right_size; |
@@ -204,7 +221,7 @@ void __asan_free(char *ptr) { |
free(rz_left); |
} |
-void __asan_poison(char *ptr, int size) { |
+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 |
@@ -212,12 +229,11 @@ void __asan_poison(char *ptr, int size) { |
DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
MEM2SHADOW(end)); |
size_t offset = SHADOW_OFFSET(ptr); |
- *(char *)MEM2SHADOW(ptr) = (offset == 0) ? POISON_VAL : offset; |
+ *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset; |
ptr += SHADOW_OFFSET(size); |
assert(IS_SHADOW_ALIGNED(ptr)); |
- for (; ptr != end; ptr += SHADOW_SCALE) { |
- *(char *)MEM2SHADOW(ptr) = POISON_VAL; |
- } |
+ int len = (end - ptr) >> SHADOW_SCALE_LOG2; |
+ memset(MEM2SHADOW(ptr), poison_val, len); |
} |
void __asan_unpoison(char *ptr, int size) { |
@@ -229,7 +245,5 @@ void __asan_unpoison(char *ptr, int size) { |
*(char *)MEM2SHADOW(ptr) = 0; |
ptr += SHADOW_OFFSET(size); |
assert(IS_SHADOW_ALIGNED(ptr)); |
- for (; ptr != end; ptr += SHADOW_SCALE) { |
- *(char *)MEM2SHADOW(ptr) = 0; |
- } |
+ memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2); |
} |