forked from OSchip/llvm-project
[hwasan] implement detection of double-free (invalid-free)
llvm-svn: 340591
This commit is contained in:
parent
0b87d05679
commit
c5f98d2ab2
|
@ -24,6 +24,7 @@
|
|||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_poisoning.h"
|
||||
#include "hwasan_report.h"
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
|
@ -173,11 +174,21 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
|
|||
return user_ptr;
|
||||
}
|
||||
|
||||
static bool PointerAndMemoryTagsMatch(void *user_ptr) {
|
||||
CHECK(user_ptr);
|
||||
tag_t ptr_tag = GetTagFromPointer(reinterpret_cast<uptr>(user_ptr));
|
||||
tag_t mem_tag = *reinterpret_cast<tag_t *>(
|
||||
MEM_TO_SHADOW(GetAddressFromPointer(user_ptr)));
|
||||
return ptr_tag == mem_tag;
|
||||
}
|
||||
|
||||
void HwasanDeallocate(StackTrace *stack, void *user_ptr) {
|
||||
CHECK(user_ptr);
|
||||
HWASAN_FREE_HOOK(user_ptr);
|
||||
|
||||
void *p = GetAddressFromPointer(user_ptr);
|
||||
if (!PointerAndMemoryTagsMatch(user_ptr))
|
||||
ReportInvalidFree(stack, reinterpret_cast<uptr>(user_ptr));
|
||||
Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
|
||||
uptr size = meta->requested_size;
|
||||
meta->state = CHUNK_FREE;
|
||||
|
@ -226,7 +237,7 @@ void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size,
|
|||
t ? t->GenerateRandomTag() : kFallbackAllocTag);
|
||||
}
|
||||
if (new_size > old_size) {
|
||||
tag_t tag = GetTagFromPointer((uptr)user_old_p);
|
||||
tag_t tag = GetTagFromPointer(reinterpret_cast<uptr>(user_old_p));
|
||||
TagMemoryAligned((uptr)old_p + old_size, new_size - old_size, tag);
|
||||
}
|
||||
return user_old_p;
|
||||
|
|
|
@ -109,30 +109,7 @@ void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
|
|||
// DescribeMemoryRange(start, size);
|
||||
}
|
||||
|
||||
void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
|
||||
bool is_store) {
|
||||
ScopedErrorReportLock l;
|
||||
|
||||
Decorator d;
|
||||
Printf("%s", d.Error());
|
||||
uptr address = GetAddressFromPointer(addr);
|
||||
// TODO: when possible, try to print heap-use-after-free, etc.
|
||||
const char *bug_type = "tag-mismatch";
|
||||
uptr pc = stack->size ? stack->trace[0] : 0;
|
||||
Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, address, pc);
|
||||
|
||||
tag_t ptr_tag = GetTagFromPointer(addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MEM_TO_SHADOW(address));
|
||||
tag_t mem_tag = *tag_ptr;
|
||||
Printf("%s", d.Access());
|
||||
Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem)\n",
|
||||
is_store ? "WRITE" : "READ", access_size, address, ptr_tag, mem_tag);
|
||||
Printf("%s", d.Default());
|
||||
|
||||
stack->Print();
|
||||
|
||||
PrintAddressDescription(address, access_size);
|
||||
|
||||
static void PrintTagsAroundAddr(tag_t *tag_ptr) {
|
||||
Printf(
|
||||
"Memory tags around the buggy address (one tag corresponds to %zd "
|
||||
"bytes):\n", kShadowAlignment);
|
||||
|
@ -152,6 +129,60 @@ void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
|
|||
}
|
||||
Printf("%s\n", row == center_row_beg ? "<=" : " ");
|
||||
}
|
||||
}
|
||||
|
||||
void ReportInvalidFree(StackTrace *stack, uptr addr) {
|
||||
ScopedErrorReportLock l;
|
||||
uptr address = GetAddressFromPointer(addr);
|
||||
tag_t ptr_tag = GetTagFromPointer(addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MEM_TO_SHADOW(address));
|
||||
tag_t mem_tag = *tag_ptr;
|
||||
Decorator d;
|
||||
Printf("%s", d.Error());
|
||||
uptr pc = stack->size ? stack->trace[0] : 0;
|
||||
const char *bug_type = "invalid-free";
|
||||
Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
|
||||
address, pc);
|
||||
Printf("%s", d.Access());
|
||||
Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag);
|
||||
Printf("%s", d.Default());
|
||||
|
||||
stack->Print();
|
||||
|
||||
PrintAddressDescription(address, 0);
|
||||
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
||||
ReportErrorSummary(bug_type, stack);
|
||||
Die();
|
||||
}
|
||||
|
||||
void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
|
||||
bool is_store) {
|
||||
ScopedErrorReportLock l;
|
||||
|
||||
Decorator d;
|
||||
Printf("%s", d.Error());
|
||||
uptr address = GetAddressFromPointer(addr);
|
||||
// TODO: when possible, try to print heap-use-after-free, etc.
|
||||
const char *bug_type = "tag-mismatch";
|
||||
uptr pc = stack->size ? stack->trace[0] : 0;
|
||||
Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
|
||||
address, pc);
|
||||
|
||||
tag_t ptr_tag = GetTagFromPointer(addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MEM_TO_SHADOW(address));
|
||||
tag_t mem_tag = *tag_ptr;
|
||||
Printf("%s", d.Access());
|
||||
Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem)\n",
|
||||
is_store ? "WRITE" : "READ", access_size, address, ptr_tag, mem_tag);
|
||||
Printf("%s", d.Default());
|
||||
|
||||
stack->Print();
|
||||
|
||||
PrintAddressDescription(address, access_size);
|
||||
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
||||
ReportErrorSummary(bug_type, stack);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
|
|||
uptr size, uptr offset);
|
||||
void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
|
||||
bool is_store);
|
||||
void ReportInvalidFree(StackTrace *stack, uptr addr);
|
||||
|
||||
void ReportAtExitStatistics();
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sanitizer/hwasan_interface.h>
|
||||
|
||||
int main() {
|
||||
__hwasan_enable_allocator_tagging();
|
||||
char * volatile x = (char*)malloc(40);
|
||||
free(x);
|
||||
free(x);
|
||||
// CHECK: ERROR: HWAddressSanitizer: invalid-free on address
|
||||
// CHECK: tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
|
||||
// CHECK: freed here:
|
||||
// CHECK: previously allocated here:
|
||||
// CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes):
|
||||
// CHECK: =>{{.*}}[[MEM_TAG]]
|
||||
fprintf(stderr, "DONE\n");
|
||||
__hwasan_disable_allocator_tagging();
|
||||
// CHECK-NOT: DONE
|
||||
}
|
Loading…
Reference in New Issue