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

Adhemerval Zanella via Glibc-cvs <[email protected]> Mon, 6 Jul 2026 13:48:03 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=28c3a25bc249ab4f20d09fc2a8694f6bca9155dd

commit 28c3a25bc249ab4f20d09fc2a8694f6bca9155dd
Author: Adhemerval Zanella <[email protected]>
Date:   Wed Jun 17 11:25:47 2026 -0300

    s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297)
    
    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
    by running the elf tests on qemu system (kernel 6.1.0).
    
    Reviewed-by: Stefan Liebler <[email protected]>

Diff:
---
 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 41fd473d14..6ecaa24384 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)