diff options
author | Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> | 2017-01-03 17:16:02 -0200 |
---|---|---|
committer | Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> | 2017-01-03 17:21:41 -0200 |
commit | e9a96ea1aca4ebaa7c86e8b83b766f118d689d0f (patch) | |
tree | c8171c3229049caaea73c8f5ee2f2f068c02669b /sysdeps/unix/sysv/linux/powerpc/elision-unlock.c | |
parent | daaff5cc793acdd4f8667fca3b901647b4c34363 (diff) | |
download | glibc-e9a96ea1aca4ebaa7c86e8b83b766f118d689d0f.zip glibc-e9a96ea1aca4ebaa7c86e8b83b766f118d689d0f.tar.gz glibc-e9a96ea1aca4ebaa7c86e8b83b766f118d689d0f.tar.bz2 |
powerpc: Fix write-after-destroy in lock elision [BZ #20822]
The update of *adapt_count after the release of the lock causes a race
condition when thread A unlocks, thread B continues and destroys the
mutex, and thread A writes to *adapt_count.
Diffstat (limited to 'sysdeps/unix/sysv/linux/powerpc/elision-unlock.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/elision-unlock.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c index 6f45a9c..759c146 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c @@ -28,13 +28,16 @@ __lll_unlock_elision (int *lock, short *adapt_count, int pshared) __libc_tend (0); else { - lll_unlock ((*lock), pshared); + /* Update adapt_count in the critical section to prevent a + write-after-destroy error as mentioned in BZ 20822. The + following update of adapt_count has to be contained within + the critical region of the fall-back lock in order to not violate + the mutex destruction requirements. */ + short __tmp = atomic_load_relaxed (adapt_count); + if (__tmp > 0) + atomic_store_relaxed (adapt_count, __tmp--); - /* Update the adapt count AFTER completing the critical section. - Doing this here prevents unneeded stalling when entering - a critical section. Saving about 8% runtime on P8. */ - if (*adapt_count > 0) - (*adapt_count)--; + lll_unlock ((*lock), pshared); } return 0; } |