diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp index f2a2529d30050..d509b25b1d525 100644 --- a/libc/src/setjmp/x86_64/longjmp.cpp +++ b/libc/src/setjmp/x86_64/longjmp.cpp @@ -29,6 +29,7 @@ LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) { // |val| in rax. Note that this has to happen before we restore the registers // from values in |buf|. Otherwise, once rsp and rbp are updated, we cannot // read |val|. + val = val == 0 ? 1 : val; LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rax) : "m"(val) :); LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rbx) : "m"(buf->rbx) :); LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rbp) : "m"(buf->rbp) :); diff --git a/libc/test/src/setjmp/setjmp_test.cpp b/libc/test/src/setjmp/setjmp_test.cpp index 8fa915f841c21..3a8e22a68deda 100644 --- a/libc/test/src/setjmp/setjmp_test.cpp +++ b/libc/test/src/setjmp/setjmp_test.cpp @@ -10,21 +10,38 @@ #include "src/setjmp/setjmp_impl.h" #include "test/UnitTest/Test.h" -jmp_buf buf; constexpr int MAX_LOOP = 123; +int longjmp_called = 0; -void jump_back(int n) { +void jump_back(jmp_buf buf, int n) { + longjmp_called++; __llvm_libc::longjmp(buf, n); // Will return |n| out of setjmp } TEST(LlvmLibcSetJmpTest, SetAndJumpBack) { + jmp_buf buf; + longjmp_called = 0; + // Local variables in setjmp scope should be declared volatile. volatile int n = 0; // The first time setjmp is called, it should return 0. // Subsequent calls will return the value passed to jump_back below. if (__llvm_libc::setjmp(buf) <= MAX_LOOP) { ++n; - jump_back(n); + jump_back(buf, n); } + ASSERT_EQ(longjmp_called, n); ASSERT_EQ(n, MAX_LOOP + 1); } + +TEST(LlvmLibcSetJmpTest, SetAndJumpBackValOne) { + jmp_buf buf; + longjmp_called = 0; + + int val = __llvm_libc::setjmp(buf); + if (val == 0) + jump_back(buf, val); + + ASSERT_EQ(longjmp_called, 1); + ASSERT_EQ(val, 1); +}