[libc-commits] [libc] Reland "[libc] build fix for sigsetjmp (#137047)" (PR #137214)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Apr 29 05:55:16 PDT 2025


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/137214

>From 3ef0ab8c752dcd3275e6f408d65a573bd92e9a01 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 24 Apr 2025 13:02:09 -0400
Subject: [PATCH 1/5] Revert "Revert "[libc] build fix for sigsetjmp (#137047)"
 (#137077)"

This reverts commit 0d00b6bc3b459122de47d16c5153887063f4ea4b.
---
 libc/config/linux/x86_64/entrypoints.txt     |  2 +
 libc/hdr/CMakeLists.txt                      |  9 ++
 libc/hdr/offsetof_macros.h                   | 23 +++++
 libc/include/llvm-libc-types/CMakeLists.txt  |  2 +-
 libc/include/llvm-libc-types/jmp_buf.h       | 15 ++++
 libc/include/setjmp.yaml                     | 16 ++++
 libc/src/setjmp/CMakeLists.txt               | 27 ++++++
 libc/src/setjmp/linux/CMakeLists.txt         | 12 +++
 libc/src/setjmp/linux/sigsetjmp_epilogue.cpp | 25 ++++++
 libc/src/setjmp/setjmp_impl.h                |  3 +-
 libc/src/setjmp/siglongjmp.cpp               | 23 +++++
 libc/src/setjmp/siglongjmp.h                 | 25 ++++++
 libc/src/setjmp/sigsetjmp.h                  | 26 ++++++
 libc/src/setjmp/sigsetjmp_epilogue.h         | 19 +++++
 libc/src/setjmp/x86_64/CMakeLists.txt        | 20 +++--
 libc/src/setjmp/x86_64/setjmp.cpp            |  2 +-
 libc/src/setjmp/x86_64/sigsetjmp.cpp         | 68 +++++++++++++++
 libc/test/src/setjmp/CMakeLists.txt          | 17 ++++
 libc/test/src/setjmp/sigsetjmp_test.cpp      | 88 ++++++++++++++++++++
 19 files changed, 414 insertions(+), 8 deletions(-)
 create mode 100644 libc/hdr/offsetof_macros.h
 create mode 100644 libc/src/setjmp/linux/CMakeLists.txt
 create mode 100644 libc/src/setjmp/linux/sigsetjmp_epilogue.cpp
 create mode 100644 libc/src/setjmp/siglongjmp.cpp
 create mode 100644 libc/src/setjmp/siglongjmp.h
 create mode 100644 libc/src/setjmp/sigsetjmp.h
 create mode 100644 libc/src/setjmp/sigsetjmp_epilogue.h
 create mode 100644 libc/src/setjmp/x86_64/sigsetjmp.cpp
 create mode 100644 libc/test/src/setjmp/sigsetjmp_test.cpp

diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 73dfeae1a2c94..e3a96da615056 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1049,6 +1049,8 @@ if(LLVM_LIBC_FULL_BUILD)
     # setjmp.h entrypoints
     libc.src.setjmp.longjmp
     libc.src.setjmp.setjmp
+    libc.src.setjmp.siglongjmp
+    libc.src.setjmp.sigsetjmp
 
     # stdio.h entrypoints
     libc.src.stdio.clearerr
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index db2dac9ff2822..209fcb965242f 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -223,5 +223,14 @@ add_proxy_header_library(
     libc.include.wchar
 )
 
+# offsetof is a macro inside compiler resource header stddef.h
+add_proxy_header_library(
+  offsetof_macros
+  HDRS
+    offsetof_macros.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-macros.offsetof_macro
+)
+
 add_subdirectory(types)
 add_subdirectory(func)
diff --git a/libc/hdr/offsetof_macros.h b/libc/hdr/offsetof_macros.h
new file mode 100644
index 0000000000000..42e853ffa92e5
--- /dev/null
+++ b/libc/hdr/offsetof_macros.h
@@ -0,0 +1,23 @@
+//===-- Definition of macros for offsetof ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_OFFSETOF_MACROS_H
+#define LLVM_LIBC_HDR_OFFSETOF_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/offsetof-macro.h"
+
+#else // Overlay mode
+
+#define __need_offsetof
+#include <stddef.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_OFFSETOF_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 861b983b34219..26a3ed06b6f05 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -39,7 +39,6 @@ add_header(gid_t HDR gid_t.h)
 add_header(uid_t HDR uid_t.h)
 add_header(imaxdiv_t HDR imaxdiv_t.h)
 add_header(ino_t HDR ino_t.h)
-add_header(jmp_buf HDR jmp_buf.h)
 add_header(mbstate_t HDR mbstate_t.h)
 add_header(mode_t HDR mode_t.h)
 add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
@@ -83,6 +82,7 @@ add_header(union_sigval HDR union_sigval.h)
 add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t .clock_t)
 add_header(sig_atomic_t HDR sig_atomic_t.h)
 add_header(sigset_t HDR sigset_t.h DEPENDS libc.include.llvm-libc-macros.signal_macros)
+add_header(jmp_buf HDR jmp_buf.h DEPENDS .sigset_t)
 add_header(struct_sigaction HDR struct_sigaction.h DEPENDS .sigset_t .siginfo_t)
 add_header(struct_timespec HDR struct_timespec.h DEPENDS .time_t)
 add_header(
diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index f246e6491cf55..1e7791610857d 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -9,6 +9,8 @@
 #ifndef LLVM_LIBC_TYPES_JMP_BUF_H
 #define LLVM_LIBC_TYPES_JMP_BUF_H
 
+#include "sigset_t.h"
+
 typedef struct {
 #ifdef __x86_64__
   __UINT64_TYPE__ rbx;
@@ -49,9 +51,22 @@ typedef struct {
 #endif
 #else
 #error "__jmp_buf not available for your target architecture."
+#endif
+  // TODO: implement sigjmp_buf related functions for other architectures
+  // Issue: https://github.com/llvm/llvm-project/issues/136358
+#if defined(__i386__) || defined(__x86_64__)
+  // return address
+  void *sig_retaddr;
+  // extra register buffer to avoid indefinite stack growth in sigsetjmp
+  void *sig_extra;
+  // signal masks
+  sigset_t sigmask;
 #endif
 } __jmp_buf;
 
 typedef __jmp_buf jmp_buf[1];
 
+#if defined(__i386__) || defined(__x86_64__)
+typedef __jmp_buf sigjmp_buf[1];
+#endif
 #endif // LLVM_LIBC_TYPES_JMP_BUF_H
diff --git a/libc/include/setjmp.yaml b/libc/include/setjmp.yaml
index 5fbb9eb2a47e5..00049e58c86c8 100644
--- a/libc/include/setjmp.yaml
+++ b/libc/include/setjmp.yaml
@@ -21,3 +21,19 @@ functions:
       - _Returns_twice
     arguments:
       - type: jmp_buf
+  - name: sigsetjmp
+    standards:
+      - POSIX
+    return_type: int
+    attributes:
+      - _Returns_twice
+    arguments:
+      - type: sigjmp_buf
+      - type: int
+  - name: siglongjmp
+    standards:
+      - POSIX
+    return_type: _Noreturn void
+    arguments:
+      - type: sigjmp_buf
+      - type: int
diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index d85c532e8636c..2591319f15240 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -1,3 +1,13 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_object_library(
+    sigsetjmp_epilogue
+    ALIAS
+    DEPENDS
+      .${LIBC_TARGET_OS}.sigsetjmp_epilogue
+  )
+endif()
+
 if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
 endif()
@@ -15,3 +25,20 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_ARCHITECTURE}.longjmp
 )
+
+add_entrypoint_object(
+  siglongjmp
+  SRCS
+    siglongjmp.cpp
+  HDRS
+    siglongjmp.h
+  DEPENDS
+    .longjmp
+)
+
+add_entrypoint_object(
+  sigsetjmp
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_ARCHITECTURE}.sigsetjmp
+)
diff --git a/libc/src/setjmp/linux/CMakeLists.txt b/libc/src/setjmp/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..b844c8c5ee55a
--- /dev/null
+++ b/libc/src/setjmp/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_object_library(
+  sigsetjmp_epilogue
+  HDRS
+    ../sigsetjmp_epilogue.h
+  SRCS
+    sigsetjmp_epilogue.cpp
+  DEPENDS
+    libc.src.__support.common
+    libc.src.__support.OSUtil.osutil
+    libc.hdr.types.jmp_buf
+    libc.hdr.types.sigset_t
+)
diff --git a/libc/src/setjmp/linux/sigsetjmp_epilogue.cpp b/libc/src/setjmp/linux/sigsetjmp_epilogue.cpp
new file mode 100644
index 0000000000000..4718623c488ec
--- /dev/null
+++ b/libc/src/setjmp/linux/sigsetjmp_epilogue.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of sigsetjmp_epilogue ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/sigsetjmp_epilogue.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/common.h"
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+[[gnu::returns_twice]] int sigsetjmp_epilogue(jmp_buf buffer, int retval) {
+  // If set is NULL, then the signal mask is unchanged (i.e., how is
+  // ignored), but the current value of the signal mask is nevertheless
+  // returned in oldset (if it is not NULL).
+  syscall_impl<long>(SYS_rt_sigprocmask, SIG_SETMASK,
+                     /* set= */ retval ? &buffer->sigmask : nullptr,
+                     /* old_set= */ retval ? nullptr : &buffer->sigmask,
+                     sizeof(sigset_t));
+  return retval;
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/setjmp_impl.h b/libc/src/setjmp/setjmp_impl.h
index 669f720bda5d3..c89d6bc07c900 100644
--- a/libc/src/setjmp/setjmp_impl.h
+++ b/libc/src/setjmp/setjmp_impl.h
@@ -29,7 +29,8 @@ namespace LIBC_NAMESPACE_DECL {
 #ifdef LIBC_COMPILER_IS_GCC
 [[gnu::nothrow]]
 #endif
-__attribute__((returns_twice)) int setjmp(jmp_buf buf);
+[[gnu::returns_twice]] int
+setjmp(jmp_buf buf);
 
 } // namespace LIBC_NAMESPACE_DECL
 
diff --git a/libc/src/setjmp/siglongjmp.cpp b/libc/src/setjmp/siglongjmp.cpp
new file mode 100644
index 0000000000000..e372a6fa37503
--- /dev/null
+++ b/libc/src/setjmp/siglongjmp.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of siglongjmp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/siglongjmp.h"
+#include "src/__support/common.h"
+#include "src/setjmp/longjmp.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// siglongjmp is the same as longjmp. The additional recovery work is done in
+// the epilogue of the sigsetjmp function.
+// TODO: move this inside the TU of longjmp and making it an alias after
+//       sigsetjmp is implemented for all architectures.
+LLVM_LIBC_FUNCTION(void, siglongjmp, (jmp_buf buf, int val)) {
+  return LIBC_NAMESPACE::longjmp(buf, val);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/siglongjmp.h b/libc/src/setjmp/siglongjmp.h
new file mode 100644
index 0000000000000..ea5bbb91df2ec
--- /dev/null
+++ b/libc/src/setjmp/siglongjmp.h
@@ -0,0 +1,25 @@
+//===-- Implementation header for siglongjmp --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SETJMP_SIGLONGJMP_H
+#define LLVM_LIBC_SRC_SETJMP_SIGLONGJMP_H
+
+#include "hdr/types/jmp_buf.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/compiler.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+#ifdef LIBC_COMPILER_IS_GCC
+[[gnu::nothrow]]
+#endif
+void siglongjmp(jmp_buf buf, int val);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SETJMP_SIGLONGJMP_H
diff --git a/libc/src/setjmp/sigsetjmp.h b/libc/src/setjmp/sigsetjmp.h
new file mode 100644
index 0000000000000..ef060c8b344a6
--- /dev/null
+++ b/libc/src/setjmp/sigsetjmp.h
@@ -0,0 +1,26 @@
+//===-- Implementation header for sigsetjmp ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SETJMP_SIGSETJMP_H
+#define LLVM_LIBC_SRC_SETJMP_SIGSETJMP_H
+
+#include "hdr/types/jmp_buf.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/compiler.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+#ifdef LIBC_COMPILER_IS_GCC
+[[gnu::nothrow]]
+#endif
+[[gnu::returns_twice]] int
+sigsetjmp(sigjmp_buf buf, int savesigs);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SETJMP_SIGSETJMP_H
diff --git a/libc/src/setjmp/sigsetjmp_epilogue.h b/libc/src/setjmp/sigsetjmp_epilogue.h
new file mode 100644
index 0000000000000..88702b743940f
--- /dev/null
+++ b/libc/src/setjmp/sigsetjmp_epilogue.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for sigsetjmp epilogue ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SETJMP_SIGSETJMP_EPILOGUE_H
+#define LLVM_LIBC_SRC_SETJMP_SIGSETJMP_EPILOGUE_H
+
+#include "hdr/types/jmp_buf.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+[[gnu::returns_twice]] int sigsetjmp_epilogue(jmp_buf buffer, int retval);
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SETJMP_SIGSETJMP_EPILOGUE_H
diff --git a/libc/src/setjmp/x86_64/CMakeLists.txt b/libc/src/setjmp/x86_64/CMakeLists.txt
index 96d5751bc81dd..0090e81655662 100644
--- a/libc/src/setjmp/x86_64/CMakeLists.txt
+++ b/libc/src/setjmp/x86_64/CMakeLists.txt
@@ -5,9 +5,22 @@ add_entrypoint_object(
   HDRS
     ../setjmp_impl.h
   DEPENDS
+    libc.hdr.offsetof_macros
     libc.hdr.types.jmp_buf
-  COMPILE_OPTIONS
-    ${libc_opt_high_flag}
+)
+
+add_entrypoint_object(
+  sigsetjmp
+  SRCS
+    sigsetjmp.cpp
+  HDRS
+    ../sigsetjmp.h
+  DEPENDS
+    libc.hdr.types.jmp_buf
+    libc.hdr.types.sigset_t
+    libc.hdr.offsetof_macros
+    libc.src.setjmp.sigsetjmp_epilogue
+    libc.src.setjmp.setjmp
 )
 
 add_entrypoint_object(
@@ -18,7 +31,4 @@ add_entrypoint_object(
     ../longjmp.h
   DEPENDS
     libc.hdr.types.jmp_buf
-  COMPILE_OPTIONS
-    ${libc_opt_high_flag}
-    -fomit-frame-pointer
 )
diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
index 5ac10fa87b39a..28e52712c785d 100644
--- a/libc/src/setjmp/x86_64/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "include/llvm-libc-macros/offsetof-macro.h"
+#include "hdr/offsetof_macros.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 #include "src/setjmp/setjmp_impl.h"
diff --git a/libc/src/setjmp/x86_64/sigsetjmp.cpp b/libc/src/setjmp/x86_64/sigsetjmp.cpp
new file mode 100644
index 0000000000000..4c97a01822679
--- /dev/null
+++ b/libc/src/setjmp/x86_64/sigsetjmp.cpp
@@ -0,0 +1,68 @@
+//===-- Implementation of sigsetjmp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/sigsetjmp.h"
+#include "hdr/offsetof_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/setjmp/setjmp_impl.h"
+#include "src/setjmp/sigsetjmp_epilogue.h"
+
+#if !defined(LIBC_TARGET_ARCH_IS_X86)
+#error "Invalid file include"
+#endif
+namespace LIBC_NAMESPACE_DECL {
+#ifdef __i386__
+[[gnu::naked]]
+LLVM_LIBC_FUNCTION(int, sigsetjmp, (sigjmp_buf buf)) {
+  asm(R"(
+      mov 8(%%esp), %%ecx
+      jecxz .Lnosave
+
+      mov 4(%%esp), %%eax
+      pop %c[retaddr](%%eax)
+      mov %%ebx, %c[extra](%%eax)
+      mov %%eax, %%ebx
+      call %P[setjmp]
+      push %c[retaddr](%%ebx)
+      mov %%ebx,4(%%esp)
+      mov %%eax,8(%%esp)
+      mov %c[extra](%%ebx), %%ebx
+      jmp %P[epilogue]
+      
+.Lnosave:
+      jmp %P[setjmp])" ::[retaddr] "i"(offsetof(__jmp_buf, sig_retaddr)),
+      [extra] "i"(offsetof(__jmp_buf, sig_extra)), [setjmp] "X"(setjmp),
+      [epilogue] "X"(sigsetjmp_epilogue)
+      : "eax", "ebx", "ecx");
+}
+#endif
+[[gnu::naked]]
+LLVM_LIBC_FUNCTION(int, sigsetjmp, (sigjmp_buf, int)) {
+  asm(R"(
+      test %%esi, %%esi
+      jz .Lnosave
+
+      pop %c[retaddr](%%rdi)
+      mov %%rbx, %c[extra](%%rdi)
+      mov %%rdi, %%rbx
+      call %P[setjmp]
+      push %c[retaddr](%%rbx)
+      mov %%rbx, %%rdi
+      mov %%eax, %%esi
+      mov %c[extra](%%rdi), %%rbx
+      jmp %P[epilogue]
+      
+.Lnosave:
+      jmp %P[setjmp])" ::[retaddr] "i"(offsetof(__jmp_buf, sig_retaddr)),
+      [extra] "i"(offsetof(__jmp_buf, sig_extra)), [setjmp] "X"(setjmp),
+      [epilogue] "X"(sigsetjmp_epilogue)
+      : "rax", "rbx");
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/setjmp/CMakeLists.txt b/libc/test/src/setjmp/CMakeLists.txt
index 392230784bd99..e95476e00e54b 100644
--- a/libc/test/src/setjmp/CMakeLists.txt
+++ b/libc/test/src/setjmp/CMakeLists.txt
@@ -17,3 +17,20 @@ add_libc_unittest(
     libc.src.setjmp.longjmp
     libc.src.setjmp.setjmp
 )
+
+add_libc_unittest(
+  sigsetjmp_test
+  SUITE
+    libc_setjmp_unittests
+  SRCS
+    sigsetjmp_test.cpp
+  CXX_STANDARD
+    20
+  DEPENDS
+    libc.src.setjmp.sigsetjmp
+    libc.src.setjmp.siglongjmp
+    libc.src.signal.sigprocmask
+    libc.src.string.memset
+    libc.src.string.memcmp
+    libc.hdr.types.sigset_t
+)
diff --git a/libc/test/src/setjmp/sigsetjmp_test.cpp b/libc/test/src/setjmp/sigsetjmp_test.cpp
new file mode 100644
index 0000000000000..cf8d2f2fab347
--- /dev/null
+++ b/libc/test/src/setjmp/sigsetjmp_test.cpp
@@ -0,0 +1,88 @@
+//===-- Unittests for sigsetjmp and siglongjmp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/siglongjmp.h"
+#include "src/setjmp/sigsetjmp.h"
+#include "src/signal/sigprocmask.h"
+#include "src/string/memcmp.h"
+#include "src/string/memset.h"
+#include "test/UnitTest/Test.h"
+
+constexpr int MAX_LOOP = 123;
+int longjmp_called = 0;
+
+void jump_back(jmp_buf buf, int n) {
+  longjmp_called++;
+  LIBC_NAMESPACE::siglongjmp(buf, n); // Will return |n| out of setjmp
+}
+
+TEST(LlvmLibcSetJmpTest, SigSetAndJumpBackSaveSigs) {
+  jmp_buf buf;
+  longjmp_called = 0;
+  volatile int n = 0;
+  sigset_t old;
+  sigset_t mask_all;
+  sigset_t recovered;
+  LIBC_NAMESPACE::memset(&mask_all, 0xFF, sizeof(mask_all));
+  LIBC_NAMESPACE::memset(&old, 0, sizeof(old));
+  LIBC_NAMESPACE::memset(&recovered, 0, sizeof(recovered));
+  LIBC_NAMESPACE::sigprocmask(0, nullptr, &old);
+  if (LIBC_NAMESPACE::sigsetjmp(buf, 1) <= MAX_LOOP) {
+    LIBC_NAMESPACE::sigprocmask(0, nullptr, &recovered);
+    ASSERT_EQ(0, LIBC_NAMESPACE::memcmp(&old, &recovered, sizeof(old)));
+    n = n + 1;
+    LIBC_NAMESPACE::sigprocmask(SIG_BLOCK, &mask_all, nullptr);
+    jump_back(buf, n);
+  }
+  ASSERT_EQ(longjmp_called, n);
+  ASSERT_EQ(n, MAX_LOOP + 1);
+}
+
+TEST(LlvmLibcSetJmpTest, SigSetAndJumpBackValOneSaveSigs) {
+  jmp_buf buf;
+  longjmp_called = 0;
+  sigset_t old;
+  sigset_t mask_all;
+  sigset_t recovered;
+  LIBC_NAMESPACE::memset(&mask_all, 0xFF, sizeof(mask_all));
+  LIBC_NAMESPACE::memset(&old, 0, sizeof(old));
+  LIBC_NAMESPACE::memset(&recovered, 0, sizeof(recovered));
+  LIBC_NAMESPACE::sigprocmask(0, nullptr, &old);
+  int val = LIBC_NAMESPACE::sigsetjmp(buf, 1);
+  if (val == 0) {
+    LIBC_NAMESPACE::sigprocmask(SIG_BLOCK, &mask_all, nullptr);
+    jump_back(buf, val);
+  }
+  LIBC_NAMESPACE::sigprocmask(0, nullptr, &recovered);
+  ASSERT_EQ(0, LIBC_NAMESPACE::memcmp(&old, &recovered, sizeof(old)));
+  ASSERT_EQ(longjmp_called, 1);
+  ASSERT_EQ(val, 1);
+}
+
+TEST(LlvmLibcSetJmpTest, SigSetAndJumpBackNoSaveSigs) {
+  jmp_buf buf;
+  longjmp_called = 0;
+  volatile int n = 0;
+  if (LIBC_NAMESPACE::sigsetjmp(buf, 0) <= MAX_LOOP) {
+    n = n + 1;
+    jump_back(buf, n);
+  }
+  ASSERT_EQ(longjmp_called, n);
+  ASSERT_EQ(n, MAX_LOOP + 1);
+}
+
+TEST(LlvmLibcSetJmpTest, SigSetAndJumpBackValOneNoSaveSigs) {
+  jmp_buf buf;
+  longjmp_called = 0;
+  int val = LIBC_NAMESPACE::sigsetjmp(buf, 0);
+  if (val == 0) {
+    jump_back(buf, val);
+  }
+  ASSERT_EQ(longjmp_called, 1);
+  ASSERT_EQ(val, 1);
+}

>From 230422621aeb97c4839ba133c75c33496aa5a75a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 24 Apr 2025 13:15:42 -0400
Subject: [PATCH 2/5] fix build again

---
 libc/src/setjmp/CMakeLists.txt        | 32 ++++++++++++++-------------
 libc/src/setjmp/x86_64/CMakeLists.txt | 29 ++++++++++++------------
 2 files changed, 32 insertions(+), 29 deletions(-)

diff --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index 2591319f15240..239254fa57dc6 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -26,19 +26,21 @@ add_entrypoint_object(
     .${LIBC_TARGET_ARCHITECTURE}.longjmp
 )
 
-add_entrypoint_object(
-  siglongjmp
-  SRCS
-    siglongjmp.cpp
-  HDRS
-    siglongjmp.h
-  DEPENDS
-    .longjmp
-)
+if (TARGET libc.src.setjmp.sigsetjmp_epilogue)
+  add_entrypoint_object(
+    siglongjmp
+    SRCS
+      siglongjmp.cpp
+    HDRS
+      siglongjmp.h
+    DEPENDS
+      .longjmp
+  )
 
-add_entrypoint_object(
-  sigsetjmp
-  ALIAS
-  DEPENDS
-    .${LIBC_TARGET_ARCHITECTURE}.sigsetjmp
-)
+  add_entrypoint_object(
+    sigsetjmp
+    ALIAS
+    DEPENDS
+      .${LIBC_TARGET_ARCHITECTURE}.sigsetjmp
+  )
+endif()
diff --git a/libc/src/setjmp/x86_64/CMakeLists.txt b/libc/src/setjmp/x86_64/CMakeLists.txt
index 0090e81655662..03ed5fb647084 100644
--- a/libc/src/setjmp/x86_64/CMakeLists.txt
+++ b/libc/src/setjmp/x86_64/CMakeLists.txt
@@ -8,20 +8,21 @@ add_entrypoint_object(
     libc.hdr.offsetof_macros
     libc.hdr.types.jmp_buf
 )
-
-add_entrypoint_object(
-  sigsetjmp
-  SRCS
-    sigsetjmp.cpp
-  HDRS
-    ../sigsetjmp.h
-  DEPENDS
-    libc.hdr.types.jmp_buf
-    libc.hdr.types.sigset_t
-    libc.hdr.offsetof_macros
-    libc.src.setjmp.sigsetjmp_epilogue
-    libc.src.setjmp.setjmp
-)
+if (TARGET libc.src.setjmp.sigsetjmp_epilogue)
+  add_entrypoint_object(
+    sigsetjmp
+    SRCS
+      sigsetjmp.cpp
+    HDRS
+      ../sigsetjmp.h
+    DEPENDS
+      libc.hdr.types.jmp_buf
+      libc.hdr.types.sigset_t
+      libc.hdr.offsetof_macros
+      libc.src.setjmp.sigsetjmp_epilogue
+      libc.src.setjmp.setjmp
+  )
+endif()
 
 add_entrypoint_object(
   longjmp

>From 3591028462d189befbe038e7a87bd9a08da7b26e Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 24 Apr 2025 16:21:47 -0400
Subject: [PATCH 3/5] [libc] more amendments

---
 libc/include/llvm-libc-types/jmp_buf.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index 1e7791610857d..a6638b222138a 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -9,7 +9,9 @@
 #ifndef LLVM_LIBC_TYPES_JMP_BUF_H
 #define LLVM_LIBC_TYPES_JMP_BUF_H
 
+#if defined(__i386__) || defined(__x86_64__)
 #include "sigset_t.h"
+#endif
 
 typedef struct {
 #ifdef __x86_64__

>From 8ce5c04559d3c66700fa8e62bcc47a6b02c29535 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 24 Apr 2025 19:32:58 -0400
Subject: [PATCH 4/5] update jmp_buf.h to always gate this by __linux__

---
 libc/include/llvm-libc-types/jmp_buf.h | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index a6638b222138a..90bd60d741293 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -9,7 +9,13 @@
 #ifndef LLVM_LIBC_TYPES_JMP_BUF_H
 #define LLVM_LIBC_TYPES_JMP_BUF_H
 
-#if defined(__i386__) || defined(__x86_64__)
+// TODO: implement sigjmp_buf related functions for other architectures
+// Issue: https://github.com/llvm/llvm-project/issues/136358
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+#define __LIBC_HAS_SIGJMP_BUF
+#endif
+
+#if defined(__LIBC_HAS_SIGJMP_BUF)
 #include "sigset_t.h"
 #endif
 
@@ -54,9 +60,7 @@ typedef struct {
 #else
 #error "__jmp_buf not available for your target architecture."
 #endif
-  // TODO: implement sigjmp_buf related functions for other architectures
-  // Issue: https://github.com/llvm/llvm-project/issues/136358
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__LIBC_HAS_SIGJMP_BUF)
   // return address
   void *sig_retaddr;
   // extra register buffer to avoid indefinite stack growth in sigsetjmp
@@ -68,7 +72,10 @@ typedef struct {
 
 typedef __jmp_buf jmp_buf[1];
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__LIBC_HAS_SIGJMP_BUF)
 typedef __jmp_buf sigjmp_buf[1];
 #endif
+
+#undef __LIBC_HAS_SIGJMP_BUF
+
 #endif // LLVM_LIBC_TYPES_JMP_BUF_H

>From 277eb688831bf203f32602ca783af044874c5470 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 29 Apr 2025 08:55:01 -0400
Subject: [PATCH 5/5] Update libc/include/llvm-libc-types/jmp_buf.h

Co-authored-by: Petr Hosek <phosek at google.com>
---
 libc/include/llvm-libc-types/jmp_buf.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index 90bd60d741293..d1a13a353d17c 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -11,9 +11,11 @@
 
 // TODO: implement sigjmp_buf related functions for other architectures
 // Issue: https://github.com/llvm/llvm-project/issues/136358
-#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+#if defined(__linux__)
+#if defined(__i386__) || defined(__x86_64__)
 #define __LIBC_HAS_SIGJMP_BUF
 #endif
+#endif
 
 #if defined(__LIBC_HAS_SIGJMP_BUF)
 #include "sigset_t.h"



More information about the libc-commits mailing list