Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement segfault handler in Crystal #10463

Merged
merged 6 commits into from
Apr 8, 2021

Conversation

maxfierke
Copy link
Contributor

@maxfierke maxfierke commented Mar 2, 2021

Resolves #3839

Required adding some C bindings for various signal structures,
based on rust's fairly comprehensive libc bindings.

This removes the need to build and link a separate C library and
reduces the complexity of cross-compiling (at build-time), with
some added complexity when porting to a new platform.

siginfo_t can be fairly complex, involving large context-dependent
unions that vary across architecture and platform. In Crystal's
case, we only care about the segfault version of the structure,
so we omit the others.

Opening as draft first for feedback before more thoroughly verifying on all supported platforms. Tier 1 platforms verified so far. will take some time to get to the BSDs, etc.

  • Tier I
    • All verified (CI)
  • Tier 2 (manual)
    • DragonFly BSD
      • No available ports. Ran into issues cross-compiling (different LLVM versions available, libressl instead of openssl), but validated that siginfo_t bindings look correct
    • FreeBSD (12.0)
      • std_spec hangs on io_spec but completes the segfault handler tests fine
    • NetBSD
      • Ports has too old a version to compile Crystal master, but based on reading their libc source, siginfo_t bindings look correct.
    • OpenBSD
      • Ports only has Crystal 0.30.1 which is too old to compile Crystal master, and ran into issues cross-compiling. However, can verify the siginfo_t bindings seem correct (at least on releases from summer 2017 forward)

Required adding some C bindings for various signal structures,
based on rust's fairly comprehensive libc bindings.

This removes the need to build and link a separate C library and
reduces the complexity of cross-compiling (at build-time), with
some added complexity when porting to a new platform.

`siginfo_t` can be fairly complex, involving large context-dependent
unions that vary across architecture and platform. In Crystal's
case, we only care about the segfault version of the structure,
so we omit the others.
si_addr was erroneously char* on OpenBSD < 2017
but has since been fixed (openbsd/src@91587a9)
@maxfierke maxfierke marked this pull request as ready for review March 5, 2021 16:47
Copy link
Member

@straight-shoota straight-shoota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks really great and should surely help avoid some friction with distribution packages and cross-compiling.

src/signal.cr Outdated Show resolved Hide resolved
src/signal.cr Outdated Show resolved Hide resolved
src/signal.cr Outdated Show resolved Hide resolved
src/signal.cr Outdated Show resolved Hide resolved
src/signal.cr Outdated Show resolved Hide resolved
src/signal.cr Outdated Show resolved Hide resolved
@straight-shoota
Copy link
Member

This requires an update to https://github.com/crystal-lang/distribution-scripts/ after merging.

@maxfierke
Copy link
Contributor Author

@straight-shoota is this something that could be slotted in for 1.1.0? I'd be happy to create a PR for the distribution-scripts work to support it, if that's something that's possible for someone outside the core team to do.

@straight-shoota
Copy link
Member

We still need a second core team member to review and approve this PR.

Contributions to distribution-scripts are welcome 👍

src/signal.cr Outdated
@@ -56,6 +56,7 @@ enum Signal : Int32
USR1 = LibC::SIGUSR1
USR2 = LibC::SIGUSR2
WINCH = LibC::SIGWINCH
STKSZ = LibC::SIGSTKSZ
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be exposed in Singal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would guess probably not, unless there's a reason to expose stack size to users, but it's not clear to me whether we consider LibC bindings to be considered public API, and not clear whether sigaltstack and other functions for working with stacks would be relevant to most, if any, users. So I'll probably update this to avoid exposing STKSZ on Signal

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LibC bindings are not public API. They are there to be used by the standard library. Users can use LibC, but in most cases they shouldn't need to.

So yes, for now let's not add it to Signal's public API. We could always add it later if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great! addressed in 786c7d9

Copy link
Member

@asterite asterite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is GREAT! I just left a small question.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, but would it be helpful to print the name of the signal? In my experience the number is hard to understand. Perhaps something like:

Suggested change
Crystal::System.print_error "Invalid memory access (signal %d) at address 0x%lx\n", sig, addr
Crystal::System.print_error "Invalid memory access (signal %d: SIG%s) at address 0x%lx\n", sig, Signal.new(sig), addr

@asterite asterite added this to the 1.1.0 milestone Apr 8, 2021
@asterite asterite merged commit a5014ed into crystal-lang:master Apr 8, 2021
dentarg added a commit to 84codes/sparoid that referenced this pull request Jul 27, 2021
I noticed that CI failed because it couldn't find 1.0.0:
https://github.com/84codes/sparoid/runs/3166205736?check_suite_focus=true#step:3:48

Apparently their new repo ("openSUSE Build Service") will only host the latest release:
crystal-lang/crystal#10949 (comment)

...but there's no Docker image for 1.1.1 right now.

Also no need to compile src/ext/sigfault.c since crystal-lang/crystal#10463
carlhoerberg pushed a commit to 84codes/sparoid that referenced this pull request Jul 28, 2021
I noticed that CI failed because it couldn't find 1.0.0:
https://github.com/84codes/sparoid/runs/3166205736?check_suite_focus=true#step:3:48

Apparently their new repo ("openSUSE Build Service") will only host the latest release:
crystal-lang/crystal#10949 (comment)

...but there's no Docker image for 1.1.1 right now.

Also no need to compile src/ext/sigfault.c since crystal-lang/crystal#10463
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rewrite sigfault.c in Crystal
4 participants