Skip to content

Commit a102bf6

Browse files
vitalybukajrtc27
authored andcommitted
[Asan] Don't crash if metadata is not initialized
Fixes google/sanitizers#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
1 parent a33a091 commit a102bf6

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

lib/asan/asan_allocator.cpp

+8-14
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,9 @@ struct Allocator {
730730
// -------------------------- Chunk lookup ----------------------
731731

732732
// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
733+
// Returns nullptr if AsanChunk is not yet initialized just after
734+
// get_allocator().Allocate(), or is being destroyed just before
735+
// get_allocator().Deallocate().
733736
AsanChunk *GetAsanChunk(void *alloc_beg) {
734737
if (!alloc_beg)
735738
return nullptr;
@@ -1102,26 +1105,17 @@ void GetUserBeginDebug(uptr chunk) {
11021105

11031106
uptr GetUserBegin(uptr chunk) {
11041107
__asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
1105-
if (!m) {
1106-
Printf(
1107-
"ASAN is about to crash with a CHECK failure.\n"
1108-
"The ASAN developers are trying to chase down this bug,\n"
1109-
"so if you've encountered this bug please let us know.\n"
1110-
"See also: https://github.com/google/sanitizers/issues/1193\n"
1111-
"Internal ref b/149237057\n"
1112-
"chunk: %p caller %p __lsan_current_stage %s\n",
1113-
chunk, GET_CALLER_PC(), __lsan_current_stage);
1114-
GetUserBeginDebug(chunk);
1115-
}
1116-
CHECK(m);
1117-
return m->Beg();
1108+
return m ? m->Beg() : 0;
11181109
}
11191110

11201111
LsanMetadata::LsanMetadata(uptr chunk) {
1121-
metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
1112+
metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize)
1113+
: nullptr;
11221114
}
11231115

11241116
bool LsanMetadata::allocated() const {
1117+
if (!metadata_)
1118+
return false;
11251119
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
11261120
return atomic_load(&m->chunk_state, memory_order_relaxed) ==
11271121
__asan::CHUNK_ALLOCATED;

test/asan/TestCases/lsan_crash.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %clangxx_asan -O2 %s -o %t && %run %t
2+
3+
#include <atomic>
4+
#include <memory>
5+
#include <sanitizer/lsan_interface.h>
6+
#include <thread>
7+
#include <vector>
8+
9+
std::atomic<bool> done;
10+
11+
void foo() {
12+
std::unique_ptr<char[]> mem;
13+
14+
while (!done)
15+
mem.reset(new char[1000000]);
16+
}
17+
18+
int main() {
19+
std::vector<std::thread> threads;
20+
for (int i = 0; i < 10; ++i)
21+
threads.emplace_back(foo);
22+
23+
for (int i = 0; i < 100; ++i)
24+
__lsan_do_recoverable_leak_check();
25+
26+
done = true;
27+
for (auto &t : threads)
28+
t.join();
29+
30+
return 0;
31+
}

0 commit comments

Comments
 (0)