[compiler-rt] c05095c - [Asan] Don't crash if metadata is not initialized

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 13:58:46 PDT 2020


Author: Vitaly Buka
Date: 2020-09-08T13:58:34-07:00
New Revision: c05095cd6865a95ee848cd95d11643969a81a241

URL: https://github.com/llvm/llvm-project/commit/c05095cd6865a95ee848cd95d11643969a81a241
DIFF: https://github.com/llvm/llvm-project/commit/c05095cd6865a95ee848cd95d11643969a81a241.diff

LOG: [Asan] Don't crash if metadata is not initialized

Fixes https://github.com/google/sanitizers/issues/1193.

AsanChunk can be uninitialized yet just after return from the secondary
allocator. If lsan starts scan just before metadata assignment it can
fail to find corresponding AsanChunk.

It should be safe to ignore this and let lsan to assume that
AsanChunk is in the beginning of the block. This block is from the
secondary allocator and created with mmap, so it should not contain
any pointers and will make lsan to miss some leaks.

Similar already happens for primary allocator. If it can't find real
AsanChunk it falls back and assume that block starts with AsanChunk.
Then if the block is already returned to allocator we have  garbage in
AsanChunk and may scan dead memory hiding some leaks.
I'll fix this in D87135.

Reviewed By: morehouse

Differential Revision: https://reviews.llvm.org/D86931

Added: 
    compiler-rt/test/asan/TestCases/lsan_crash.cpp

Modified: 
    compiler-rt/lib/asan/asan_allocator.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp
index 7334b7200fc4..1d8d5bcad1dc 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -730,6 +730,9 @@ struct Allocator {
   // -------------------------- Chunk lookup ----------------------
 
   // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+  // Returns nullptr if AsanChunk is not yet initialized just after
+  // get_allocator().Allocate(), or is being destroyed just before
+  // get_allocator().Deallocate().
   AsanChunk *GetAsanChunk(void *alloc_beg) {
     if (!alloc_beg)
       return nullptr;
@@ -1102,26 +1105,17 @@ void GetUserBeginDebug(uptr chunk) {
 
 uptr GetUserBegin(uptr chunk) {
   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
-  if (!m) {
-    Printf(
-        "ASAN is about to crash with a CHECK failure.\n"
-        "The ASAN developers are trying to chase down this bug,\n"
-        "so if you've encountered this bug please let us know.\n"
-        "See also: https://github.com/google/sanitizers/issues/1193\n"
-        "Internal ref b/149237057\n"
-        "chunk: %p caller %p __lsan_current_stage %s\n",
-        chunk, GET_CALLER_PC(), __lsan_current_stage);
-    GetUserBeginDebug(chunk);
-  }
-  CHECK(m);
-  return m->Beg();
+  return m ? m->Beg() : 0;
 }
 
 LsanMetadata::LsanMetadata(uptr chunk) {
-  metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
+  metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize)
+                    : nullptr;
 }
 
 bool LsanMetadata::allocated() const {
+  if (!metadata_)
+    return false;
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
   return atomic_load(&m->chunk_state, memory_order_relaxed) ==
          __asan::CHUNK_ALLOCATED;

diff  --git a/compiler-rt/test/asan/TestCases/lsan_crash.cpp b/compiler-rt/test/asan/TestCases/lsan_crash.cpp
new file mode 100644
index 000000000000..23c2569a0b73
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/lsan_crash.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx_asan -O2 %s -o %t && %run %t
+
+#include <atomic>
+#include <memory>
+#include <sanitizer/lsan_interface.h>
+#include <thread>
+#include <vector>
+
+std::atomic<bool> done;
+
+void foo() {
+  std::unique_ptr<char[]> mem;
+
+  while (!done)
+    mem.reset(new char[1000000]);
+}
+
+int main() {
+  std::vector<std::thread> threads;
+  for (int i = 0; i < 10; ++i)
+    threads.emplace_back(foo);
+
+  for (int i = 0; i < 100; ++i)
+    __lsan_do_recoverable_leak_check();
+
+  done = true;
+  for (auto &t : threads)
+    t.join();
+
+  return 0;
+}


        


More information about the llvm-commits mailing list