Skip to content

ci(macos): drop -undefined dynamic_lookup from macOS linker flags#293

Merged
smunini merged 1 commit into
mainfrom
fix/macos-dyld-undefined-dynamic-lookup
Jul 17, 2026
Merged

ci(macos): drop -undefined dynamic_lookup from macOS linker flags#293
smunini merged 1 commit into
mainfrom
fix/macos-dyld-undefined-dynamic-lookup

Conversation

@smunini

@smunini smunini commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Problem

The macOS test-rust job (and other self-hosted-runner jobs) intermittently abort at runtime — not at compile time — with:

dyld cache '(null)' not loaded: syscall to map cache into shared region failed
dyld[…]: Library not loaded: /System/Library/Frameworks/SystemConfiguration.framework/…
  Reason: tried: '…/SystemConfiguration' (no such file, no dyld cache)
process didn't exit successfully: … (signal: 6, SIGABRT)

Observed on PR #244: https://github.com/HeliosSoftware/hfs/actions/runs/29596368102/job/87937639611

Root cause

The "Configure Rust linker (macOS)" step wrote these rustflags into ~/.cargo/config.toml:

["-C","link-arg=-Wl,-dead_strip","-C","link-arg=-undefined","-C","link-arg=dynamic_lookup"]

-undefined dynamic_lookup is a loadable-bundle linker mode — it is not valid for executables or test binaries. On Apple Silicon it yields Mach-O binaries dyld cannot map against the shared cache, which surfaces as syscall to map cache into shared region failed. That then cascades into "SystemConfiguration.framework not loaded", because that framework only exists inside the dyld shared cache on modern macOS — once the cache fails to map, any binary referencing it (here helios-rest, via reqwest) aborts with SIGABRT.

Introduced in 52ec228e6 ("Removed lld for macOS"). Linux and Windows link fine with no equivalent flag, confirming it was never needed.

Fix

Replace the flags in all 6 jobs with just the 8 MB main-thread stack bump that mirrors the Linux config, and add a comment so the bad flag does not return:

rustflags = ["-C", "link-arg=-Wl,-stack_size,0x800000"]

Note

This crash class can also appear intermittently on self-hosted Apple Silicon runners due to shared-region map exhaustion across many uniquely-signed binaries in a single boot. Removing the bad flag is the correct, highest-leverage fix; if sporadic "map cache into shared region failed" persists afterward, that points to runner-host state (cleared by a reboot), independent of this workflow bug.

https://claude.ai/code/session_01Vnu2A87mWaKnbeFuWZSwkd

The macOS "Configure Rust linker" step wrote
`-undefined dynamic_lookup` (plus `-dead_strip`) into the cargo
rustflags. `-undefined dynamic_lookup` is a loadable-bundle linker
mode and is invalid for executables/test binaries. On Apple Silicon
it produces Mach-O binaries dyld cannot map against the shared cache,
surfacing at runtime as:

    dyld cache '(null)' not loaded: syscall to map cache into shared region failed
    Library not loaded: .../SystemConfiguration.framework (no dyld cache)
    process ... (signal: 6, SIGABRT)

SystemConfiguration.framework only lives inside the dyld shared cache
on modern macOS, so once the cache fails to map, any binary that
references it (helios-rest, via reqwest) aborts. Linux and Windows
link fine without this flag; it was never needed.

Replace the flags in all six jobs with just the 8 MB main-thread
stack bump that mirrors the Linux config, and add a comment so the
bad flag does not come back.

Claude-Session: https://claude.ai/code/session_01Vnu2A87mWaKnbeFuWZSwkd
@smunini
smunini merged commit 1db0033 into main Jul 17, 2026
3 checks passed
@smunini
smunini deleted the fix/macos-dyld-undefined-dynamic-lookup branch July 17, 2026 17:44
smunini added a commit that referenced this pull request Jul 17, 2026
Follow-up to #293. Replacing `-undefined dynamic_lookup` with
`-Wl,-stack_size,0x800000` fixed the dyld crash but introduced a new
build failure: ld64 rejects `-stack_size` on any link that is not a
main executable —

    ld: -stack_size option can only be used when linking a main executable

cargo applies rustflags to every link invocation, including
proc-macro/cdylib crates (e.g. serde_derive, linked `-dynamiclib`),
so the flag fails the build before any test runs. On Linux the
equivalent `-zstack-size` is silently accepted for shared objects,
which is why it was never caught there.

macOS already defaults the main-thread stack to 8 MB — the same value
the Linux side sets explicitly — so no override is needed. Drop the
custom rustflags on macOS entirely.

Claude-Session: https://claude.ai/code/session_01Vnu2A87mWaKnbeFuWZSwkd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant