diff --git a/.gitignore b/.gitignore index ed709c9b2cda..0c22a78c30e1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,3 @@ all_spec /src/llvm/ext/llvm_ext.o /src/llvm/ext/llvm_ext.obj /src/llvm/ext/llvm_ext.dwo -/src/ext/*.o -/src/ext/libcrystal.a diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7a6b7b42319..6a77a16bfd2a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,8 +91,6 @@ Additionally, all official documentation can be found on [the Crystal website](h 1. Fork it ( https://github.com/crystal-lang/crystal/fork ) 2. Clone it -Be sure to execute `make libcrystal` inside the cloned repository. - Once in the cloned directory, and once you [installed Crystal](https://crystal-lang.org/install/), you can execute `bin/crystal` instead of `crystal`. This is a wrapper that will use the cloned repository as the standard library. Otherwise the barebones `crystal` executable uses the standard library that comes in diff --git a/Makefile b/Makefile index cf3ffd900135..cabf2ecca427 100644 --- a/Makefile +++ b/Makefile @@ -42,11 +42,7 @@ SHELL = sh LLVM_CONFIG := $(shell src/llvm/ext/find-llvm-config) LLVM_EXT_DIR = src/llvm/ext LLVM_EXT_OBJ = $(LLVM_EXT_DIR)/llvm_ext.o -LIB_CRYSTAL_SOURCES = $(shell find src/ext -name '*.c') -LIB_CRYSTAL_OBJS = $(subst .c,.o,$(LIB_CRYSTAL_SOURCES)) -LIB_CRYSTAL_TARGET = src/ext/libcrystal.a -DEPS = $(LLVM_EXT_OBJ) $(LIB_CRYSTAL_TARGET) -CFLAGS += -fPIC $(if $(debug),-g -O0) +DEPS = $(LLVM_EXT_OBJ) CXXFLAGS += $(if $(debug),-g -O0) CRYSTAL_VERSION ?= $(shell cat src/VERSION) @@ -99,11 +95,9 @@ docs: ## Generate standard library documentation .PHONY: crystal crystal: $(O)/crystal ## Build the compiler -.PHONY: deps llvm_ext libcrystal +.PHONY: deps llvm_ext deps: $(DEPS) ## Build dependencies - llvm_ext: $(LLVM_EXT_OBJ) -libcrystal: $(LIB_CRYSTAL_TARGET) $(O)/all_spec: $(DEPS) $(SOURCES) $(SPEC_SOURCES) @mkdir -p $(O) @@ -124,13 +118,9 @@ $(O)/crystal: $(DEPS) $(SOURCES) $(LLVM_EXT_OBJ): $(LLVM_EXT_DIR)/llvm_ext.cc $(CXX) -c $(CXXFLAGS) -o $@ $< $(shell $(LLVM_CONFIG) --cxxflags) -$(LIB_CRYSTAL_TARGET): $(LIB_CRYSTAL_OBJS) - $(AR) -rcs $@ $^ - .PHONY: clean clean: clean_crystal ## Clean up built directories and files rm -rf $(LLVM_EXT_OBJ) - rm -rf $(LIB_CRYSTAL_OBJS) $(LIB_CRYSTAL_TARGET) .PHONY: clean_crystal clean_crystal: ## Clean up crystal built files diff --git a/shell.nix b/shell.nix index f95a0f4a061a..7c25b6fd723f 100644 --- a/shell.nix +++ b/shell.nix @@ -146,6 +146,5 @@ pkgs.stdenv.mkDerivation rec { LLVM_CONFIG = "${llvm_suite.llvm}/bin/llvm-config"; - # ld: warning: object file (.../src/ext/libcrystal.a(sigfault.o)) was built for newer OSX version (10.14) than being linked (10.12) MACOSX_DEPLOYMENT_TARGET = "10.11"; } diff --git a/src/ext.cr b/src/ext.cr deleted file mode 100644 index effe7be28e75..000000000000 --- a/src/ext.cr +++ /dev/null @@ -1,4 +0,0 @@ -@[Link(ldflags: "#{__DIR__}/ext/libcrystal.a")] -lib LibExt - fun setup_sigfault_handler -end diff --git a/src/ext/sigfault.c b/src/ext/sigfault.c deleted file mode 100644 index 5293f3d84304..000000000000 --- a/src/ext/sigfault.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include - -void __crystal_sigfault_handler(int sig, void *addr); - -void sigfault_handler(int sig, siginfo_t *info, void *data) { - __crystal_sigfault_handler(sig, info->si_addr); -} - -void setup_sigfault_handler() { - stack_t altstack; - struct sigaction action; - - altstack.ss_sp = malloc(SIGSTKSZ); - altstack.ss_size = SIGSTKSZ; - altstack.ss_flags = 0; - sigaltstack(&altstack, NULL); - - sigemptyset(&action.sa_mask); - action.sa_flags = SA_ONSTACK | SA_SIGINFO; - action.sa_sigaction = &sigfault_handler; - - sigaction(SIGSEGV, &action, NULL); - sigaction(SIGBUS, &action, NULL); -} diff --git a/src/kernel.cr b/src/kernel.cr index 60117755d3d6..1630df946711 100644 --- a/src/kernel.cr +++ b/src/kernel.cr @@ -535,12 +535,12 @@ end end Signal.setup_default_handlers - LibExt.setup_sigfault_handler + Signal.setup_segfault_handler {% end %} {% if !flag?(:win32) %} # load dwarf on start up of the program is executed with CRYSTAL_LOAD_DWARF=1 - # this will make dwarf available on print_frame that is used on __crystal_sigfault_handler + # this will make dwarf available on print_frame that is used by Crystal's segfault handler # # - CRYSTAL_LOAD_DWARF=0 will never use dwarf information (See Exception::CallStack.load_dwarf) # - CRYSTAL_LOAD_DWARF=1 will load dwarf on startup diff --git a/src/lib_c/aarch64-darwin/c/signal.cr b/src/lib_c/aarch64-darwin/c/signal.cr index 74af1891ee06..8e3cbe8c0e6e 100644 --- a/src/lib_c/aarch64-darwin/c/signal.cr +++ b/src/lib_c/aarch64-darwin/c/signal.cr @@ -34,6 +34,8 @@ lib LibC SIGINFO = 29 SIGWINCH = 28 + SIGSTKSZ = 131072 + SIG_SETMASK = 3 alias SighandlerT = Int -> @@ -42,9 +44,41 @@ lib LibC SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null) + SA_ONSTACK = 0x0001 + SA_SIGINFO = 0x0040 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_pid : PidT + si_uid : UidT + si_status : Int + si_addr : Void* + _pad : StaticArray(SizeT, 9) + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + # Technically a union, but only one can be valid and we only use sa_sigaction + # and not sa_handler (which would be a SighandlerT) + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + end + + struct StackT + ss_sp : Void* + ss_size : SizeT + ss_flags : Int + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/aarch64-linux-gnu/c/signal.cr b/src/lib_c/aarch64-linux-gnu/c/signal.cr index 325fdb8cf457..c9d22e360cb7 100644 --- a/src/lib_c/aarch64-linux-gnu/c/signal.cr +++ b/src/lib_c/aarch64-linux-gnu/c/signal.cr @@ -36,6 +36,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = 31 + SIGSTKSZ = 16384 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -43,12 +45,41 @@ lib LibC SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null) struct SigsetT - val : ULong[32] # (1024 / (8 * sizeof(long))) + val : ULong[16] # (1024 / (8 * sizeof(ULong))) + end + + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + __pad0 : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad1 : StaticArray(Int, 20) # __SI_PAD_SIZE (28) - sizeof(void*) (8) = 20 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT end fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/aarch64-linux-musl/c/signal.cr b/src/lib_c/aarch64-linux-musl/c/signal.cr index a66eac510650..1f0411e152c7 100644 --- a/src/lib_c/aarch64-linux-musl/c/signal.cr +++ b/src/lib_c/aarch64-linux-musl/c/signal.cr @@ -35,6 +35,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = LibC::SIGSYS + SIGSTKSZ = 12288 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -45,9 +47,38 @@ lib LibC val : ULong[16] # 128 / sizeof(long) end + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + __pad0 : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad1 : StaticArray(Int, 20) # __SI_PAD_SIZE (28) - sizeof(void*) (8) = 20 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/arm-linux-gnueabihf/c/signal.cr b/src/lib_c/arm-linux-gnueabihf/c/signal.cr index 325fdb8cf457..22e4fdd561b9 100644 --- a/src/lib_c/arm-linux-gnueabihf/c/signal.cr +++ b/src/lib_c/arm-linux-gnueabihf/c/signal.cr @@ -36,6 +36,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = 31 + SIGSTKSZ = 8192 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -46,9 +48,37 @@ lib LibC val : ULong[32] # (1024 / (8 * sizeof(long))) end + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/i386-linux-gnu/c/signal.cr b/src/lib_c/i386-linux-gnu/c/signal.cr index 325fdb8cf457..22e4fdd561b9 100644 --- a/src/lib_c/i386-linux-gnu/c/signal.cr +++ b/src/lib_c/i386-linux-gnu/c/signal.cr @@ -36,6 +36,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = 31 + SIGSTKSZ = 8192 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -46,9 +48,37 @@ lib LibC val : ULong[32] # (1024 / (8 * sizeof(long))) end + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/i386-linux-musl/c/signal.cr b/src/lib_c/i386-linux-musl/c/signal.cr index df01a297bc4d..d822d82b9d27 100644 --- a/src/lib_c/i386-linux-musl/c/signal.cr +++ b/src/lib_c/i386-linux-musl/c/signal.cr @@ -35,6 +35,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = LibC::SIGSYS + SIGSTKSZ = 8192 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -45,9 +47,37 @@ lib LibC bits : ULong[32] # 128 / sizeof(long) end + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad : StaticArray(Int, 25) # __SI_PAD_SIZE (29) - sizeof(void*) (4) = 25 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-darwin/c/signal.cr b/src/lib_c/x86_64-darwin/c/signal.cr index 74af1891ee06..8e3cbe8c0e6e 100644 --- a/src/lib_c/x86_64-darwin/c/signal.cr +++ b/src/lib_c/x86_64-darwin/c/signal.cr @@ -34,6 +34,8 @@ lib LibC SIGINFO = 29 SIGWINCH = 28 + SIGSTKSZ = 131072 + SIG_SETMASK = 3 alias SighandlerT = Int -> @@ -42,9 +44,41 @@ lib LibC SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null) + SA_ONSTACK = 0x0001 + SA_SIGINFO = 0x0040 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_pid : PidT + si_uid : UidT + si_status : Int + si_addr : Void* + _pad : StaticArray(SizeT, 9) + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + # Technically a union, but only one can be valid and we only use sa_sigaction + # and not sa_handler (which would be a SighandlerT) + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + end + + struct StackT + ss_sp : Void* + ss_size : SizeT + ss_flags : Int + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-dragonfly/c/signal.cr b/src/lib_c/x86_64-dragonfly/c/signal.cr index 54baf1d21984..34ee5a0d22fb 100644 --- a/src/lib_c/x86_64-dragonfly/c/signal.cr +++ b/src/lib_c/x86_64-dragonfly/c/signal.cr @@ -38,6 +38,8 @@ lib LibC SIGCKPT = 33 SIGCKPTEXIT = 34 + SIGSTKSZ = 40960 + SIG_SETMASK = 3 alias SighandlerT = Int -> @@ -48,9 +50,48 @@ lib LibC bits : UInt32[4] end + SA_ONSTACK = 0x0001 + SA_SIGINFO = 0x0040 + + struct Sigval + # Actually a union of an int and a void* + _sival_ptr : Void* + end + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_pid : PidT + si_uid : UidT + si_status : Int + si_addr : Void* + si_value : Sigval + _pad1 : Long + _pad2 : StaticArray(Int, 7) + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + # Technically a union, but only one can be valid and we only use sa_sigaction + # and not sa_handler (which would be a SighandlerT) + sa_sigaction : SigactionHandlerT + sa_flags : Int + sa_mask : SigsetT + end + + struct StackT + ss_sp : Void* + ss_size : SizeT + ss_flags : Int + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-freebsd/c/signal.cr b/src/lib_c/x86_64-freebsd/c/signal.cr index 58ed84355d64..369153956b45 100644 --- a/src/lib_c/x86_64-freebsd/c/signal.cr +++ b/src/lib_c/x86_64-freebsd/c/signal.cr @@ -33,6 +33,7 @@ lib LibC SIGEMT = 7 SIGINFO = 29 SIGWINCH = 28 + SIGSTKSZ = 2048 + 32768 # MINSIGSTKSZ + 32768 SIG_SETMASK = 3 @@ -44,9 +45,48 @@ lib LibC bits : UInt32[4] end + SA_ONSTACK = 0x0001 + SA_SIGINFO = 0x0040 + + struct Sigval + # Actually a union of an int and a void* + _sival_ptr : Void* + end + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + si_pid : PidT + si_uid : UidT + si_status : Int + si_addr : Void* + si_value : Sigval + _pad1 : Long + _pad2 : StaticArray(Int, 7) + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + # Technically a union, but only one can be valid and we only use sa_sigaction + # and not sa_handler (which would be a SighandlerT) + sa_sigaction : SigactionHandlerT + sa_flags : Int + sa_mask : SigsetT + end + + struct StackT + ss_sp : Void* + ss_size : SizeT + ss_flags : Int + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-linux-gnu/c/signal.cr b/src/lib_c/x86_64-linux-gnu/c/signal.cr index 87d6a372ba3c..0556b55ae3e1 100644 --- a/src/lib_c/x86_64-linux-gnu/c/signal.cr +++ b/src/lib_c/x86_64-linux-gnu/c/signal.cr @@ -36,6 +36,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = 31 + SIGSTKSZ = 8192 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -46,9 +48,38 @@ lib LibC val : ULong[16] # (1024 / (8 * sizeof(ULong))) end + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + __pad0 : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad1 : StaticArray(Int, 20) # __SI_PAD_SIZE (28) - sizeof(void*) (8) = 20 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-linux-musl/c/signal.cr b/src/lib_c/x86_64-linux-musl/c/signal.cr index f13190050469..8b1b75bc0e94 100644 --- a/src/lib_c/x86_64-linux-musl/c/signal.cr +++ b/src/lib_c/x86_64-linux-musl/c/signal.cr @@ -35,6 +35,8 @@ lib LibC SIGSTKFLT = 16 SIGUNUSED = LibC::SIGSYS + SIGSTKSZ = 8192 + SIG_SETMASK = 2 alias SighandlerT = Int -> @@ -45,9 +47,38 @@ lib LibC bits : ULong[16] # 128 / sizeof(long) end + SA_ONSTACK = 0x08000000 + SA_SIGINFO = 0x00000004 + + struct SiginfoT + si_signo : Int + si_errno : Int + si_code : Int + __pad0 : Int + si_addr : Void* # Assuming the sigfault form of siginfo_t + __pad1 : StaticArray(Int, 20) # __SI_PAD_SIZE (28) - sizeof(void*) (8) = 20 + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + sa_sigaction : SigactionHandlerT + sa_mask : SigsetT + sa_flags : Int + sa_restorer : Void* + end + + struct StackT + ss_sp : Void* + ss_flags : Int + ss_size : SizeT + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-netbsd/c/signal.cr b/src/lib_c/x86_64-netbsd/c/signal.cr index a9d866834f17..501772cc3637 100644 --- a/src/lib_c/x86_64-netbsd/c/signal.cr +++ b/src/lib_c/x86_64-netbsd/c/signal.cr @@ -34,6 +34,8 @@ lib LibC SIGINFO = 29 SIGWINCH = 28 + SIGSTKSZ = 40960 + SIG_SETMASK = 3 alias SighandlerT = Int -> @@ -44,9 +46,39 @@ lib LibC bits : UInt32[4] end + SA_ONSTACK = 0x0001 + SA_SIGINFO = 0x0040 + + struct SiginfoT + si_signo : Int + si_code : Int + si_errno : Int + _pad1 : Int + si_addr : Void* + _pad2 : StaticArray(UInt64, 13) + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + # Technically a union, but only one can be valid and we only use sa_sigaction + # and not sa_handler (which would be a SighandlerT) + sa_sigaction : SigactionHandlerT + sa_flags : Int + sa_mask : SigsetT + end + + struct StackT + ss_sp : Void* + ss_size : SizeT + ss_flags : Int + end + fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction = __sigaction14(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack = __sigaltstack14(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset = __sigemptyset14(SigsetT*) : Int fun sigfillset = __sigfillset14(SigsetT*) : Int fun sigaddset = __sigaddset14(SigsetT*, Int) : Int diff --git a/src/lib_c/x86_64-openbsd/c/signal.cr b/src/lib_c/x86_64-openbsd/c/signal.cr index d28423d828a7..e96e5b75cdf3 100644 --- a/src/lib_c/x86_64-openbsd/c/signal.cr +++ b/src/lib_c/x86_64-openbsd/c/signal.cr @@ -34,6 +34,10 @@ lib LibC SIGINFO = 29 SIGWINCH = 28 + MAX_PAGE_SHIFT = 12_u32 + MINSIGSTKSZ = 3_u64 << LibC::MAX_PAGE_SHIFT + SIGSTKSZ = LibC::MINSIGSTKSZ + (1_u64 << LibC::MAX_PAGE_SHIFT) * 4 + SIG_SETMASK = 3 alias SighandlerT = Int -> @@ -42,6 +46,27 @@ lib LibC SIG_DFL = SighandlerT.new(Pointer(Void).new(0_u64), Pointer(Void).null) SIG_IGN = SighandlerT.new(Pointer(Void).new(1_u64), Pointer(Void).null) + SA_ONSTACK = 0x0001 + SA_SIGINFO = 0x0040 + + struct SiginfoT + si_signo : Int + si_code : Int + si_errno : Int + si_addr : Void* + _pad : StaticArray(UInt8, 108) + end + + alias SigactionHandlerT = (Int, SiginfoT*, Void*) -> + + struct Sigaction + # Technically a union, but only one can be valid and we only use sa_sigaction + # and not sa_handler (which would be a SighandlerT) + sa_sigaction : SigactionHandlerT + sa_flags : Int + sa_mask : SigsetT + end + struct StackT ss_sp : Void* ss_size : SizeT @@ -51,6 +76,8 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void + fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int + fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int fun sigemptyset(SigsetT*) : Int fun sigfillset(SigsetT*) : Int fun sigaddset(SigsetT*, Int) : Int diff --git a/src/prelude.cr b/src/prelude.cr index 5ccd0f959358..8b6f18377ac2 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -41,7 +41,6 @@ require "enum" require "enumerable" require "env" require "errno" -require "ext" require "file" require "float" require "gc" diff --git a/src/signal.cr b/src/signal.cr index ca2738cd4f62..ae9aa017dccb 100644 --- a/src/signal.cr +++ b/src/signal.cr @@ -123,6 +123,34 @@ enum Signal : Int32 end @@setup_default_handlers = Atomic::Flag.new + @@setup_segfault_handler = Atomic::Flag.new + @@segfault_handler = LibC::SigactionHandlerT.new { |sig, info, data| + # Capture fault signals (SEGV, BUS) and finish the process printing a backtrace first + + # Determine if the SEGV was inside or 'near' the top of the stack + # to check for potential stack overflow. 'Near' is a small + # amount larger than a typical stack frame, 4096 bytes here. + addr = info.value.si_addr + + is_stack_overflow = + begin + stack_top = Pointer(Void).new(Fiber.current.@stack.address - 4096) + stack_bottom = Fiber.current.@stack_bottom + stack_top <= addr < stack_bottom + rescue e + Crystal::System.print_error "Error while trying to determine if a stack overflow has occurred. Probable memory corruption\n" + false + end + + if is_stack_overflow + Crystal::System.print_error "Stack overflow (e.g., infinite or very deep recursion)\n" + else + Crystal::System.print_error "Invalid memory access (signal %d) at address 0x%lx\n", sig, addr + end + + Exception::CallStack.print_backtrace + LibC._exit(sig) + } # :nodoc: def self.setup_default_handlers @@ -132,6 +160,25 @@ enum Signal : Int32 Signal::PIPE.ignore Signal::CHLD.reset end + + # :nodoc: + def self.setup_segfault_handler + return unless @@setup_segfault_handler.test_and_set + + altstack = LibC::StackT.new + altstack.ss_sp = LibC.malloc(LibC::SIGSTKSZ) + altstack.ss_size = LibC::SIGSTKSZ + altstack.ss_flags = 0 + LibC.sigaltstack(pointerof(altstack), nil) + + action = LibC::Sigaction.new + action.sa_flags = LibC::SA_ONSTACK | LibC::SA_SIGINFO + action.sa_sigaction = @@segfault_handler + LibC.sigemptyset(pointerof(action.@sa_mask)) + + LibC.sigaction(SEGV, pointerof(action), nil) + LibC.sigaction(BUS, pointerof(action), nil) + end end # :nodoc: @@ -320,30 +367,3 @@ module Crystal::SignalChildHandler @@waiting.clear end end - -# :nodoc: -fun __crystal_sigfault_handler(sig : LibC::Int, addr : Void*) - # Capture fault signals (SEGV, BUS) and finish the process printing a backtrace first - - # Determine if the SEGV was inside or 'near' the top of the stack - # to check for potential stack overflow. 'Near' is a small - # amount larger than a typical stack frame, 4096 bytes here. - is_stack_overflow = - begin - stack_top = Pointer(Void).new(Fiber.current.@stack.address - 4096) - stack_bottom = Fiber.current.@stack_bottom - stack_top <= addr < stack_bottom - rescue e - Crystal::System.print_error "Error while trying to determine if a stack overflow has occurred. Probable memory corruption\n" - false - end - - if is_stack_overflow - Crystal::System.print_error "Stack overflow (e.g., infinite or very deep recursion)\n" - else - Crystal::System.print_error "Invalid memory access (signal %d) at address 0x%lx\n", sig, addr - end - - Exception::CallStack.print_backtrace - LibC._exit(sig) -end