diff options
author | Elliott Hughes <enh@google.com> | 2014-03-07 17:59:05 -0800 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2014-06-02 19:03:18 +0000 |
commit | 38e8c7947a997f2ec9600882d2a6e3930ed49f22 (patch) | |
tree | 72b6476599f2fc58c890d779b933c0b89993383a | |
parent | 52b9a11ffb036e3bc2e700b5a020e5148eff7450 (diff) | |
download | bionic-38e8c7947a997f2ec9600882d2a6e3930ed49f22.zip bionic-38e8c7947a997f2ec9600882d2a6e3930ed49f22.tar.gz bionic-38e8c7947a997f2ec9600882d2a6e3930ed49f22.tar.bz2 |
Fix pthread_detach for already-exited threads.cm-11.0-XNPH25R-bacon-d22b777afacm-11.0-XNPH22R-bacon-03d77315ea
This fix handles the case when pthread_detach is
called for threads which have already exited.
This is required to avoid any memory leak
Change-Id: I2bf7f41234d93b226132a4c51705f4186f4961c3
Reported-by: Paresh Nakhe <pnakhe@codeaurora.org>
(cherry picked from commit 452fa4ec246f502ac1e773151898ee85a8410cd8)
-rw-r--r-- | libc/bionic/pthread_detach.cpp | 6 | ||||
-rw-r--r-- | tests/pthread_test.cpp | 30 |
2 files changed, 36 insertions, 0 deletions
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp index 95f11ac..a8608e3 100644 --- a/libc/bionic/pthread_detach.cpp +++ b/libc/bionic/pthread_detach.cpp @@ -44,6 +44,12 @@ int pthread_detach(pthread_t t) { return 0; // Already being joined; silently do nothing, like glibc. } + if (thread->tid == 0) { + // Already exited; clean up. + _pthread_internal_remove_locked(thread.get()); + return 0; + } + thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED; return 0; } diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index d4d38f5..5551c48 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -18,6 +18,7 @@ #include <errno.h> #include <limits.h> +#include <malloc.h> #include <pthread.h> #include <unistd.h> @@ -278,6 +279,35 @@ TEST(pthread, pthread_detach__no_such_thread) { ASSERT_EQ(ESRCH, pthread_detach(dead_thread)); } +TEST(pthread, pthread_detach__leak) { + size_t initial_bytes = mallinfo().uordblks; + + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + + std::vector<pthread_t> threads; + for (size_t i = 0; i < 32; ++i) { + pthread_t t; + ASSERT_EQ(0, pthread_create(&t, &attr, IdFn, NULL)); + threads.push_back(t); + } + + sleep(1); + + for (size_t i = 0; i < 32; ++i) { + ASSERT_EQ(0, pthread_detach(threads[i])) << i; + } + + size_t final_bytes = mallinfo().uordblks; + + int leaked_bytes = (final_bytes - initial_bytes); + + // User code (like this test) doesn't know how large pthread_internal_t is. + // We can be pretty sure it's more than 128 bytes. + ASSERT_LT(leaked_bytes, 32 /*threads*/ * 128 /*bytes*/); +} + TEST(pthread, pthread_getcpuclockid__clock_gettime) { pthread_t t; ASSERT_EQ(0, pthread_create(&t, NULL, SleepFn, reinterpret_cast<void*>(5))); |