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));