summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipe Cabecinhas <me@filcab.net>2016-04-29 20:37:34 +0000
committerFilipe Cabecinhas <me@filcab.net>2016-04-29 20:37:34 +0000
commit04d61050ea0c064520e0952497fbc5948d908662 (patch)
tree1f1ff3f4a6ca360aa02e61cadfc5930b69e5f338
parent9debb987219720b1ff880a830dbfb158c4b864bf (diff)
downloadbcm5719-llvm-04d61050ea0c064520e0952497fbc5948d908662.tar.gz
bcm5719-llvm-04d61050ea0c064520e0952497fbc5948d908662.zip
[asan] Assert in __sanitizer_ptr_{sub,cmp} if one of the pointers was freed.
Summary: This (partially) implements the check mentioned at http://kristerw.blogspot.co.uk/2016/04/dangling-pointers-and-undefined-behavior.html (via John Regehr) Quoting: "That the behavior is undefined follows from C11 6.2.4 "Storage durations of objects" The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime. and 7.22.3 "Memory management functions" that says that free ends the lifetime of objects The lifetime of an allocated object extends from the allocation until the deallocation. " We can probably implement this for stack variables too, but I think this is a good start to see if there's interest in this check. We can also hide this behind a flag, too. Reviewers: samsonov, kcc, rsmith, regehr Subscribers: kubabrecka, llvm-commits Differential Revision: http://reviews.llvm.org/D19691 llvm-svn: 268097
-rw-r--r--compiler-rt/lib/asan/asan_allocator.cc3
-rw-r--r--compiler-rt/lib/asan/asan_allocator.h11
-rw-r--r--compiler-rt/lib/asan/asan_report.cc8
-rw-r--r--compiler-rt/test/asan/TestCases/invalid-pointer-pairs.cc37
4 files changed, 50 insertions, 9 deletions
diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc
index 29a5ba6b012..41b1689d91c 100644
--- a/compiler-rt/lib/asan/asan_allocator.cc
+++ b/compiler-rt/lib/asan/asan_allocator.cc
@@ -665,6 +665,9 @@ static AsanAllocator &get_allocator() {
bool AsanChunkView::IsValid() {
return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
}
+bool AsanChunkView::IsAllocated() {
+ return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED;
+}
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h
index 5ddaeb32598..9807d1bd51c 100644
--- a/compiler-rt/lib/asan/asan_allocator.h
+++ b/compiler-rt/lib/asan/asan_allocator.h
@@ -49,11 +49,12 @@ void GetAllocatorOptions(AllocatorOptions *options);
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
- bool IsValid(); // Checks if AsanChunkView points to a valid allocated
- // or quarantined chunk.
- uptr Beg(); // First byte of user memory.
- uptr End(); // Last byte of user memory.
- uptr UsedSize(); // Size requested by the user.
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ bool IsAllocated(); // Checks if the memory is currently allocated.
+ uptr Beg(); // First byte of user memory.
+ uptr End(); // Last byte of user memory.
+ uptr UsedSize(); // Size requested by the user.
uptr AllocTid();
uptr FreeTid();
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc
index 3eafe39d992..568d06bb1e5 100644
--- a/compiler-rt/lib/asan/asan_report.cc
+++ b/compiler-rt/lib/asan/asan_report.cc
@@ -1012,10 +1012,10 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
uptr a2 = reinterpret_cast<uptr>(p2);
AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
- bool valid1 = chunk1.IsValid();
- bool valid2 = chunk2.IsValid();
- if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
- GET_CALLER_PC_BP_SP; \
+ bool valid1 = chunk1.IsAllocated();
+ bool valid2 = chunk2.IsAllocated();
+ if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
+ GET_CALLER_PC_BP_SP;
return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
}
}
diff --git a/compiler-rt/test/asan/TestCases/invalid-pointer-pairs.cc b/compiler-rt/test/asan/TestCases/invalid-pointer-pairs.cc
new file mode 100644
index 00000000000..874107cdff7
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/invalid-pointer-pairs.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair
+
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 %run %t k 2>&1 | FileCheck %s -check-prefix=OK -allow-empty
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t g 2>&1 | FileCheck %s -check-prefix=CMP -check-prefix=ALL-ERRORS
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t s 2>&1 | FileCheck %s -check-prefix=SUB -check-prefix=ALL-ERRORS
+// RUN: %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t f 2>&1 | FileCheck %s -check-prefix=FREE -check-prefix=ALL-ERRORS
+
+#include <assert.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ // ALL-ERRORS: ERROR: AddressSanitizer: invalid-pointer-pair
+ // [[PTR1:0x[0-9a-f]+]] [[PTR2:0x[0-9a-f]+]]
+ assert(argc >= 2);
+ char *p = (char *)malloc(42);
+ char *q = (char *)malloc(42);
+ switch (argv[1][0]) {
+ case 'g':
+ // CMP: #0 {{.*}} in main {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]]:14
+ return p > q;
+ case 's':
+ // SUB: #0 {{.*}} in main {{.*}}invalid-pointer-pairs.cc:[[@LINE+1]]:14
+ return p - q;
+ case 'k': {
+ // OK-NOT: ERROR
+ char *p2 = p + 20;
+ return p > p2;
+ }
+ case 'f': {
+ char *p3 = p + 20;
+ free(p);
+ // FREE: #0 {{.*}} in main {{.*}}invalid-pointer-pairs.cc:[[@LINE+2]]:14
+ // FREE: freed by thread
+ return p < p3;
+ }
+ }
+}
OpenPOWER on IntegriCloud