forked from OSchip/llvm-project
[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
This commit is contained in:
parent
5c463d107d
commit
c05095cd68
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue