forked from OSchip/llvm-project
[hwasan] print thread IDs when reporting a bug (also had to fix pthread_create on Linux)
llvm-svn: 341438
This commit is contained in:
parent
8806e512bb
commit
5d05be84b7
|
@ -292,16 +292,23 @@ INTERCEPTOR(void *, malloc, SIZE_T size) {
|
|||
extern "C" int pthread_attr_init(void *attr);
|
||||
extern "C" int pthread_attr_destroy(void *attr);
|
||||
|
||||
struct ThreadStartArg {
|
||||
thread_callback_t callback;
|
||||
void *param;
|
||||
};
|
||||
|
||||
static void *HwasanThreadStartFunc(void *arg) {
|
||||
__hwasan_thread_enter();
|
||||
ThreadStartArg *A = reinterpret_cast<ThreadStartArg*>(arg);
|
||||
return A->callback(A->param);
|
||||
ThreadStartArg A = *reinterpret_cast<ThreadStartArg*>(arg);
|
||||
UnmapOrDie(arg, GetPageSizeCached());
|
||||
return A.callback(A.param);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
|
||||
void * param) {
|
||||
ScopedTaggingDisabler disabler;
|
||||
ThreadStartArg *A = GetCurrentThread()->thread_start_arg();
|
||||
ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
|
||||
GetPageSizeCached(), "pthread_create"));
|
||||
*A = {callback, param};
|
||||
int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
|
||||
&HwasanThreadStartFunc, A);
|
||||
|
|
|
@ -43,6 +43,7 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator {
|
|||
const char *Origin() const { return Magenta(); }
|
||||
const char *Name() const { return Green(); }
|
||||
const char *Location() { return Green(); }
|
||||
const char *Thread() { return Green(); }
|
||||
};
|
||||
|
||||
bool FindHeapAllocation(HeapAllocationsRingBuffer *rb,
|
||||
|
@ -116,7 +117,7 @@ void PrintAddressDescription(uptr tagged_addr, uptr access_size) {
|
|||
har.requested_size, UntagAddr(har.tagged_addr),
|
||||
UntagAddr(har.tagged_addr) + har.requested_size);
|
||||
Printf("%s", d.Allocation());
|
||||
Printf("freed by thread %p here:\n", t);
|
||||
Printf("freed by thread T%zd here:\n", t->unique_id());
|
||||
Printf("%s", d.Default());
|
||||
GetStackTraceFromId(har.free_context_id).Print();
|
||||
|
||||
|
@ -124,6 +125,7 @@ void PrintAddressDescription(uptr tagged_addr, uptr access_size) {
|
|||
Printf("previously allocated here:\n", t);
|
||||
Printf("%s", d.Default());
|
||||
GetStackTraceFromId(har.alloc_context_id).Print();
|
||||
t->Announce();
|
||||
|
||||
num_descriptions_printed++;
|
||||
}
|
||||
|
@ -131,8 +133,10 @@ void PrintAddressDescription(uptr tagged_addr, uptr access_size) {
|
|||
// Very basic check for stack memory.
|
||||
if (t->AddrIsInStack(untagged_addr)) {
|
||||
Printf("%s", d.Location());
|
||||
Printf("Address %p is located in stack of thread %p\n", untagged_addr, t);
|
||||
Printf("%s", d.Default());
|
||||
Printf("Address %p is located in stack of thread T%zd\n", untagged_addr,
|
||||
t->unique_id());
|
||||
t->Announce();
|
||||
|
||||
num_descriptions_printed++;
|
||||
}
|
||||
});
|
||||
|
@ -230,18 +234,21 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
|
|||
Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
|
||||
untagged_addr, pc);
|
||||
|
||||
Thread *t = GetCurrentThread();
|
||||
|
||||
tag_t ptr_tag = GetTagFromPointer(tagged_addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
|
||||
tag_t mem_tag = *tag_ptr;
|
||||
Printf("%s", d.Access());
|
||||
Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem)\n",
|
||||
Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n",
|
||||
is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag,
|
||||
mem_tag);
|
||||
mem_tag, t->unique_id());
|
||||
Printf("%s", d.Default());
|
||||
|
||||
stack->Print();
|
||||
|
||||
PrintAddressDescription(tagged_addr, access_size);
|
||||
t->Announce();
|
||||
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
||||
|
|
|
@ -63,10 +63,11 @@ void Thread::Create() {
|
|||
uptr size = RoundUpTo(sizeof(Thread), PageSize);
|
||||
Thread *thread = (Thread*)MmapOrDie(size, __func__);
|
||||
thread->destructor_iterations_ = GetPthreadDestructorIterations();
|
||||
thread->random_state_ = flags()->random_tags ? RandomSeed() : 0;
|
||||
thread->unique_id_ = unique_id++;
|
||||
thread->random_state_ =
|
||||
flags()->random_tags ? RandomSeed() : thread->unique_id_;
|
||||
if (auto sz = flags()->heap_history_size)
|
||||
thread->heap_allocations_ = RingBuffer<HeapAllocationRecord>::New(sz);
|
||||
thread->unique_id_ = unique_id++;
|
||||
InsertIntoThreadList(thread);
|
||||
SetCurrentThread(thread);
|
||||
thread->Init();
|
||||
|
@ -100,7 +101,7 @@ void Thread::Init() {
|
|||
CHECK(MemIsApp(stack_top_ - 1));
|
||||
}
|
||||
if (flags()->verbose_threads)
|
||||
Print("Creating ");
|
||||
Print("Creating : ");
|
||||
}
|
||||
|
||||
void Thread::ClearShadowForThreadStackAndTLS() {
|
||||
|
@ -112,7 +113,7 @@ void Thread::ClearShadowForThreadStackAndTLS() {
|
|||
|
||||
void Thread::Destroy() {
|
||||
if (flags()->verbose_threads)
|
||||
Print("Destroying");
|
||||
Print("Destroying: ");
|
||||
malloc_storage().CommitBack();
|
||||
ClearShadowForThreadStackAndTLS();
|
||||
RemoveFromThreadList(this);
|
||||
|
@ -124,8 +125,8 @@ void Thread::Destroy() {
|
|||
}
|
||||
|
||||
void Thread::Print(const char *Prefix) {
|
||||
Printf("%s: thread %p id: %zd stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix,
|
||||
this, unique_id_, stack_bottom(), stack_top(),
|
||||
Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix,
|
||||
unique_id_, this, stack_bottom(), stack_top(),
|
||||
stack_top() - stack_bottom(),
|
||||
tls_begin(), tls_end());
|
||||
}
|
||||
|
|
|
@ -19,11 +19,6 @@
|
|||
|
||||
namespace __hwasan {
|
||||
|
||||
struct ThreadStartArg {
|
||||
thread_callback_t callback;
|
||||
void *param;
|
||||
};
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
static void Create(); // Must be called from the thread itself.
|
||||
|
@ -73,9 +68,12 @@ class Thread {
|
|||
}
|
||||
}
|
||||
|
||||
// Return a scratch ThreadStartArg object to be used in
|
||||
// pthread_create interceptor.
|
||||
ThreadStartArg *thread_start_arg() { return &thread_start_arg_; }
|
||||
u64 unique_id() const { return unique_id_; }
|
||||
void Announce() {
|
||||
if (announced_) return;
|
||||
announced_ = true;
|
||||
Print("Thread: ");
|
||||
}
|
||||
|
||||
private:
|
||||
// NOTE: There is no Thread constructor. It is allocated
|
||||
|
@ -108,7 +106,7 @@ class Thread {
|
|||
|
||||
u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
|
||||
|
||||
ThreadStartArg thread_start_arg_;
|
||||
bool announced_;
|
||||
};
|
||||
|
||||
Thread *GetCurrentThread();
|
||||
|
|
|
@ -14,12 +14,12 @@ void *BoringThread(void *arg) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// CHECK: Creating : thread {{.*}} id: 0
|
||||
// CHECK: Creating : thread {{.*}} id: 1
|
||||
// CHECK: Destroying: thread {{.*}} id: 1
|
||||
// CHECK: Creating : thread {{.*}} id: 1100
|
||||
// CHECK: Destroying: thread {{.*}} id: 1100
|
||||
// CHECK: Creating : thread {{.*}} id: 1101
|
||||
// CHECK: Creating : T0
|
||||
// CHECK: Creating : T1
|
||||
// CHECK: Destroying: T1
|
||||
// CHECK: Creating : T1100
|
||||
// CHECK: Destroying: T1100
|
||||
// CHECK: Creating : T1101
|
||||
|
||||
void *UAFThread(void *arg) {
|
||||
char * volatile x = (char*)malloc(10);
|
||||
|
@ -29,6 +29,7 @@ void *UAFThread(void *arg) {
|
|||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address
|
||||
// CHECK: WRITE of size 1
|
||||
// CHECK: many-threads-uaf.c:[[@LINE-3]]
|
||||
// CHECK: Thread: T1101
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Tests UAF detection where Allocate/Deallocate/Use
|
||||
// happen in separate threads.
|
||||
// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
|
@ -7,20 +9,48 @@
|
|||
|
||||
#include <sanitizer/hwasan_interface.h>
|
||||
|
||||
void *Thread(void *arg) {
|
||||
char * volatile x = (char*)malloc(10);
|
||||
fprintf(stderr, "ZZZ %p\n", x);
|
||||
char *volatile x;
|
||||
int state;
|
||||
|
||||
void *Allocate(void *arg) {
|
||||
x = (char*)malloc(10);
|
||||
__sync_fetch_and_add(&state, 1);
|
||||
while (__sync_fetch_and_add(&state, 0) != 3) {}
|
||||
return NULL;
|
||||
}
|
||||
void *Deallocate(void *arg) {
|
||||
while (__sync_fetch_and_add(&state, 0) != 1) {}
|
||||
free(x);
|
||||
__sync_fetch_and_add(&state, 1);
|
||||
while (__sync_fetch_and_add(&state, 0) != 3) {}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *Use(void *arg) {
|
||||
while (__sync_fetch_and_add(&state, 0) != 2) {}
|
||||
x[5] = 42;
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch on address
|
||||
// CHECK: WRITE of size 1
|
||||
// CHECK: WRITE of size 1 {{.*}} in thread T3
|
||||
// CHECK: thread-uaf.c:[[@LINE-3]]
|
||||
// CHECK: freed by thread T2 here
|
||||
// CHECK: in Deallocate
|
||||
// CHECK: previously allocated here:
|
||||
// CHECK: in Allocate
|
||||
// CHECK: Thread: T2 0x
|
||||
// CHECK: Thread: T3 0x
|
||||
__sync_fetch_and_add(&state, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
__hwasan_enable_allocator_tagging();
|
||||
pthread_t t;
|
||||
pthread_create(&t, NULL, Thread, NULL);
|
||||
pthread_join(t, NULL);
|
||||
pthread_t t1, t2, t3;
|
||||
|
||||
pthread_create(&t1, NULL, Allocate, NULL);
|
||||
pthread_create(&t2, NULL, Deallocate, NULL);
|
||||
pthread_create(&t3, NULL, Use, NULL);
|
||||
|
||||
pthread_join(t1, NULL);
|
||||
pthread_join(t2, NULL);
|
||||
pthread_join(t3, NULL);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue