OSDN Git Service

Fix leak of bionic TLS when threads are detached.
authorJosh Gao <jmgao@google.com>
Wed, 8 Mar 2017 07:05:08 +0000 (23:05 -0800)
committerJosh Gao <jmgao@google.com>
Wed, 8 Mar 2017 07:24:50 +0000 (23:24 -0800)
__pthread_internal_free doesn't happen on threads that are detached,
causing the bionic TLS allocation (and guard pages) to be leaked.

Fix the leak, and name the allocations to make things apparent if this
ever happens again.

Bug: http://b/36045112
Test: manually ran a program that detached empty threads
Change-Id: Id1c7852b7384474244f7bf5a0f7da54ff962e0a1

libc/bionic/pthread_create.cpp
libc/bionic/pthread_exit.cpp
libc/bionic/pthread_internal.cpp

index f591c86..6b3e148 100644 (file)
@@ -62,11 +62,13 @@ void __init_tls(pthread_internal_t* thread) {
   if (allocation == MAP_FAILED) {
     __libc_fatal("failed to allocate TLS");
   }
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard page");
 
   thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PAGE_SIZE);
   if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) != 0) {
     __libc_fatal("failed to mprotect TLS");
   }
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS");
 }
 
 void __init_thread_stack_guard(pthread_internal_t* thread) {
index 3401ed7..9adf405 100644 (file)
@@ -92,6 +92,10 @@ void pthread_exit(void* return_value) {
     thread->alternate_signal_stack = NULL;
   }
 
+  // Unmap the bionic TLS, including guard pages.
+  void* allocation = reinterpret_cast<char*>(thread->bionic_tls) - PAGE_SIZE;
+  munmap(allocation, BIONIC_TLS_SIZE + 2 * PAGE_SIZE);
+
   ThreadJoinState old_state = THREAD_NOT_JOINED;
   while (old_state == THREAD_NOT_JOINED &&
          !atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_EXITED_NOT_JOINED)) {
index 2bc2bfb..5819bc1 100644 (file)
@@ -86,10 +86,6 @@ void __pthread_internal_remove(pthread_internal_t* thread) {
 }
 
 static void __pthread_internal_free(pthread_internal_t* thread) {
-  // Unmap the TLS, including guard pages.
-  void* allocation = reinterpret_cast<char*>(thread->bionic_tls) - PAGE_SIZE;
-  munmap(allocation, BIONIC_TLS_SIZE + 2 * PAGE_SIZE);
-
   if (thread->mmap_size != 0) {
     // Free mapped space, including thread stack and pthread_internal_t.
     munmap(thread->attr.stack_base, thread->mmap_size);