fix(dyld): correct class-dump rsBase on iOS 15 (deadlock + bogus selectors)#1197
fix(dyld): correct class-dump rsBase on iOS 15 (deadlock + bogus selectors)#1197Lessica wants to merge 1 commit into
Conversation
The previous logic gated rsBase computation on objc opt version >= 16, which skipped the case where the cache uses the legacy ObjcOptT optimization header (typical for iOS 15 shared caches). As a result, class-dump produced relative method lists with a zero base address and emitted bogus selector offsets. Compute rsBase unconditionally from the optimization's relative method lists base address, and only add SharedRegionStart when the optimization is the new LargeSharedCache *ObjCOptimizationHeader* (which stores the base as a cache-relative offset). Apply the same correction to both the full GetMacho path and the GetPartialMacho path. Also persist objcOptRoAddr in getOptimizationsOld so the legacy code path resolves the correct __objc_opt_ro section address. Additionally, GetPartialMacho must not call GetOptimizations when the partial macho being parsed is libobjc.A.dylib itself: on iOS 15 the optimization lookup falls back to getOptimizationsOld() which calls getLibObjC() -> image.GetPartialMacho() on the very same libobjc image, re-entering f.objcOptOnce and deadlocking. Skip the rsBase resolution in that self-referential case (libobjc's own selectors do not require it at the partial-macho stage).
There was a problem hiding this comment.
Pull request overview
Fixes incorrect Objective-C relative selector resolution and a sync.Once re-entrancy deadlock when running class-dump against iOS 15 (and earlier) dyld shared caches.
Changes:
- Compute
rsBase(relative method-list base) for all objc optimization header versions and only applySharedRegionStartfor the LargeSharedCacheObjCOptimizationHeaderformat. - Prevent a deadlock in
GetPartialMachoby skipping optimization lookup when parsinglibobjc.A.dylibitself. - Persist
__objc_opt_rosection address (objcOptRoAddr) in the legacy optimization path.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| pkg/dyld/objc.go | Stores __objc_opt_ro VM address so legacy optimization offsets can be resolved correctly. |
| pkg/dyld/image.go | Fixes rsBase computation for iOS 15 legacy headers and avoids objcOptOnce re-entrancy deadlock for libobjc.A.dylib. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This PR cannot be safely merged. This is because I do not fully understand the AI-generated fix, even though it resolves the issue I encountered: successfully completing I created this PR simply to help others who are having trouble with this. I hope the author can help improve this PR. Thank you! |
Summary
Fix
class-dumpon iOS 15 (and earlier) shared caches. Refs #577.On iOS 15 DSCs the previous logic broke in two ways:
rsBase(the relative-method-list base) was only computed when theobjc-opt header version was
>= 16. iOS 15 caches still use the legacyObjcOptToptimization header, sorsBasestayed at0and everyrelative method-list selector resolved to a garbage address — class-dump
output looked fine but every selector name was wrong.
GetPartialMachoresolvesrsBaseviaGetOptimizations. Forlibobjc.A.dylibitself this re-enters the optimization lookup(
getOptimizationsOld→getLibObjC→image.GetPartialMachoon thesame image) and deadlocks on
f.objcOptOnce.Changes:
pkg/dyld/image.go: computersBaseunconditionally from theoptimization's relative-method-list base; only add
SharedRegionStartwhen the optimization is the LargeSharedCache
ObjCOptimizationHeader(which stores the base as a cache-relative offset). Apply the same
correction in both
GetMachoandGetPartialMacho. InGetPartialMachoalso skip the optimization lookup when the image being parsed is
libobjc.A.dylib, breaking the re-entrancy.pkg/dyld/objc.go: persistobjcOptRoAddringetOptimizationsOldsothe legacy code path resolves the correct
__objc_opt_rosectionaddress.
Testing
ipsw dyld class-dump --all <DSC>against the system DSC of each release:Spot-checked selector strings on iOS 15 against the on-device classes —
all correct after the fix (random garbage before).
AI Assistance
GitHub Copilot (Claude) helped narrow down the deadlock by tracing the
objcOptOncere-entry path and drafted the early-return for thelibobjc.A.dylibself-reference case. I personally reviewed every codechange, ran the five-version
class-dump --allmatrix above, andverified the resulting selectors against on-device class metadata before
opening this PR.