[PATCH] s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297)

Stefan Liebler stli@linux.ibm.com
Mon Jul 6 12:50:15 GMT 2026


On 6/17/26 16:25, Adhemerval Zanella wrote:
> THREAD_SET_STACK_GUARD reads the thread pointer via THREAD_SELF
> (__builtin_thread_pointer), which the compiler treats as invariant.  In the
> static startup path the thread pointer is installed by the __libc_setup_tls
> call that immediately precedes the guard store, so the read must stay below
> it.  The existing barrier only clobbered the access registers a0/a1, which
> creates no dependency on the call, so the compiler could move the whole
> barrier and read above __libc_setup_tls.
> 
> This is sensitive to instruction scheduling and recent TLS startup
> changes exposed it on s390x.
> 
> Add a "memory" clobber to the barrier so it is tied to the call's memory
> effects and cannot be hoisted above it.  The macro is shared with the
> dynamic loader, so both startup paths are covered.
> 
> I checked on s390x-linux-gnu build for arch5, arch8, arch9, and arch11
> byt running the elf tests on qemu system (kernel 6.1.0).
> ---
>  sysdeps/s390/nptl/tls.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/sysdeps/s390/nptl/tls.h b/sysdeps/s390/nptl/tls.h
> index 41fd473d14a..6ecaa243841 100644
> --- a/sysdeps/s390/nptl/tls.h
> +++ b/sysdeps/s390/nptl/tls.h
> @@ -131,7 +131,7 @@ typedef struct
>  #define THREAD_SET_STACK_GUARD(value) \
>    do									      \
>     {									      \
> -     __asm__ __volatile__ ("" : : : "a0", "a1");			      \
> +     __asm__ __volatile__ ("" : : : "a0", "a1", "memory");		      \
>       THREAD_SETMEM (THREAD_SELF, header.stack_guard, value);		      \
>     }									      \
>    while (0)

Hi Adhemerval,

sorry for the long delay. I was away quite away for a while.

I can confirm, that without the patch for a static binary, reading a0 is
moved before the __libc_setup_tls call where a0/a1 is set up to the
valid thread pointer.

With the additional memory barrier, the reading of a0 takes place after
__libc_setup_tls.

I've also tested this patch with various configurations.

Reviewed-by: Stefan Liebler <stli@linux.ibm.com>



Independent of this patch, I've recognized that e.g. the new static test
elf/tst-ptrguard-static-dlopen can fail as test-container may fail to
start due to wrong GLIBC_2.XY version of system libc.so symbols. Usually
test-via-rtld-prefix is set to run-via-rtld-prefix in Makeconfig. The
latter one is set to "../ld.so --library-path ..." for dynamic tests,
but not for those listed in tests-static. In this case, the test itself
is static, but test-container is dynamically linked and is run without
"../ld.so --library-path ...".

Thanks,
Stefan


More information about the Libc-alpha mailing list