about summary refs log tree commit diff
path: root/nptl
diff options
context:
space:
mode:
authorTorvald Riegel <triegel@redhat.com>2015-07-14 21:58:34 +0200
committerTorvald Riegel <triegel@redhat.com>2015-12-23 18:44:53 +0100
commit389fdf78b2e606387ce9d51f29e5c0a22ad9ad2a (patch)
tree3c665e20903d53ded06618a794b10d0d28292cc9 /nptl
parent7962541a32eff5597bc4207e781cfac8d1bb0d87 (diff)
downloadglibc-389fdf78b2e606387ce9d51f29e5c0a22ad9ad2a.tar.gz
glibc-389fdf78b2e606387ce9d51f29e5c0a22ad9ad2a.tar.xz
glibc-389fdf78b2e606387ce9d51f29e5c0a22ad9ad2a.zip
Do not violate mutex destruction requirements.
POSIX and C++11 require that a thread can destroy a mutex if no other
thread owns the mutex, is blocked on the mutex, or will try to acquire
it in the future.  After destroying the mutex, it can reuse or unmap the
underlying memory.  Thus, we must not access a mutex' memory after
releasing it.  Currently, we can load the private flag after releasing
the mutex, which is fixed by this patch.
See https://sourceware.org/bugzilla/show_bug.cgi?id=13690 for more
background.

We need to call futex_wake on the lock after releasing it, however.  This
is by design, and can lead to spurious wake-ups on unrelated futex words
(e.g., when the mutex memory is reused for another mutex).  This behavior
is documented in the glibc-internal futex API and in recent drafts of the
Linux kernel's futex documentation (see the draft_futex branch of
git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git).
Diffstat (limited to 'nptl')
-rw-r--r--nptl/pthread_mutex_unlock.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
index c078f7ebe3..e2cd52411f 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -230,16 +230,18 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
 	/* One less user.  */
 	--mutex->__data.__nusers;
 
-      /* Unlock.  */
+      /* Unlock.  Load all necessary mutex data before releasing the mutex
+	 to not violate the mutex destruction requirements (see
+	 lll_unlock).  */
+      int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+      int private = (robust
+		     ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
+		     : PTHREAD_MUTEX_PSHARED (mutex));
       if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
 	  || atomic_compare_and_exchange_bool_rel (&mutex->__data.__lock, 0,
 						   THREAD_GETMEM (THREAD_SELF,
 								  tid)))
 	{
-	  int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
-	  int private = (robust
-			 ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
-			 : PTHREAD_MUTEX_PSHARED (mutex));
 	  INTERNAL_SYSCALL_DECL (__err);
 	  INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
 			    __lll_private_flag (FUTEX_UNLOCK_PI, private));