Skip to content

Commit 16ee6fa

Browse files
committed
Avoid infinite recursion when raising SIGABRT in SIGABRT handler
When VM state is corrupted enough, we can call abort() from the SIGABRT handler. Previously, we would spam until the stack is full: ABRT received in SEGV handler SEGV received in ABRT handler ABRT received in SEGV handler ABRT received in ABRT handler ABRT received in ABRT handler ABRT received in ABRT handler [...] We've seen this on CI: https://github.com/ruby/ruby/actions/runs/26591192708/job/78350130653 To test this situation locally, temporarily patch in a call to abort() in rb_bug_for_fatal_signal() then use `Process.kill(:ABRT, Process.pid)`. Fix by restoring the default signal handler before aborting.
1 parent 63d9f09 commit 16ee6fa

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

signal.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1020,8 +1020,20 @@ check_reserved_signal_(const char *name, size_t name_len, int signo)
10201020
#if __has_feature(address_sanitizer) || \
10211021
__has_feature(memory_sanitizer) || \
10221022
defined(HAVE_VALGRIND_MEMCHECK_H)
1023-
ruby_posix_signal(signo, SIG_DFL);
1023+
# define SANITIZING true
1024+
#else
1025+
# define SANITIZING false
1026+
#endif
1027+
1028+
#ifdef SIGABRT
1029+
// Avoid infinite loop when already aborting
1030+
# define RECURSIVE (signo == SIGABRT)
1031+
#else
1032+
# define RECURSIVE false
10241033
#endif
1034+
if (SANITIZING || RECURSIVE) ruby_signal(signo, SIG_DFL);
1035+
# undef SANITIZING
1036+
# undef RECURSIVE
10251037
W(name, name_len);
10261038
W(msg1, sizeof(msg1));
10271039
W(prev, strlen(prev));

0 commit comments

Comments
 (0)