Skip to content

[Bug Report] GC Crash in Multithreaded Python Program Using @codon.convert Class + Python Object + ThreadPoolExecutor #773

@LeeLee26

Description

@LeeLee26

Problem Description

I encountered a GC crash (garbage collection segmentation fault) when running a multithreaded Python program using the Codon compiler. The crash occurs during concurrent execution with ThreadPoolExecutor and a @codon.convert decorated class.

Environment

  • OS: Debian GNU/Linux 12 (bookworm)
  • Codon version: 0.19.3 && the latest version 0.19.6 build from source (develop codon branch)
  • Python version: 3.11.10

Minimal Reproducible Code

import codon
from concurrent.futures import ThreadPoolExecutor

@codon.convert
class PyMockCPUBusy:
    __slots__ = ["compute_iters"]

    def __init__(self, compute_iters: int):
        self.compute_iters = compute_iters

    @codon.jit
    def __call__(self, obj):
        count = 0
        target = self.compute_iters
        while count < target:
            count += 1
        return obj
    
def worker(tid: int, op: PyMockCPUBusy):
    for i in range(20000):
        op(None)

if __name__ == "__main__":
  num_threads = 16
  op = PyMockCPUBusy(100000)

  with ThreadPoolExecutor(max_workers=num_threads) as ex:
    futures = [ex.submit(worker, tid, op) for tid in range(num_threads)]
    for f in futures:
        f.result()

How to Run

python3 test.py

Crash Frame

Collecting from unknown thread
Aborted (core dumped)
#0  0x00007fff4a360f12 in GC_find_limit_with_bound () from /data00/home/leelee/.codon/lib/codon/libcodonrt.so
#1  0x00007fff4a360d30 in GC_init_linux_data_start () from /data00/home/leelee/.codon/lib/codon/libcodonrt.so
#2  0x00007fff4a35efef in GC_init () from /data00/home/leelee/.codon/lib/codon/libcodonrt.so
#3  0x00007fff4a362218 in GC_add_roots () from /data00/home/leelee/.codon/lib/codon/libcodonrt.so
#4  0x00007fff4d86afb6 in codon::BoehmGCJITLinkMemoryManager::allocate(llvm::jitlink::JITLinkDylib const*, llvm::jitlink::LinkGraph&, llvm::unique_function<void (llvm::Expected<std::unique_ptr<llvm::jitlink::JITLinkMemoryManager::InFlightAlloc, std::default_delete<llvm::jitlink::JITLinkMemoryManager::InFlightAlloc> > >)>) ()
   from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#5  0x00007fff522874c2 in llvm::jitlink::JITLinkerBase::linkPhase1(std::unique_ptr<llvm::jitlink::JITLinkerBase, std::default_delete<llvm::jitlink::JITLinkerBase> >) ()
   from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#6  0x00007fff52263f58 in llvm::jitlink::link_ELF_x86_64(std::unique_ptr<llvm::jitlink::LinkGraph, std::default_delete<llvm::jitlink::LinkGraph> >, std::unique_ptr<llvm::jitlink::JITLinkContext, std::default_delete<llvm::jitlink::JITLinkContext> >) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#7  0x00007fff5222413a in llvm::jitlink::link_ELF(std::unique_ptr<llvm::jitlink::LinkGraph, std::default_delete<llvm::jitlink::LinkGraph> >, std::unique_ptr<llvm::jitlink::JITLinkContext, std::default_delete<llvm::jitlink::JITLinkContext> >) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#8  0x00007fff521ef75d in llvm::jitlink::link(std::unique_ptr<llvm::jitlink::LinkGraph, std::default_delete<llvm::jitlink::LinkGraph> >, std::unique_ptr<llvm::jitlink::JITLinkContext, std::default_delete<llvm::jitlink::JITLinkContext> >) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#9  0x00007fff50a31cc8 in llvm::orc::LinkGraphLinkingLayer::emit(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >, std::unique_ptr<llvm::jitlink::LinkGraph, std::default_delete<llvm::jitlink::LinkGraph> >, std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >) ()
   from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#10 0x00007fff50a81479 in llvm::orc::ObjectLinkingLayer::emit(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >, std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#11 0x00007fff50a81849 in llvm::orc::ObjectTransformLayer::emit(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >, std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#12 0x00007fff50ac76c3 in llvm::orc::IRCompileLayer::emit(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >, llvm::orc::ThreadSafeModule) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#13 0x00007fff50ac7f47 in llvm::orc::IRTransformLayer::emit(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >, llvm::orc::ThreadSafeModule) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#14 0x00007fff50ac7f47 in llvm::orc::IRTransformLayer::emit(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >, llvm::orc::ThreadSafeModule) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#15 0x00007fff50a28537 in llvm::orc::BasicIRLayerMaterializationUnit::materialize(std::unique_ptr<llvm::orc::MaterializationResponsibility, std::default_delete<llvm::orc::MaterializationResponsibility> >) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#16 0x00007fff509f1a8b in llvm::orc::MaterializationTask::run() () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#17 0x00007fff509f1e41 in llvm::orc::ExecutionSession::dispatchOutstandingMUs() () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#18 0x00007fff509f2f3d in llvm::orc::ExecutionSession::OL_completeLookup(std::unique_ptr<llvm::orc::InProgressLookupState, std::default_delete<llvm::orc::InProgressLookupState> >, std::shared_ptr<llvm::orc::AsynchronousSymbolQuery>, std::function<void (llvm::DenseMap<llvm::orc::JITDylib*, llvm::DenseSet<llvm::orc::SymbolStringPtr, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void> >, llvm::DenseMapInfo<llvm::orc::JITDylib*, void>, llvm::detail::DenseMapPair<llvm::orc::JITDylib*, llvm::DenseSet<llvm::orc::SymbolStringPtr, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void> > > > const&)>) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#19 0x00007fff509f3d33 in llvm::orc::InProgressFullLookupState::complete(std::unique_ptr<llvm::orc::InProgressLookupState, std::default_delete<llvm::orc::InProgressLookupState> >) ()
   from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#20 0x00007fff509f6c93 in llvm::orc::ExecutionSession::OL_applyQueryPhase1(std::unique_ptr<llvm::orc::InProgressLookupState, std::default_delete<llvm::orc::InProgressLookupState> >, llvm::Error) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#21 0x00007fff509f73f2 in llvm::orc::ExecutionSession::lookup(llvm::orc::LookupKind, std::vector<std::pair<llvm::orc::JITDylib*, llvm::orc::JITDylibLookupFlags>, std::allocator<std::p--Type <RET> for more, q to quit, c to continue without paging--
