From 75ed7e6baca02d884af9941ac0002d517aa331bc Mon Sep 17 00:00:00 2001 From: Dmitri Goutnik Date: Tue, 18 Oct 2022 10:41:11 -0500 Subject: [PATCH] Exception::CallStack: avoid allocations in LibC.dl_iterate_phdr callback Calling self.read_dwarf_sections directly from the C callback may lead to reallocations and deadlocks due to the internal lock held by dl_iterate_phdr (#10084). Work around this by storing object base address and passing it to self.read_dwarf_sections later when dl_iterate_phdr returns. This also fixes #12329 because there's no need to disable GC around dl_iterate_phdr anymore. --- src/exception/call_stack/elf.cr | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/exception/call_stack/elf.cr b/src/exception/call_stack/elf.cr index cdedae66dd42..6bcaf5eec2b7 100644 --- a/src/exception/call_stack/elf.cr +++ b/src/exception/call_stack/elf.cr @@ -5,16 +5,19 @@ require "crystal/elf" struct Exception::CallStack protected def self.load_debug_info_impl + base_address : LibC::Elf_Addr = 0 phdr_callback = LibC::DlPhdrCallback.new do |info, size, data| - # The first entry is the header for the current program - read_dwarf_sections(info.value.addr) + # The first entry is the header for the current program. + # Note that we avoid allocating here and just store the base address + # to be passed to self.read_dwarf_sections when dl_iterate_phdr returns. + # Calling self.read_dwarf_sections from this callback may lead to reallocations + # and deadlocks due to the internal lock held by dl_iterate_phdr (#10084). + data.as(Pointer(LibC::Elf_Addr)).value = info.value.addr 1 end - # GC needs to be disabled around dl_iterate_phdr in freebsd (#10084) - {% if flag?(:freebsd) %} GC.disable {% end %} - LibC.dl_iterate_phdr(phdr_callback, nil) - {% if flag?(:freebsd) %} GC.enable {% end %} + LibC.dl_iterate_phdr(phdr_callback, pointerof(base_address)) + self.read_dwarf_sections(base_address) end protected def self.read_dwarf_sections(base_address = 0)