Fix blocking pthread_join. [BZ #23137]

On s390 (31bit) if glibc is build with -Os, pthread_join sometimes
blocks indefinitely. This is e.g. observable with
testcase intl/tst-gettext6.

pthread_join is calling lll_wait_tid(tid), which performs the futex-wait
syscall in a loop as long as tid != 0 (thread is alive).

On s390 (and build with -Os), tid is loaded from memory before
comparing against zero and then the tid is loaded a second time
in order to pass it to the futex-wait-syscall.
If the thread exits in between, then the futex-wait-syscall is
called with the value zero and it waits until a futex-wake occurs.
As the thread is already exited, there won't be a futex-wake.

In lll_wait_tid, the tid is stored to the local variable __tid,
which is then used as argument for the futex-wait-syscall.
But unfortunately the compiler is allowed to reload the value
from memory.

With this patch, the tid is loaded with atomic_load_acquire.
Then the compiler is not allowed to reload the value for __tid from memory.

ChangeLog:

	[BZ #23137]
	* sysdeps/nptl/lowlevellock.h (lll_wait_tid):
	Use atomic_load_acquire to load __tid.

(cherry picked from commit 1660901840)
This commit is contained in:
Stefan Liebler 2018-05-04 10:00:59 +02:00 committed by Dmitry V. Levin
parent a06d48fb9f
commit db988e50a8
2 changed files with 14 additions and 5 deletions

View File

@ -1,3 +1,9 @@
2018-05-04 Stefan Liebler <stli@linux.vnet.ibm.com>
[BZ #23137]
* sysdeps/nptl/lowlevellock.h (lll_wait_tid):
Use atomic_load_acquire to load __tid.
2018-04-24 Joseph Myers <joseph@codesourcery.com> 2018-04-24 Joseph Myers <joseph@codesourcery.com>
* sysdeps/unix/sysv/linux/sys/ptrace.h * sysdeps/unix/sysv/linux/sys/ptrace.h

View File

@ -184,8 +184,11 @@ extern int __lll_timedlock_wait (int *futex, const struct timespec *,
#define lll_wait_tid(tid) \ #define lll_wait_tid(tid) \
do { \ do { \
__typeof (tid) __tid; \ __typeof (tid) __tid; \
while ((__tid = (tid)) != 0) \ /* We need acquire MO here so that we synchronize \
lll_futex_wait (&(tid), __tid, LLL_SHARED);\ with the kernel's store to 0 when the clone \
terminates. (see above) */ \
while ((__tid = atomic_load_acquire (&(tid))) != 0) \
lll_futex_wait (&(tid), __tid, LLL_SHARED); \
} while (0) } while (0)
extern int __lll_timedwait_tid (int *, const struct timespec *) extern int __lll_timedwait_tid (int *, const struct timespec *)