air<llvm::orc::JITDylib*, llvm::orc::JITDylibLookupFlags> > > const&, llvm::orc::SymbolLookupSet, llvm::orc::SymbolState, llvm::unique_function<void (llvm::Expected<llvm::DenseMap<llvm::orc::SymbolStringPtr, llvm::orc::ExecutorSymbolDef, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void>, llvm::detail::DenseMapPair<llvm::orc::SymbolStringPtr, llvm::orc::ExecutorSymbolDef> > >)>, std::function<void (llvm::DenseMap<llvm::orc::JITDylib*, llvm::DenseSet<llvm::orc::SymbolStringPtr, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void> >, llvm::DenseMapInfo<llvm::orc::JITDylib*, void>, llvm::detail::DenseMapPair<llvm::orc::JITDylib*, llvm::DenseSet<llvm::orc::SymbolStringPtr, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void> > > > const&)>) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#22 0x00007fff509f7601 in llvm::orc::ExecutionSession::lookup(std::vector<std::pair<llvm::orc::JITDylib*, llvm::orc::JITDylibLookupFlags>, std::allocator<std::pair<llvm::orc::JITDylib*, llvm::orc::JITDylibLookupFlags> > > const&, llvm::orc::SymbolLookupSet, llvm::orc::LookupKind, llvm::orc::SymbolState, std::function<void (llvm::DenseMap<llvm::orc::JITDylib*, llvm::DenseSet<llvm::orc::SymbolStringPtr, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void> >, llvm::DenseMapInfo<llvm::orc::JITDylib*, void>, llvm::detail::DenseMapPair<llvm::orc::JITDylib*, llvm::DenseSet<llvm::orc::SymbolStringPtr, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr, void> > > > const&)>) ()
   from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#23 0x00007fff509f83ce in llvm::orc::ExecutionSession::lookup(std::vector<std::pair<llvm::orc::JITDylib*, llvm::orc::JITDylibLookupFlags>, std::allocator<std::pair<llvm::orc::JITDylib*, llvm::orc::JITDylibLookupFlags> > > const&, llvm::orc::SymbolStringPtr, llvm::orc::SymbolState) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#24 0x00007fff50a45b66 in llvm::orc::LLJIT::lookupLinkerMangled(llvm::orc::JITDylib&, llvm::orc::SymbolStringPtr) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#25 0x00007fff4d847421 in llvm::orc::LLJIT::lookup(llvm::orc::JITDylib&, llvm::StringRef) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#26 0x00007fff4d845686 in codon::jit::Engine::lookup(llvm::StringRef) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#27 0x00007fff4d84bdf1 in codon::jit::JIT::init(bool) () from /data00/home/leelee/.codon/lib/codon/libcodonc.so
#28 0x00007fff4d84fb16 in jit_init () from /data00/home/leelee/.codon/lib/codon/libcodonc.so

Key Observations

  1. Crash only happens in multithreaded mode (ThreadPoolExecutor with ≥ 2 threads)
  2. Crash should Involves:
    • @codon.convert class
    • @codon.jit method
    • A PyObject Type param needs to be passed in
  3. The code is CPU-bound and does not perform any heap allocation inside the JIT loop

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions