Skip to content

Commit

Permalink
Avoid infinite loop when doing SIGTRAP in arm64-apple (#51284)
Browse files Browse the repository at this point in the history
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 <vtjnash@gmail.com>
(cherry picked from commit d51ad06)
  • Loading branch information
gbaraldi authored and nalimilan committed Nov 5, 2023
1 parent cb8c455 commit a00e2d4
Showing 1 changed file with 27 additions and 3 deletions.
30 changes: 27 additions & 3 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,19 @@ static void sigint_handler(int sig)
jl_sigint_passed = 1;
}

#if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
static void sigtrap_handler(int sig, siginfo_t *info, void *context)
{
uintptr_t pc = ((ucontext_t*)context)->uc_mcontext->__ss.__pc; // TODO: Do this in linux as well
uint32_t* code = (uint32_t*)(pc); // https://gcc.gnu.org/legacy-ml/gcc-patches/2013-11/msg02228.html
if (*code == 0xd4200020) { // brk #0x1 which is what LLVM defines as trap
signal(sig, SIG_DFL);
sig = SIGILL; // redefine this as as an "unreachable reached" error message
sigdie_handler(sig, info, context);
}
}
#endif

void jl_install_default_signal_handlers(void)
{
struct sigaction actf;
Expand All @@ -1004,6 +1017,20 @@ void jl_install_default_signal_handlers(void)
if (sigaction(SIGFPE, &actf, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
#if defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
struct sigaction acttrap;
memset(&acttrap, 0, sizeof(struct sigaction));
sigemptyset(&acttrap.sa_mask);
acttrap.sa_sigaction = sigtrap_handler;
acttrap.sa_flags = SA_ONSTACK | SA_SIGINFO;
if (sigaction(SIGTRAP, &acttrap, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
#else
if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGTRAP");
}
#endif
struct sigaction actint;
memset(&actint, 0, sizeof(struct sigaction));
sigemptyset(&actint.sa_mask);
Expand All @@ -1015,9 +1042,6 @@ void jl_install_default_signal_handlers(void)
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGPIPE");
}
if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGTRAP");
}

#if defined(HAVE_MACH)
allocate_mach_handler();
Expand Down

0 comments on commit a00e2d4

Please sign in to comment.