diff options
| author | Kostya Serebryany <kcc@google.com> | 2011-12-28 22:58:01 +0000 |
|---|---|---|
| committer | Kostya Serebryany <kcc@google.com> | 2011-12-28 22:58:01 +0000 |
| commit | 6c4bd806fae3d64976fa8d4936fa91aa9d940111 (patch) | |
| tree | 5e3d3d3babae77cf356d288084cbbebe049dc392 | |
| parent | 12a14e270eaa174c12f6d3674eb8cb899a47f093 (diff) | |
| download | bcm5719-llvm-6c4bd806fae3d64976fa8d4936fa91aa9d940111.tar.gz bcm5719-llvm-6c4bd806fae3d64976fa8d4936fa91aa9d940111.zip | |
[asan] use custom libc-free getenv; a bit of refactoring around mmap calls
llvm-svn: 147326
| -rw-r--r-- | compiler-rt/lib/asan/asan_allocator.cc | 35 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.cc | 17 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_interceptors.h | 2 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_internal.h | 22 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_linux.cc | 47 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_mac.cc | 32 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_printf.cc | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/asan/asan_rtl.cc | 69 |
8 files changed, 174 insertions, 54 deletions
diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc index c3f61890783..aa0413c7ab7 100644 --- a/compiler-rt/lib/asan/asan_allocator.cc +++ b/compiler-rt/lib/asan/asan_allocator.cc @@ -60,32 +60,15 @@ static const size_t kMaxAllowedMallocSize = 3UL << 30; // 3G static const size_t kMaxAllowedMallocSize = 8UL << 30; // 8G #endif -static void OutOfMemoryMessage(const char *mem_type, size_t size) { - AsanThread *t = asanThreadRegistry().GetCurrent(); - CHECK(t); - Report("ERROR: AddressSanitizer failed to allocate " - "0x%lx (%lu) bytes (%s) in T%d\n", - size, size, mem_type, t->tid()); -} - static inline bool IsAligned(uintptr_t a, uintptr_t alignment) { return (a & (alignment - 1)) == 0; } -static inline bool IsPowerOfTwo(size_t x) { - return (x & (x - 1)) == 0; -} - static inline size_t Log2(size_t x) { CHECK(IsPowerOfTwo(x)); return __builtin_ctzl(x); } -static inline size_t RoundUpTo(size_t size, size_t boundary) { - CHECK(IsPowerOfTwo(boundary)); - return (size + boundary - 1) & ~(boundary - 1); -} - static inline size_t RoundUpToPowerOfTwo(size_t size) { CHECK(size); if (IsPowerOfTwo(size)) return size; @@ -132,14 +115,7 @@ static void PoisonHeapPartialRightRedzone(uintptr_t mem, size_t size) { static uint8_t *MmapNewPagesAndPoisonShadow(size_t size) { CHECK(IsAligned(size, kPageSize)); - uint8_t *res = (uint8_t*)asan_mmap(0, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); - if (res == (uint8_t*)-1) { - OutOfMemoryMessage(__FUNCTION__, size); - PRINT_CURRENT_STACK(); - ASAN_DIE; - } + uint8_t *res = (uint8_t*)AsanMmapSomewhereOrDie(size, __FUNCTION__); PoisonShadow((uintptr_t)res, size, kAsanHeapLeftRedzoneMagic); if (FLAG_debug) { Printf("ASAN_MMAP: [%p, %p)\n", res, res + size); @@ -929,8 +905,7 @@ void FakeStack::Cleanup() { if (mem) { PoisonShadow(mem, ClassMmapSize(i), 0); allocated_size_classes_[i] = 0; - int munmap_res = munmap((void*)mem, ClassMmapSize(i)); - CHECK(munmap_res == 0); + AsanUnmapOrDie((void*)mem, ClassMmapSize(i)); } } } @@ -941,10 +916,8 @@ size_t FakeStack::ClassMmapSize(size_t size_class) { void FakeStack::AllocateOneSizeClass(size_t size_class) { CHECK(ClassMmapSize(size_class) >= kPageSize); - uintptr_t new_mem = (uintptr_t)asan_mmap(0, ClassMmapSize(size_class), - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); - CHECK(new_mem != (uintptr_t)-1); + uintptr_t new_mem = (uintptr_t)AsanMmapSomewhereOrDie( + ClassMmapSize(size_class), __FUNCTION__); // Printf("T%d new_mem[%ld]: %p-%p mmap %ld\n", // asanThreadRegistry().GetCurrent()->tid(), // size_class, new_mem, new_mem + ClassMmapSize(size_class), diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 5cf92952f77..53ef91ae857 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -119,6 +119,23 @@ size_t internal_strnlen(const char *s, size_t maxlen) { return i; } +void* internal_memchr(const void* s, int c, size_t n) { + const char* t = (char*)s; + for (size_t i = 0; i < n; ++i, ++t) + if (*t == c) + return (void*)t; + return NULL; +} + +int internal_memcmp(const void* s1, const void* s2, size_t n) { + const char* t1 = (char*)s1; + const char* t2 = (char*)s2; + for (size_t i = 0; i < n; ++i, ++t1, ++t2) + if (*t1 != *t2) + return *t1 < *t2 ? -1 : 1; + return 0; +} + void InitializeAsanInterceptors() { #ifndef __APPLE__ INTERCEPT_FUNCTION(index); diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index 11fecc83444..07b94208197 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -123,6 +123,8 @@ extern strnlen_f real_strnlen; // __asan::internal_X() is the implementation of X() for use in RTL. size_t internal_strlen(const char *s); size_t internal_strnlen(const char *s, size_t maxlen); +void* internal_memchr(const void* s, int c, size_t n); +int internal_memcmp(const void* s1, const void* s2, size_t n); // Initializes pointers to str*/mem* functions. void InitializeAsanInterceptors(); diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h index 79a4f05e84e..041aa3f6c03 100644 --- a/compiler-rt/lib/asan/asan_internal.h +++ b/compiler-rt/lib/asan/asan_internal.h @@ -83,11 +83,20 @@ bool DescribeAddrIfGlobal(uintptr_t addr); // asan_malloc_linux.cc / asan_malloc_mac.cc void ReplaceSystemMalloc(); +void OutOfMemoryMessageAndDie(const char *mem_type, size_t size); + // asan_linux.cc / asan_mac.cc void *AsanDoesNotSupportStaticLinkage(); +int AsanOpenReadonly(const char* filename); void *asan_mmap(void *addr, size_t length, int prot, int flags, int fd, uint64_t offset); -ssize_t asan_write(int fd, const void *buf, size_t count); + +void *AsanMmapSomewhereOrDie(size_t size, const char *where); +void AsanUnmapOrDie(void *ptr, size_t size); + +ssize_t AsanRead(int fd, void *buf, size_t count); +ssize_t AsanWrite(int fd, const void *buf, size_t count); +int AsanClose(int fd); // asan_printf.cc void RawWrite(const char *buffer); @@ -109,7 +118,6 @@ void PoisonShadowPartialRightRedzone(uintptr_t addr, uintptr_t redzone_size, uint8_t value); - extern size_t FLAG_quarantine_size; extern int FLAG_demangle; extern bool FLAG_symbolize; @@ -185,6 +193,16 @@ const int kAsanInternalHeapMagic = 0xfe; static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3; static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E; +// --------------------------- Bit twiddling ------- {{{1 +inline bool IsPowerOfTwo(size_t x) { + return (x & (x - 1)) == 0; +} + +inline size_t RoundUpTo(size_t size, size_t boundary) { + CHECK(IsPowerOfTwo(boundary)); + return (size + boundary - 1) & ~(boundary - 1); +} + // -------------------------- LowLevelAllocator ----- {{{1 // A simple low-level memory allocator for internal use. class LowLevelAllocator { diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index ceb722bf9f8..45f94e9e0ab 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -17,6 +17,8 @@ #include <sys/mman.h> #include <sys/syscall.h> +#include <sys/types.h> +#include <fcntl.h> #include <unistd.h> extern char _DYNAMIC[]; @@ -28,22 +30,49 @@ void *AsanDoesNotSupportStaticLinkage() { return &_DYNAMIC; } -#ifdef ANDROID -#define SYS_mmap2 __NR_mmap2 -#define SYS_write __NR_write -#endif - void *asan_mmap(void *addr, size_t length, int prot, int flags, int fd, uint64_t offset) { # if __WORDSIZE == 64 - return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); + return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset); # else - return (void *)syscall(SYS_mmap2, addr, length, prot, flags, fd, offset); + return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset); # endif } -ssize_t asan_write(int fd, const void *buf, size_t count) { - return (ssize_t)syscall(SYS_write, fd, buf, count); +void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { + size = RoundUpTo(size, kPageSize); + void *res = asan_mmap(0, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (res == (void*)-1) { + OutOfMemoryMessageAndDie(mem_type, size); + } + return res; +} + +void AsanUnmapOrDie(void *addr, size_t size) { + if (!addr || !size) return; + int res = syscall(__NR_munmap, addr, size); + if (res != 0) { + Report("Failed to unmap\n"); + ASAN_DIE; + } +} + +ssize_t AsanWrite(int fd, const void *buf, size_t count) { + return (ssize_t)syscall(__NR_write, fd, buf, count); +} + +int AsanOpenReadonly(const char* filename) { + return open(filename, O_RDONLY); +} + +ssize_t AsanRead(int fd, void *buf, size_t count) { + return (ssize_t)syscall(__NR_read, fd, buf, count); +} + +int AsanClose(int fd) { + return close(fd); } } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index 43e8c00ba06..15d0987fa42 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -49,6 +49,38 @@ ssize_t asan_write(int fd, const void *buf, size_t count) { return write(fd, buf, count); } +void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { + size = RoundUpTo(size, kPageSize); + void *res = asan_mmap(0, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (res == (void*)-1) { + OutOfMemoryMessageAndDie(mem_type, size); + } + return res; +} + +void AsanUnmapOrDie(void *addr, size_t size) { + if (!addr || !size) return; + int res = munmap(addr, size); + if (res != 0) { + Report("Failed to unmap\n"); + ASAN_DIE; + } +} + +int AsanOpenReadonly(const char* filename) { + return open(filename, O_RDONLY); +} + +ssize_t AsanRead(int fd, void *buf, size_t count) { + return read(fd, buf, count); +} + +int AsanClose(int fd) { + return close(fd); +} + // Support for the following functions from libdispatch on Mac OS: // dispatch_async_f() // dispatch_async() diff --git a/compiler-rt/lib/asan/asan_printf.cc b/compiler-rt/lib/asan/asan_printf.cc index 4f111861f1b..a3d06ff67ad 100644 --- a/compiler-rt/lib/asan/asan_printf.cc +++ b/compiler-rt/lib/asan/asan_printf.cc @@ -24,8 +24,8 @@ namespace __asan { void RawWrite(const char *buffer) { static const char *kRawWriteError = "RawWrite can't output requested buffer!"; ssize_t length = (ssize_t)internal_strlen(buffer); - if (length != asan_write(2, buffer, length)) { - asan_write(2, kRawWriteError, internal_strlen(kRawWriteError)); + if (length != AsanWrite(2, buffer, length)) { + AsanWrite(2, kRawWriteError, internal_strlen(kRawWriteError)); ASAN_DIE; } } diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index 83528474c28..299f647e171 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -122,6 +122,56 @@ static void PrintBytes(const char *before, uintptr_t *a) { Printf("\n"); } +// Opens the file 'file_name" and reads up to 'max_len' bytes. +// The resulting buffer is mmaped and stored in '*buff'. +// Returns the number of read bytes or -1 if file can not be opened. +static ssize_t ReadFileToBuffer(const char *file_name, char **buff, + size_t max_len) { + const size_t kMinFileLen = kPageSize; + ssize_t read_len = -1; + *buff = 0; + size_t maped_size = 0; + // The files we usually open are not seekable, so try different buffer sizes. + for (size_t size = kMinFileLen; size <= max_len; size *= 2) { + int fd = AsanOpenReadonly(file_name); + if (fd < 0) return -1; + AsanUnmapOrDie(*buff, maped_size); + maped_size = size; + *buff = (char*)AsanMmapSomewhereOrDie(size, __FUNCTION__); + read_len = AsanRead(fd, *buff, size); + AsanClose(fd); + if (read_len < size) // We've read the whole file. + break; + } + return read_len; +} + +// Like getenv, but reads env directly from /proc and does not use libc. +// This function should be called first inside __asan_init. +static const char* GetEnvFromProcSelfEnviron(const char* name) { + static char *environ; + static ssize_t len; + static bool inited; + if (!inited) { + inited = true; + len = ReadFileToBuffer("/proc/self/environ", &environ, 1 << 20); + } + if (!environ || len <= 0) return NULL; + size_t namelen = internal_strlen(name); + const char *p = environ; + while (*p != '\0') { // will happen at the \0\0 that terminates the buffer + // proc file has the format NAME=value\0NAME=value\0NAME=value\0... + const char* endp = + (char*)internal_memchr(p, '\0', len - (p - environ)); + if (endp == NULL) // this entry isn't NUL terminated + return NULL; + else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. + return p + namelen + 1; // point after = + p = endp + 1; + } + return NULL; // Not found. +} + // ---------------------- Thread ------------------------- {{{1 static void *asan_thread_start(void *arg) { AsanThread *t= (AsanThread*)arg; @@ -130,10 +180,12 @@ static void *asan_thread_start(void *arg) { } // ---------------------- mmap -------------------- {{{1 -static void OutOfMemoryMessage(const char *mem_type, size_t size) { +void OutOfMemoryMessageAndDie(const char *mem_type, size_t size) { Report("ERROR: AddressSanitizer failed to allocate " "0x%lx (%ld) bytes of %s\n", size, size, mem_type); + PRINT_CURRENT_STACK(); + ShowStatsAndAbort(); } static char *mmap_pages(size_t start_page, size_t n_pages, const char *mem_type, @@ -144,8 +196,7 @@ static char *mmap_pages(size_t start_page, size_t n_pages, const char *mem_type, // Printf("%p => %p\n", (void*)start_page, res); char *ch = (char*)res; if (res == (void*)-1L && abort_on_failure) { - OutOfMemoryMessage(mem_type, n_pages * kPageSize); - ShowStatsAndAbort(); + OutOfMemoryMessageAndDie(mem_type, n_pages * kPageSize); } CHECK(res == (void*)start_page || res == (void*)-1L); return ch; @@ -175,10 +226,8 @@ void *LowLevelAllocator::Allocate(size_t size) { CHECK((size & (size - 1)) == 0 && "size must be a power of two"); if (allocated_end_ - allocated_current_ < size) { size_t size_to_allocate = Max(size, kPageSize); - allocated_current_ = (char*)asan_mmap(0, size_to_allocate, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); - CHECK((allocated_current_ != (char*)-1) && "Can't mmap"); + allocated_current_ = + (char*)AsanMmapSomewhereOrDie(size_to_allocate, __FUNCTION__); allocated_end_ = allocated_current_ + size_to_allocate; PoisonShadow((uintptr_t)allocated_current_, size_to_allocate, kAsanInternalHeapMagic); @@ -306,7 +355,7 @@ static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { return; } // Write the first message using the bullet-proof write. - if (13 != asan_write(2, "ASAN:SIGSEGV\n", 13)) ASAN_DIE; + if (13 != AsanWrite(2, "ASAN:SIGSEGV\n", 13)) ASAN_DIE; uintptr_t pc, sp, bp, ax; GetPcSpBpAx(context, &pc, &sp, &bp, &ax); Report("ERROR: AddressSanitizer crashed on unknown address %p" @@ -321,7 +370,7 @@ static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { static void ASAN_OnSIGILL(int, siginfo_t *siginfo, void *context) { // Write the first message using the bullet-proof write. - if (12 != asan_write(2, "ASAN:SIGILL\n", 12)) ASAN_DIE; + if (12 != AsanWrite(2, "ASAN:SIGILL\n", 12)) ASAN_DIE; uintptr_t pc, sp, bp, ax; GetPcSpBpAx(context, &pc, &sp, &bp, &ax); @@ -656,7 +705,7 @@ void __asan_init() { AsanDoesNotSupportStaticLinkage(); // flags - const char *options = getenv("ASAN_OPTIONS"); + const char *options = GetEnvFromProcSelfEnviron("ASAN_OPTIONS"); FLAG_malloc_context_size = IntFlagValue(options, "malloc_context_size=", kMallocContextSize); CHECK(FLAG_malloc_context_size <= kMallocContextSize); |

