[hwasan] Madvise away thread aux data

Summary:
Release memory pages for thread data (allocator cache, stack allocations
ring buffer, etc) when a thread exits. We can not simply munmap them
because this memory is custom allocated within a limited address range,
and it needs to stay "reserved".

This change alters thread storage layout by putting the ring buffer
before Thread instead of after it. This makes it possible to find the
start of the thread aux allocation given only the Thread pointer.

Reviewers: kcc, pcc

Subscribers: kubamracek, llvm-commits

Differential Revision: https://reviews.llvm.org/D56621

llvm-svn: 352151
This commit is contained in:
Evgeniy Stepanov 2019-01-25 02:05:48 +00:00
parent 9ea001401c
commit f4e7051c67

View File

@ -108,38 +108,52 @@ struct ThreadStats {
class HwasanThreadList {
public:
HwasanThreadList(uptr storage, uptr size)
: free_space_(storage),
free_space_end_(storage + size),
ring_buffer_size_(RingBufferSize()) {}
: free_space_(storage), free_space_end_(storage + size) {
// [storage, storage + size) is used as a vector of
// thread_alloc_size_-sized, ring_buffer_size_*2-aligned elements.
// Each element contains
// * a ring buffer at offset 0,
// * a Thread object at offset ring_buffer_size_.
ring_buffer_size_ = RingBufferSize();
thread_alloc_size_ =
RoundUpTo(ring_buffer_size_ + sizeof(Thread), ring_buffer_size_ * 2);
}
Thread *CreateCurrentThread() {
Thread *t;
{
SpinMutexLock l(&list_mutex_);
t = free_list_.Pop();
if (t)
internal_memset((void *)t, 0, sizeof(Thread) + ring_buffer_size_);
else
if (t) {
uptr start = (uptr)t - ring_buffer_size_;
internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
} else {
t = AllocThread();
}
live_list_.Push(t);
}
t->Init((uptr)(t + 1), ring_buffer_size_);
t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
AddThreadStats(t);
return t;
}
void DontNeedThread(Thread *t) {
uptr start = (uptr)t - ring_buffer_size_;
ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
}
void ReleaseThread(Thread *t) {
// FIXME: madvise away the ring buffer?
RemoveThreadStats(t);
t->Destroy();
SpinMutexLock l(&list_mutex_);
live_list_.Remove(t);
free_list_.Push(t);
DontNeedThread(t);
}
Thread *GetThreadByBufferAddress(uptr p) {
uptr align = ring_buffer_size_ * 2;
return (Thread *)(RoundDownTo(p, align) - sizeof(Thread));
return (Thread *)(RoundDownTo(p, ring_buffer_size_ * 2) +
ring_buffer_size_);
}
uptr MemoryUsedPerThread() {
@ -175,15 +189,17 @@ class HwasanThreadList {
private:
Thread *AllocThread() {
uptr align = ring_buffer_size_ * 2;
uptr ring_buffer_start = RoundUpTo(free_space_ + sizeof(Thread), align);
free_space_ = ring_buffer_start + ring_buffer_size_;
CHECK(IsAligned(free_space_, align));
Thread *t = (Thread *)(free_space_ + ring_buffer_size_);
free_space_ += thread_alloc_size_;
CHECK(free_space_ <= free_space_end_ && "out of thread memory");
return (Thread *)(ring_buffer_start - sizeof(Thread));
return t;
}
uptr free_space_;
uptr free_space_end_;
uptr ring_buffer_size_;
uptr thread_alloc_size_;
ThreadListHead free_list_;
ThreadListHead live_list_;