Index: runtime/szrt_asan.c |
diff --git a/runtime/szrt_asan.c b/runtime/szrt_asan.c |
index 9f62e28ef474015e8843a38cea631e0f364396ac..6fab295879818dfe1684f236223cbb78a04e2ee2 100644 |
--- a/runtime/szrt_asan.c |
+++ b/runtime/szrt_asan.c |
@@ -16,48 +16,133 @@ |
//===----------------------------------------------------------------------===// |
#include <assert.h> |
+#include <errno.h> |
+#include <limits.h> |
+#include <stdbool.h> |
#include <stddef.h> |
+#include <stdint.h> |
#include <stdio.h> |
#include <stdlib.h> |
+#include <sys/mman.h> |
-static __thread int behind_malloc = 0; |
+#define RZ_SIZE (32) |
+#define SHADOW_SCALE_LOG2 (3) |
+#define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2) |
+ |
+// Assuming 48 bit address space on 64 bit systems |
+#define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2)) |
+#define SHADOW_LENGTH_32 (1u << (32 - SHADOW_SCALE_LOG2)) |
+#define IS_32_BIT (sizeof(void *) == 4) |
+ |
+#define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) |
+#define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) |
+ |
+#define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) |
+#define SHADOW2MEM(p) \ |
+ ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) |
+ |
+#define POISON_VAL (-1) |
+ |
+static char *shadow_offset = NULL; |
+ |
+void __asan_init(void); |
+void __asan_check(char *, int); |
+void *__asan_malloc(size_t); |
+void __asan_free(char *); |
+void __asan_poison(char *, int); |
+void __asan_unpoison(char *, int); |
-// TODO(tlively): Define and implement this library |
void __asan_init(void) { |
- if (behind_malloc == 0) |
- printf("set up shadow memory here\n"); |
+ // ensure the redzones are large enough to hold metadata |
+ assert(RZ_SIZE >= sizeof(void *) && RZ_SIZE >= sizeof(size_t)); |
+ assert(shadow_offset == NULL); |
+ size_t length = (IS_32_BIT) ? SHADOW_LENGTH_32 : SHADOW_LENGTH_64; |
+ int prot = PROT_READ | PROT_WRITE; |
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS; |
+ int fd = -1; |
+ off_t offset = 0; |
+ shadow_offset = mmap((void *)length, length, prot, flags, fd, offset); |
+ if (shadow_offset == NULL) |
+ fprintf(stderr, "unable to allocate shadow memory\n"); |
+ else |
+ printf("set up shadow memory at %p\n", shadow_offset); |
+ if (mprotect(MEM2SHADOW(shadow_offset), length >> SHADOW_SCALE_LOG2, |
+ PROT_NONE)) |
+ fprintf(stderr, "could not protect bad region\n"); |
+ else |
+ printf("protected bad region\n"); |
} |
-void __asan_check(void *addr, int size) { |
- if (behind_malloc == 0) |
- printf("check %d bytes at %p\n", size, addr); |
+void __asan_check(char *ptr, int size) { |
+ printf("check %d bytes at %p\n", size, ptr); |
+ char *end = ptr + size; |
+ for (; ptr < end; ++ptr) { |
+ char shadow = *(char *)MEM2SHADOW(ptr); |
+ printf("checking %p with shadow %d\n", ptr, shadow); |
+ assert(shadow == 0 || (shadow > 0 && SHADOW_OFFSET(ptr) <= shadow)); |
+ } |
} |
void *__asan_malloc(size_t size) { |
- if (behind_malloc == 0) |
- printf("malloc() called with size %d\n", size); |
- ++behind_malloc; |
- void *ret = malloc(size); |
- --behind_malloc; |
- assert(behind_malloc >= 0); |
+ printf("malloc() called with size %d\n", size); |
+ size_t padding = |
+ (IS_SHADOW_ALIGNED(size)) ? 0 : SHADOW_SCALE - SHADOW_OFFSET(size); |
+ size_t rz_left_size = RZ_SIZE; |
+ size_t rz_right_size = RZ_SIZE + padding; |
+ void *rz_left; |
+ int err = posix_memalign(&rz_left, SHADOW_SCALE, |
+ rz_left_size + size + rz_right_size); |
+ if (err != 0) { |
+ assert(err == ENOMEM); |
+ return NULL; |
+ } |
+ 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); |
+ // record size and location data so we can find it again |
+ *(void **)rz_left = rz_right; |
+ *(size_t *)rz_right = rz_right_size; |
+ assert((uintptr_t)ret % 8 == 0); |
return ret; |
} |
-void __asan_free(void *ptr) { |
- if (behind_malloc == 0) |
- printf("free() called on %p\n", ptr); |
- ++behind_malloc; |
- free(ptr); |
- --behind_malloc; |
- assert(behind_malloc >= 0); |
+void __asan_free(char *ptr) { |
+ printf("free() called on %p\n", ptr); |
+ void *rz_left = ptr - RZ_SIZE; |
+ void *rz_right = *(void **)rz_left; |
+ 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); |
} |
-void __asan_alloca(void *ptr, int size) { |
- if (behind_malloc == 0) |
- printf("alloca of %d bytes at %p\n", size, ptr); |
+void __asan_poison(char *ptr, int size) { |
+ 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); |
+ printf("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; |
+ ptr += SHADOW_OFFSET(size); |
+ assert(IS_SHADOW_ALIGNED(ptr)); |
+ for (; ptr != end; ptr += SHADOW_SCALE) { |
+ *(char *)MEM2SHADOW(ptr) = POISON_VAL; |
+ } |
} |
-void __asan_unalloca(void *ptr, int size) { |
- if (behind_malloc == 0) |
- printf("unalloca of %d bytes as %p\n", size, ptr); |
+void __asan_unpoison(char *ptr, int size) { |
+ char *end = ptr + size; |
+ assert(IS_SHADOW_ALIGNED(end)); |
+ assert(size < 2 * RZ_SIZE); |
+ printf("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
+ MEM2SHADOW(end)); |
+ *(char *)MEM2SHADOW(ptr) = 0; |
+ ptr += SHADOW_OFFSET(size); |
+ assert(IS_SHADOW_ALIGNED(ptr)); |
+ for (; ptr != end; ptr += SHADOW_SCALE) { |
+ *(char *)MEM2SHADOW(ptr) = 0; |
+ } |
} |