Don't register EHFrameRegistrationPlugin on MachO (fixes #1782)#1783
Open
dg1sbg wants to merge 1 commit into
Open
Don't register EHFrameRegistrationPlugin on MachO (fixes #1782)#1783dg1sbg wants to merge 1 commit into
dg1sbg wants to merge 1 commit into
Conversation
This was referenced Jun 1, 2026
…pers#1782) On macOS/arm64, native (cleavir-compiled) code unwinds via compact-unwind (__TEXT,__unwind_info), not DWARF .eh_frame — clasp's native MachO objects carry no __eh_frame. ClaspJIT_O adds orc::EHFrameRegistrationPlugin to its ObjectLinkingLayer, but that plugin's MachO path inserts a front PrePrune pass that removes the __LD,__compact_unwind section (see LLVM EHFrameRegistrationPlugin.cpp). That deletes the only unwind info native code has, before JITLink's CompactUnwindManager can synthesize __TEXT,__unwind_info. libunwind is then left with no description for native PCs, so a C++ exception thrown below a native frame and caught above it cannot find its handler -> std::terminate -> abort. This is the long-standing clasp/cando macos-latest/native CI failure (mp PROCESS-ABORT). Fix: only add EHFrameRegistrationPlugin for non-MachO (ELF) targets. On MachO it has no eh-frame to register anyway, so its sole effect was deleting the compact-unwind. With it gone, the stock pipeline works: CompactUnwindManager synthesizes __unwind_info and the default platform's UnwindInfoRegistrationPlugin registers it with Apple libunwind, so C++ exceptions unwind across native frames again. Verified on Apple silicon (LLVM 22, boehmprecise native image): the mp regression suite passes (PROCESS-ABORT-1/2/3/5, PROCESS-EXIT); UnwindInfoManager::registerSectionsImpl now runs per loaded object (was never called before); no regressions in the unwind/conditions/control suites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f11b704 to
d96aef4
Compare
Member
|
I don't have an ARM Mac to test on right this second, and the CI is still reporting an unknown exception there. Though in the interrupt tests. I'll run it again and see what happens. |
Contributor
Author
|
With all PRs in, I just reran all tests here locally with
and get: No unhandled exceptions left ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The long-standing
clasp/candomacos-latest/native "Run regression tests" CI failure (#1782): thempregression suite reachesPROCESS-ABORT-1and the processstd::terminates instead of unwinding (startRunStop.cc:135 unhandled unknown exception→Abort signal). Ubuntu native and the bytecode image are unaffected — only the native image on arm64-darwin.Root cause
On macOS/arm64, native (cleavir-compiled) code unwinds via compact-unwind (
__TEXT,__unwind_info), not DWARF.eh_frame— clasp's native MachO objects carry no__eh_frame.ClaspJIT_Oaddsorc::EHFrameRegistrationPluginto itsObjectLinkingLayer. But that plugin's MachO path inserts a front PrePrune pass that removes the__LD,__compact_unwindsection:That deletes the only unwind info native code has, before JITLink's
CompactUnwindManagercan synthesize__TEXT,__unwind_info. libunwind is then left with no description for native PCs, so a C++ exception thrown below a native frame (mp::abort_process→throw AbortProcess()) and caught above it (Process_O::runInner) cannot find its handler →std::terminate→ abort.(For the record: the
__compact_unwindrecords are valid self-sufficientUNWIND_ARM64_MODE_FRAMEentries; the original "objects lack__eh_frame" framing was a red herring — they correctly lack it, and0x04000000isMODE_FRAMEon arm64, notMODE_DWARF.)Fix
Only add
EHFrameRegistrationPluginfor non-MachO (ELF) targets. On MachO it has no eh-frame to register anyway, so its sole effect was deleting the compact-unwind. With it gone, the stock pipeline works end-to-end:CompactUnwindManagersynthesizes__unwind_infoand the defaultsetUpGenericLLVMIRPlatform'sUnwindInfoRegistrationPluginregisters it with Apple libunwind. LLVM's own writer handles personality/LSDA, so landing-pad functions are covered too.Verification
Apple silicon, LLVM 22,
boehmprecisenative image:mpregression suite: 44 successes, 0 failures —PROCESS-ABORT-1/2/3/5andPROCESS-EXITpass (were aborting CI).mp:abort-processnow unwinds across native frames and signalsPROCESS-JOIN-ERROR(the documented behavior) instead ofstd::terminate.llvm::orc::UnwindInfoManager::registerSectionsImplnow runs per loaded object (15349×; was never called before); libunwind'sfindSectionsImplresolves during the throw.unwind/conditions/controlsuites.🤖 Generated with Claude Code