Skip to content

Commit d51ad06

Browse files
gbaraldivtjnash
andauthored
Avoid infinite loop when doing SIGTRAP in arm64-apple (#51284)
The guard instruction for unreachables and other crashes in aarch64 is `brk`, in macos there isn't a distinction between a brk for a breakpoint and one for a crash, as an attempt we check the value of `pc` when the signal is triggered, if it is `brk #0x1` we say that it is a crash and go into the sigdie_handler. We should probably do the same in aarch64 linux, though I haven't dug too deep into what values it uses for traps, and if what compiler used matters, on apple I assumed we use clang/LLVM It might be possible to test this by calling some inline assembly. This means that something like #51267 actually crashes with ```c [16908] signal (5): Trace/BPT trap: 5 in expression starting at /Users/gabrielbaraldi/julia/test.jl:2 _collect at ./array.jl:768 collect at ./array.jl:757 top-level scope at /Users/gabrielbaraldi/julia/test.jl:5 _jl_invoke at /Users/gabrielbaraldi/julia/src/gf.c:2892 jl_toplevel_eval_flex at /Users/gabrielbaraldi/julia/src/toplevel.c:925 jl_toplevel_eval_flex at /Users/gabrielbaraldi/julia/src/toplevel.c:877 ijl_toplevel_eval at /Users/gabrielbaraldi/julia/src/toplevel.c:943 [inlined] ijl_toplevel_eval_in at /Users/gabrielbaraldi/julia/src/toplevel.c:985 eval at ./boot.jl:383 [inlined] include_string at ./loading.jl:2070 _jl_invoke at /Users/gabrielbaraldi/julia/src/gf.c:2873 ijl_apply_generic at /Users/gabrielbaraldi/julia/src/gf.c:3074 _include at ./loading.jl:2130 include at ./Base.jl:494 jfptr_include_46486 at /Users/gabrielbaraldi/julia/usr/lib/julia/sys.dylib (unknown line) _jl_invoke at /Users/gabrielbaraldi/julia/src/gf.c:2873 ijl_apply_generic at /Users/gabrielbaraldi/julia/src/gf.c:3074 exec_options at ./client.jl:317 _start at ./client.jl:552 jfptr__start_83179 at /Users/gabrielbaraldi/julia/usr/lib/julia/sys.dylib (unknown line) _jl_invoke at /Users/gabrielbaraldi/julia/src/gf.c:2873 ijl_apply_generic at /Users/gabrielbaraldi/julia/src/gf.c:3074 jl_apply at /Users/gabrielbaraldi/julia/src/./julia.h:1970 [inlined] true_main at /Users/gabrielbaraldi/julia/src/jlapi.c:582 jl_repl_entrypoint at /Users/gabrielbaraldi/julia/src/jlapi.c:731 Allocations: 570978 (Pool: 570031; Big: 947); GC: 1 fish: Job 1, './julia test.jl' terminated by signal SIGTRAP (Trace or breakpoint trap) ``` instead of hanging silently --------- Co-authored-by: Jameson Nash <[email protected]>
1 parent bdd3ffd commit d51ad06

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

src/signals-unix.c

+27-3
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,19 @@ static void sigint_handler(int sig)
994994
jl_sigint_passed = 1;
995995
}
996996

997+
#if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
998+
static void sigtrap_handler(int sig, siginfo_t *info, void *context)
999+
{
1000+
uintptr_t pc = ((ucontext_t*)context)->uc_mcontext->__ss.__pc; // TODO: Do this in linux as well
1001+
uint32_t* code = (uint32_t*)(pc); // https://gcc.gnu.org/legacy-ml/gcc-patches/2013-11/msg02228.html
1002+
if (*code == 0xd4200020) { // brk #0x1 which is what LLVM defines as trap
1003+
signal(sig, SIG_DFL);
1004+
sig = SIGILL; // redefine this as as an "unreachable reached" error message
1005+
sigdie_handler(sig, info, context);
1006+
}
1007+
}
1008+
#endif
1009+
9971010
void jl_install_default_signal_handlers(void)
9981011
{
9991012
struct sigaction actf;
@@ -1004,6 +1017,20 @@ void jl_install_default_signal_handlers(void)
10041017
if (sigaction(SIGFPE, &actf, NULL) < 0) {
10051018
jl_errorf("fatal error: sigaction: %s", strerror(errno));
10061019
}
1020+
#if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
1021+
struct sigaction acttrap;
1022+
memset(&acttrap, 0, sizeof(struct sigaction));
1023+
sigemptyset(&acttrap.sa_mask);
1024+
acttrap.sa_sigaction = sigtrap_handler;
1025+
acttrap.sa_flags = SA_ONSTACK | SA_SIGINFO;
1026+
if (sigaction(SIGTRAP, &acttrap, NULL) < 0) {
1027+
jl_errorf("fatal error: sigaction: %s", strerror(errno));
1028+
}
1029+
#else
1030+
if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
1031+
jl_error("fatal error: Couldn't set SIGTRAP");
1032+
}
1033+
#endif
10071034
struct sigaction actint;
10081035
memset(&actint, 0, sizeof(struct sigaction));
10091036
sigemptyset(&actint.sa_mask);
@@ -1015,9 +1042,6 @@ void jl_install_default_signal_handlers(void)
10151042
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
10161043
jl_error("fatal error: Couldn't set SIGPIPE");
10171044
}
1018-
if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
1019-
jl_error("fatal error: Couldn't set SIGTRAP");
1020-
}
10211045

10221046
#if defined(HAVE_MACH)
10231047
allocate_mach_handler();

0 commit comments

Comments
 (0)