PIMutexUnlock: load owner_tid in non-common case
For a recursive or errorcheck PI mutex, the old_owner variable wasn't
being initialized. As a result, unlocking a doubly-locked recursive
mutex owned by another thread decremented the mutex counter. Instead, the
unlock call should fail with EPERM.
Bug: http://b/130841532
Test: bionic-unit-tests
Test: bionic-unit-tests-glibc --gtest_filter='pthread.pthread_mutex_lock*'
Change-Id: I37adb094cb2ce8d51df7b4f48e8d6bc144436418
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 7b64401..0bf8e29 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -1843,10 +1843,25 @@
DISALLOW_COPY_AND_ASSIGN(PthreadMutex);
};
+static int UnlockFromAnotherThread(pthread_mutex_t* mutex) {
+ pthread_t thread;
+ pthread_create(&thread, nullptr, [](void* mutex_voidp) -> void* {
+ pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(mutex_voidp);
+ intptr_t result = pthread_mutex_unlock(mutex);
+ return reinterpret_cast<void*>(result);
+ }, mutex);
+ void* result;
+ EXPECT_EQ(0, pthread_join(thread, &result));
+ return reinterpret_cast<intptr_t>(result);
+};
+
static void TestPthreadMutexLockNormal(int protocol) {
PthreadMutex m(PTHREAD_MUTEX_NORMAL, protocol);
ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+ if (protocol == PTHREAD_PRIO_INHERIT) {
+ ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
+ }
ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
ASSERT_EQ(EBUSY, pthread_mutex_trylock(&m.lock));
@@ -1857,6 +1872,7 @@
PthreadMutex m(PTHREAD_MUTEX_ERRORCHECK, protocol);
ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+ ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
ASSERT_EQ(EDEADLK, pthread_mutex_lock(&m.lock));
ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));
@@ -1873,7 +1889,9 @@
PthreadMutex m(PTHREAD_MUTEX_RECURSIVE, protocol);
ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+ ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
ASSERT_EQ(0, pthread_mutex_lock(&m.lock));
+ ASSERT_EQ(EPERM, UnlockFromAnotherThread(&m.lock));
ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
ASSERT_EQ(0, pthread_mutex_trylock(&m.lock));