Skip to content

core: capture the host-arch slice of fat Xcode builds (R03 iOS crash) - #438

Merged
obj-p merged 1 commit into
mainfrom
xcode-capture-arch
Jul 21, 2026
Merged

core: capture the host-arch slice of fat Xcode builds (R03 iOS crash)#438
obj-p merged 1 commit into
mainfrom
xcode-capture-arch

Conversation

@obj-p

@obj-p obj-p commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Problem

A generic iOS Simulator xcodebuild destination has no active arch, so it builds every ARCHS slice and the build log carries one swift-frontend invocation per arch. XcodeCommandCapture.parse returned the first module match, which could be the x86_64 slice. The daemon then compiled the preview overlay to x86_64 and the arm64 JIT agent died with SIGILL executing an x86_64 prologue (55 48 89 e5). Deterministic on examples/regress/xcode-resources (R03's iOS half, regressed since the 2026-07-15 pass).

Fix (two layers)

  • XcodeCommandCapture.parse prefers the invocation whose -target triple matches the arch the agent runs as; log order no longer decides. A foreign-arch-only log still captures the first match.
  • stripForeignTargetTriple treats a foreign-arch triple as foreign (family match alone no longer keeps it), so Compiler's injected host-arch target wins for stale persisted captures without waiting for re-capture.
  • collectSourceFiles drops its hardcoded arm64 OutputFileMap path for hostArch, finishing the arch parameterization (clangObjects already used it).

Verification

  • Unit rows pin both layers: host-arch preference in either log order, first-foreign fallback, default hostArch wiring, no--target passthrough, -sdk-before--target ordering, foreign-arch/foreign-family strips, host keeps.
  • R03 iOS renders end to end again, twice: once with the stale x86_64 persisted capture (strip layer defuses it), once after deleting it (fresh capture now persists arm64-apple-ios26.2-simulator).
  • Gates: 4-angle /simplify (findings folded), 4-angle adversarial correctness review (no confirmed defects; one benign residue noted: foreign-arch -Xcc -I DerivedSources paths survive the strip — additive header search dirs, arch-guarded contents), both local tiers green, manual RegressToolGuardTests green, lint exit 0.

Alternative considered

Pinning the arch at the xcodebuild invocation (ARCHS=<hostArch>) would close the class at the root and halve frontend work, but changes the native build the user's products dir gets (thin instead of fat). Left as named future work; the read-side fix tolerates whatever the build emits.

🤖 Generated with Claude Code

A generic iOS Simulator destination builds every ARCHS slice, so the
build log carries one swift-frontend invocation per arch and the capture
could return the x86_64 one. The JIT then materialized x86_64 code in
the arm64 agent, which died with SIGILL executing an x86_64 prologue.

Two layers: XcodeCommandCapture.parse prefers the invocation whose
-target matches the arch the agent runs as (log order no longer
decides), and stripForeignTargetTriple treats a foreign-arch triple as
foreign so Compiler's injected target wins for stale persisted captures.

Verified: unit rows on both layers; R03 iOS renders again end-to-end,
first with the stale x86_64 persisted capture (strip layer) and then
with a fresh capture that now persists arm64 (parse layer).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@obj-p obj-p added the merge Run CI and auto-merge (squash) on success label Jul 21, 2026
@obj-p
obj-p enabled auto-merge (squash) July 21, 2026 17:51
@obj-p
obj-p merged commit 1609bae into main Jul 21, 2026
3 checks passed
@obj-p
obj-p deleted the xcode-capture-arch branch July 21, 2026 18:10
obj-p added a commit that referenced this pull request Jul 21, 2026
…mily design (#439)

* docs: re-verify B04/R02/R03 on main ahead of resource-staging family

B04 unchanged. R02's blank framebuffer is gone; its Spanish assertion is
a fixture defect (String(localized:locale:) cannot select an lproj).
R03 macOS unchanged; iOS regressed to an agent SIGILL — the Xcode
build-log capture takes an x86_64 simulator invocation that
stripForeignTargetTriple accepts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* examples: R02 Spanish assertion via explicit lproj sub-bundle; row closes

String(localized:bundle:locale:) does not select the .lproj (locale:
affects interpolation formatting only, proven natively against the
built bundle), so the 2026-07-15 fixture variant could never display
Spanish even against correct staging. The title now resolves through
the locale's .lproj sub-bundle with visible staging-failure states.
With the mechanism corrected, all R02 surfaces render Recursos
cargados (macOS control, iOS single-preview control, iOS index 1 after
a live switch) and the row flips to Guard passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* examples: B04 resource assertion via Bundle(for:); row closes

Bundle.allFrameworks never lists a framework without ObjC classes
(proven natively with a dlopen control), and the JSON sat under
Resources/ in a flat iOS framework whose resource directory is the
wrapper root. DynamicBadge gains an ObjC marker class, the payload
moves to the framework root, and the preview resolves through
Bundle(for:) with distinct failure states. With the mechanism
corrected the iOS snapshot renders the payload — the EPC-dlopened
framework serves its internal resource, so B04 flips to Guard passes.
B02's combined render re-verified after the artifact change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: jit-bundle-resolution family design; R03 row updated post-#438

The resource-staging cluster dissolved under re-verification: R02 and
B04 were fixture-mechanism defects, R03's iOS crash was the fat-build
capture bug (#438). The one genuine gap is Bundle(for:) on JIT-compiled
classes resolving to the agent image while only Generated*Symbols.swift
gets the #151 wrapper rewrite. Design: an agent-side bundleForClass:
hook keyed on class_getImageName == NULL, wrapper path plumbed from
CODESIGNING_FOLDER_PATH; stage 2 retires the text rewrite. Amendments
from adversarial review with native experiments folded: dladdr is
unsound as the discriminator in a Swift process, and imageless
JIT-linked SwiftPM package classes are a documented, gated limitation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: fold branch-gate review findings

Drop rebase-orphaned commit SHAs from the design doc (cite rows
instead), list B04's failure states by stage rather than an incomplete
enumeration, and correct the DynamicBadge README's rationale — the
marker anchors Bundle(for:), while the allFrameworks ObjC requirement
is a separate fact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge Run CI and auto-merge (squash) on success

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant