[PATCH v2] Mark swapcontext returns_twice by default [BZ #23130]

Stian Halseth stian@itx.no
Fri Sep 4 15:29:55 GMT 2026


swapcontext does not restore every callee-saved register on all targets.
On sparc the %l and %i registers are not in the saved context at all:
they live in the register window save area of the calling frame, which
another pass through that frame can overwrite.  stdlib/tst-setcontext2
fails on sparc64 for this reason at -O2 with PIC, where gcc keeps
&global in %i5 across swapcontext and reuses %i5 as the GOT base on
another path through the same frame.

Mark swapcontext returns_twice in the generic bits/indirect-return.h, so
every target that does not override it is covered.  x86 and aarch64 keep
their own headers and are unchanged.

string/tst-xbzero-opt.c calls swapcontext from an always_inline
function, which a returns_twice callee forbids; key its guard on the
availability of indirect_return rather than on __CET__.  It is the only
such site in the tree.

Tested on sparc64: full make check is clean, with no test that passed
before failing after.

Signed-off-by: Stian Halseth <stian@itx.no>
---
Changes in v2:
 - drop the sparc-specific rationale from the generic header
 - use returns_twice unconditionally rather than preferring
   indirect_return

I left the tst-xbzero-opt.c guard keyed on indirect_return.  The
attribute is x86/aarch64-only in practice -- __has_attribute reports 1
on x86_64 and 0 on sparc64 -- and both of those targets have their own
headers, so the guard still selects exactly the targets that end up with
returns_twice.

On sparc64 the generic header resolves to returns_twice either way, so
the make check result from v1 stands unchanged.

 bits/indirect-return.h  | 9 +++++++--
 string/tst-xbzero-opt.c | 7 +++----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/bits/indirect-return.h b/bits/indirect-return.h
index 819bd25b..ba2efb06 100644
--- a/bits/indirect-return.h
+++ b/bits/indirect-return.h
@@ -21,5 +21,10 @@
 #endif
 
 /* __INDIRECT_RETURN is used on swapcontext to indicate if it requires
-   special compiler treatment.  */
-#define __INDIRECT_RETURN
+   special compiler treatment.  swapcontext does not restore every
+   callee-saved register on all targets.  */
+#if __glibc_has_attribute (__returns_twice__)
+# define __INDIRECT_RETURN __attribute__ ((__returns_twice__))
+#else
+# define __INDIRECT_RETURN
+#endif
diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c
index 3aa13d03..26e2ec1c 100644
--- a/string/tst-xbzero-opt.c
+++ b/string/tst-xbzero-opt.c
@@ -111,10 +111,9 @@ use_test_buffer (unsigned char *buf)
 /* Always check the test buffer immediately after filling it; this
    makes externally visible side effects depend on the buffer existing
    and having been filled in.  */
-#if defined __CET__ && !__glibc_has_attribute (__indirect_return__)
-/* Note: swapcontext returns via indirect branch when SHSTK is enabled.
-   Without indirect_return attribute, swapcontext is marked with
-   returns_twice attribute, which prevents always_inline to work.  */
+#if !__glibc_has_attribute (__indirect_return__)
+/* Without indirect_return, swapcontext is marked returns_twice, which
+   prevents always_inline from working.  */
 # define ALWAYS_INLINE
 #else
 # define ALWAYS_INLINE	__attribute__ ((always_inline))
-- 
2.43.0



More information about the Libc-alpha mailing list