summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-09-13 18:38:40 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-09-13 18:38:40 +0000
commitb48348fec5776f2edb11768dac84effcd163c528 (patch)
treea8e7e70bee86695be8f2f8f38e634fde303efa10
parentffa0241a03f917405634a744793a48877dfc22de (diff)
downloadbcm5719-llvm-b48348fec5776f2edb11768dac84effcd163c528.tar.gz
bcm5719-llvm-b48348fec5776f2edb11768dac84effcd163c528.zip
[asan] Re-poison all redzones on activation.
When running with start_deactivated=1 in ASAN_OPTIONS, heap redzones are not poisoned until the first instrumented module is loaded. This can cause false negatives even on memory allocated after activation, because redzones are normally poisoned only once when a new allocator region is mapped. This change attempts to fix it by iterating over all existing allocator chunks and poisoning their redzones. llvm-svn: 281364
-rw-r--r--compiler-rt/lib/asan/asan_allocator.cc34
-rw-r--r--compiler-rt/test/asan/TestCases/Posix/start-deactivated.cc41
2 files changed, 63 insertions, 12 deletions
diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc
index aa08969e1e1..72590602038 100644
--- a/compiler-rt/lib/asan/asan_allocator.cc
+++ b/compiler-rt/lib/asan/asan_allocator.cc
@@ -266,9 +266,43 @@ struct Allocator {
SharedInitCode(options);
}
+ void RePoisonChunk(uptr chunk) {
+ // This could a user-facing chunk (with redzones), or some internal
+ // housekeeping chunk, like TransferBatch. Start by assuming the former.
+ AsanChunk *ac = GetAsanChunk((void *)chunk);
+ uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac);
+ uptr beg = ac->Beg();
+ uptr end = ac->Beg() + ac->UsedSize(true);
+ uptr chunk_end = chunk + allocated_size;
+ if (chunk < beg && beg < end && end <= chunk_end) {
+ // Looks like a valid AsanChunk. Or maybe not. Be conservative and only
+ // poison the redzones.
+ PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic);
+ uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY);
+ FastPoisonShadowPartialRightRedzone(
+ end_aligned_down, end - end_aligned_down,
+ chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic);
+ } else {
+ // This can not be an AsanChunk. Poison everything. It may be reused as
+ // AsanChunk later.
+ PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
+ }
+ }
+
void ReInitialize(const AllocatorOptions &options) {
allocator.SetMayReturnNull(options.may_return_null);
SharedInitCode(options);
+
+ // Poison all existing allocation's redzones.
+ if (CanPoisonMemory()) {
+ allocator.ForceLock();
+ allocator.ForEachChunk(
+ [](uptr chunk, void *alloc) {
+ ((Allocator *)alloc)->RePoisonChunk(chunk);
+ },
+ this);
+ allocator.ForceUnlock();
+ }
}
void GetOptions(AllocatorOptions *options) const {
diff --git a/compiler-rt/test/asan/TestCases/Posix/start-deactivated.cc b/compiler-rt/test/asan/TestCases/Posix/start-deactivated.cc
index 187ee5e549e..9691404ebce 100644
--- a/compiler-rt/test/asan/TestCases/Posix/start-deactivated.cc
+++ b/compiler-rt/test/asan/TestCases/Posix/start-deactivated.cc
@@ -2,8 +2,8 @@
// Main executable is uninstrumented, but linked to ASan runtime. The shared
// library is instrumented. Memory errors before dlopen are not detected.
-// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx -O0 %s -c -o %t.o
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -std=c++11 -fPIC -shared -o %t-so.so
+// RUN: %clangxx -O0 %s -std=c++11 -c -o %t.o
// RUN: %clangxx_asan -O0 %t.o %libdl -o %t
// RUN: %env_asan_opts=start_deactivated=1,allocator_may_return_null=0 \
// RUN: ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s
@@ -32,18 +32,25 @@
#include "sanitizer/asan_interface.h"
-void test_malloc_shadow() {
- char *p = (char *)malloc(100);
- char *q = (char *)__asan_region_is_poisoned(p + 95, 8);
- fprintf(stderr, "=%zd=\n", q ? q - (p + 95) : -1);
- free(p);
+constexpr unsigned nPtrs = 200;
+char *ptrs[nPtrs];
+
+void test_malloc_shadow(char *p, size_t sz, bool expect_redzones) {
+ assert((char *)__asan_region_is_poisoned(p - 1, sz + 1) ==
+ (expect_redzones ? p - 1 : nullptr));
+ assert((char *)__asan_region_is_poisoned(p, sz) == nullptr);
+ assert((char *)__asan_region_is_poisoned(p, sz + 1) ==
+ (expect_redzones ? p + sz : nullptr));
}
typedef void (*Fn)();
int main(int argc, char *argv[]) {
- test_malloc_shadow();
- // CHECK: =-1=
+ // Before activation: no redzones.
+ for (size_t sz = 1; sz < nPtrs; ++sz) {
+ ptrs[sz] = (char *)malloc(sz);
+ test_malloc_shadow(ptrs[sz], sz, false);
+ }
std::string path = std::string(argv[0]) + "-so.so";
void *dso = dlopen(path.c_str(), RTLD_NOW);
@@ -52,9 +59,6 @@ int main(int argc, char *argv[]) {
return 1;
}
- test_malloc_shadow();
- // CHECK: =5=
-
// After this line ASan is activated and starts detecting errors.
void *fn = dlsym(dso, "do_another_bad_thing");
if (!fn) {
@@ -62,6 +66,19 @@ int main(int argc, char *argv[]) {
return 1;
}
+ // After activation: redzones.
+ {
+ char *p = (char *)malloc(100);
+ test_malloc_shadow(p, 100, true);
+ free(p);
+ }
+
+ // Pre-existing allocations got redzones, too.
+ for (size_t sz = 1; sz < nPtrs; ++sz) {
+ test_malloc_shadow(ptrs[sz], sz, true);
+ free(ptrs[sz]);
+ }
+
// Test that ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 has effect.
void *p = malloc((unsigned long)-2);
assert(!p);
OpenPOWER on IntegriCloud