Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

SchrodingerZhu
Copy link
Contributor

@SchrodingerZhu SchrodingerZhu commented Apr 24, 2025

Reland sigsetjmp patches with build fixes.

We wrap every target replying on the epilogue library into conditional checks.

@SchrodingerZhu
Copy link
Contributor Author

SchrodingerZhu commented Apr 24, 2025

@gulfemsavrun could you check if this fix addresses the build issue? thank you!

@SchrodingerZhu SchrodingerZhu marked this pull request as ready for review April 24, 2025 19:10
@llvmbot llvmbot added the libc label Apr 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 24, 2025

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

Changes

Reland sigsetjmp patches with build fixes.

We wrap every target replying on the epilogue library into conditional checks.


Full diff: https://github.com/llvm/llvm-project/pull/137214.diff

19 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+2)
  • (modified) libc/hdr/CMakeLists.txt (+9)
  • (added) libc/hdr/offsetof_macros.h (+23)
  • (modified) libc/include/llvm-libc-types/CMakeLists.txt (+1-1)
  • (modified) libc/include/llvm-libc-types/jmp_buf.h (+15)
  • (modified) libc/include/setjmp.yaml (+16)
  • (modified) libc/src/setjmp/CMakeLists.txt (+29)
  • (added) libc/src/setjmp/linux/CMakeLists.txt (+12)
  • (added) libc/src/setjmp/linux/sigsetjmp_epilogue.cpp (+25)
  • (modified) libc/src/setjmp/setjmp_impl.h (+2-1)
  • (added) libc/src/setjmp/siglongjmp.cpp (+23)
  • (added) libc/src/setjmp/siglongjmp.h (+25)
  • (added) libc/src/setjmp/sigsetjmp.h (+26)
  • (added) libc/src/setjmp/sigsetjmp_epilogue.h (+19)
  • (modified) libc/src/setjmp/x86_64/CMakeLists.txt (+16-5)
  • (modified) libc/src/setjmp/x86_64/setjmp.cpp (+1-1)
  • (added) libc/src/setjmp/x86_64/sigsetjmp.cpp (+68)
  • (modified) libc/test/src/setjmp/CMakeLists.txt (+17)
  • (added) libc/test/src/setjmp/sigsetjmp_test.cpp (+88)
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..239254fa57dc6 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,22 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_ARCHITECTURE}.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
+  )
+endif()
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..03ed5fb647084 100644
--- a/libc/src/setjmp/x86_64/CMakeLists.txt
+++ b/libc/src/setjmp/x86_64/CMakeLists.txt
@@ -5,10 +5,24 @@ add_entrypoint_object(
   HDRS
     ../setjmp_impl.h
   DEPENDS
+    libc.hdr.offsetof_macros
     libc.hdr.types.jmp_buf
-  COMPILE_OPTIONS
-    ${libc_opt_high_flag}
 )
+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
@@ -18,7 +32,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);
+}

@gulfemsavrun
Copy link
Contributor

@gulfemsavrun could you check if this fix addresses the build issue? thank you!

No, unfortunately it still has an issue. The issue seems to be different though.

[781/2496](33) Building CXX object libc/src/setjmp/arm/CMakeFiles/libc.src.setjmp.arm.setjmp.dir/setjmp.cpp.obj
FAILED: libc/src/setjmp/arm/CMakeFiles/libc.src.setjmp.arm.setjmp.dir/setjmp.cpp.obj 
/b/s/w/ir/x/w/llvm_build/./bin/clang++ --target=armv6m-none-eabi -DLIBC_NAMESPACE=__llvm_libc_21_0_0_git -I/b/s/w/ir/x/w/github-llvm-llvm-project/libc -isystem /b/s/w/ir/x/w/llvm_build/include/armv6m-unknown-none-eabi --target=armv6m-none-eabi -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" -D_LIBCPP_PRINT=1 -mthumb -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/b/s/w/ir/x/w/llvm_build/runtimes/runtimes-armv6m-none-eabi-bins=../../../github-llvm-llvm-project -ffile-prefix-map=/b/s/w/ir/x/w/github-llvm-llvm-project/= -no-canonical-prefixes -Os -DNDEBUG -std=gnu++17 --target=armv6m-none-eabi -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_TYPES_TIME_T_IS_32_BIT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -UNDEBUG -MD -MT libc/src/setjmp/arm/CMakeFiles/libc.src.setjmp.arm.setjmp.dir/setjmp.cpp.obj -MF libc/src/setjmp/arm/CMakeFiles/libc.src.setjmp.arm.setjmp.dir/setjmp.cpp.obj.d -o libc/src/setjmp/arm/CMakeFiles/libc.src.setjmp.arm.setjmp.dir/setjmp.cpp.obj -c /b/s/w/ir/x/w/github-llvm-llvm-project/libc/src/setjmp/arm/setjmp.cpp
In file included from /b/s/w/ir/x/w/github-llvm-llvm-project/libc/src/setjmp/arm/setjmp.cpp:11:
In file included from /b/s/w/ir/x/w/github-llvm-llvm-project/libc/src/setjmp/setjmp_impl.h:14:
In file included from /b/s/w/ir/x/w/github-llvm-llvm-project/libc/hdr/types/jmp_buf.h:14:
In file included from /b/s/w/ir/x/w/github-llvm-llvm-project/libc/include/llvm-libc-types/jmp_buf.h:12:
/b/s/w/ir/x/w/github-llvm-llvm-project/libc/include/llvm-libc-types/sigset_t.h:17:27: error: use of undeclared identifier '__NSIGSET_WORDS'
   17 |   unsigned long __signals[__NSIGSET_WORDS];
      |                           ^~~~~~~~~~~~~~~
1 error generated.

https://logs.chromium.org/logs/fuchsia/buildbucket/cr-buildbucket/8716684692628018529/+/u/clang/build/stdout

@SchrodingerZhu
Copy link
Contributor Author

Should be fixed by 3591028

@gulfemsavrun
Copy link
Contributor

Should be fixed by 3591028

With the above fix, the issue is resolved.
https://ci.chromium.org/b/8716676148318392433

#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__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than conditionally enabling this based on architecture, we should do it based on the standards enabled in hdrgen. Specifically, this should only be enabled for POSIX and should never be included elsewhere regardless of the architecture.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we will need _POSIX_SOURCE but I don't think this system is implemented in libc currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants