Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/crystal/system/unix/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ module Crystal::System::Signal
@@segfault_handler = LibC::SigactionHandlerT.new { |sig, info, data|
# Capture fault signals (SEGV, BUS) and finish the process printing a backtrace first

# This handler must not allocate memory via the GC! Expanding the heap or
# triggering a GC cycle here could geenrate another SEGV

# 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.
Expand Down
21 changes: 20 additions & 1 deletion src/exception/call_stack/libunwind.cr
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ struct Exception::CallStack
end
{% end %}

if frame = decode_frame(repeated_frame.ip)
if frame = unsafe_decode_frame(repeated_frame.ip)
offset, sname, fname = frame
Crystal::System.print_error "%s +%lld in %s", sname, offset.to_i64, fname
else
Expand Down Expand Up @@ -149,4 +149,23 @@ struct Exception::CallStack
{offset, symbol, file}
end
end

# variant of `.decode_frame` that returns the C strings directly instead of
# wrapping them in `String.new`, since the SIGSEGV handler cannot allocate
# memory via the GC
protected def self.unsafe_decode_frame(ip)
original_ip = ip
while LibC.dladdr(ip, out info) != 0
offset = original_ip - info.dli_saddr
if offset == 0
ip -= 1
next
end

return if info.dli_sname.null? && info.dli_fname.null?
symbol = info.dli_sname || "??".to_unsafe
file = info.dli_fname || "??".to_unsafe
return {offset, symbol, file}
end
end
end