Validate allocations against mappings
Bug 120032857 is seeing what appears to be allocations with incorrect end addresses, leading to a much later crash when it tries to map a zero page outside the valid virtual address space. Detect allocations that extend outside the highest or lowest memory mapping and crash immediately instead. Test: memunreachable_test Bug: 120032857 Change-Id: I9be670a025143e7078360a6bf7a83219279614d9
This commit is contained in:
parent
d780dcbaa5
commit
3ca1976fa7
4 changed files with 39 additions and 0 deletions
|
|
@ -35,6 +35,13 @@ bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
|
|||
end = begin + 1;
|
||||
}
|
||||
Range range{begin, end};
|
||||
if (valid_mappings_range_.end != 0 &&
|
||||
(begin < valid_mappings_range_.begin || end > valid_mappings_range_.end)) {
|
||||
MEM_LOG_ALWAYS_FATAL("allocation %p-%p is outside mapping range %p-%p",
|
||||
reinterpret_cast<void*>(begin), reinterpret_cast<void*>(end),
|
||||
reinterpret_cast<void*>(valid_mappings_range_.begin),
|
||||
reinterpret_cast<void*>(valid_mappings_range_.end));
|
||||
}
|
||||
auto inserted = allocations_.insert(std::pair<Range, AllocationInfo>(range, AllocationInfo{}));
|
||||
if (inserted.second) {
|
||||
valid_allocations_range_.begin = std::min(valid_allocations_range_.begin, begin);
|
||||
|
|
@ -87,6 +94,11 @@ void HeapWalker::RecurseRoot(const Range& root) {
|
|||
}
|
||||
}
|
||||
|
||||
void HeapWalker::Mapping(uintptr_t begin, uintptr_t end) {
|
||||
valid_mappings_range_.begin = std::min(valid_mappings_range_.begin, begin);
|
||||
valid_mappings_range_.end = std::max(valid_mappings_range_.end, end);
|
||||
}
|
||||
|
||||
void HeapWalker::Root(uintptr_t begin, uintptr_t end) {
|
||||
roots_.push_back(Range{begin, end});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ class HeapWalker {
|
|||
segv_page_count_(0) {
|
||||
valid_allocations_range_.end = 0;
|
||||
valid_allocations_range_.begin = ~valid_allocations_range_.end;
|
||||
valid_mappings_range_.end = 0;
|
||||
valid_mappings_range_.begin = ~valid_allocations_range_.end;
|
||||
|
||||
segv_handler_.install(
|
||||
SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
|
||||
|
|
@ -68,6 +70,7 @@ class HeapWalker {
|
|||
|
||||
~HeapWalker() {}
|
||||
bool Allocation(uintptr_t begin, uintptr_t end);
|
||||
void Mapping(uintptr_t begin, uintptr_t end);
|
||||
void Root(uintptr_t begin, uintptr_t end);
|
||||
void Root(const allocator::vector<uintptr_t>& vals);
|
||||
|
||||
|
|
@ -98,6 +101,7 @@ class HeapWalker {
|
|||
AllocationMap allocations_;
|
||||
size_t allocation_bytes_;
|
||||
Range valid_allocations_range_;
|
||||
Range valid_mappings_range_;
|
||||
|
||||
allocator::vector<Range> roots_;
|
||||
allocator::vector<uintptr_t> root_vals_;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,11 @@ bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& thr
|
|||
const allocator::vector<Mapping>& mappings,
|
||||
const allocator::vector<uintptr_t>& refs) {
|
||||
MEM_ALOGI("searching process %d for allocations", pid_);
|
||||
|
||||
for (auto it = mappings.begin(); it != mappings.end(); it++) {
|
||||
heap_walker_.Mapping(it->begin, it->end);
|
||||
}
|
||||
|
||||
allocator::vector<Mapping> heap_mappings{mappings};
|
||||
allocator::vector<Mapping> anon_mappings{mappings};
|
||||
allocator::vector<Mapping> globals_mappings{mappings};
|
||||
|
|
|
|||
|
|
@ -73,6 +73,24 @@ TEST_F(HeapWalkerTest, zero) {
|
|||
ASSERT_FALSE(heap_walker.Allocation(2, 3));
|
||||
}
|
||||
|
||||
TEST_F(HeapWalkerTest, mapping) {
|
||||
HeapWalker heap_walker(heap_);
|
||||
heap_walker.Mapping(2, 3);
|
||||
heap_walker.Mapping(4, 5);
|
||||
ASSERT_TRUE(heap_walker.Allocation(2, 3));
|
||||
ASSERT_TRUE(heap_walker.Allocation(4, 5));
|
||||
// space between mappings is not checked, but could be in the future
|
||||
ASSERT_TRUE(heap_walker.Allocation(3, 4));
|
||||
|
||||
// re-enable malloc, ASSERT_DEATH may allocate
|
||||
disable_malloc_.Enable();
|
||||
ASSERT_DEATH({ heap_walker.Allocation(1, 2); }, "0x1-0x2.*outside.*0x2-0x5");
|
||||
ASSERT_DEATH({ heap_walker.Allocation(1, 3); }, "0x1-0x3.*outside.*0x2-0x5");
|
||||
ASSERT_DEATH({ heap_walker.Allocation(4, 6); }, "0x4-0x6.*outside.*0x2-0x5");
|
||||
ASSERT_DEATH({ heap_walker.Allocation(5, 6); }, "0x5-0x6.*outside.*0x2-0x5");
|
||||
ASSERT_DEATH({ heap_walker.Allocation(1, 6); }, "0x1-0x6.*outside.*0x2-0x5");
|
||||
}
|
||||
|
||||
#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(buffer)
|
||||
#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(buffer) + sizeof(buffer))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue