diff --git a/Docs/generation.md b/Docs/generation.md index e6df7ae..da56bae 100644 --- a/Docs/generation.md +++ b/Docs/generation.md @@ -153,8 +153,10 @@ list, regular member-table entry, root entry, or loaded class/category relationship preserves its readable siblings and produces a typed degradation; unloaded relative lists are skipped without warning. These guarantees cover structural table, list, and layout ranges; they do not validate referenced C -strings or loaded class RW-extension arrays. Once that target is published, -PrivateHeaderKit reports the precise owner and degradation as an +strings. MachOObjCSection's public loaded class RW-extension list-array queries +now apply the same bounded structural reads, although PrivateHeaderKit's current +raw dump does not query that dependency surface. When a queried target is +degraded, PrivateHeaderKit reports the precise owner and degradation as an `objc-metadata-warning` and persists the warning in `generation.sqlite`. A bounded diagnostics report records when additional warnings were omitted, so malformed metadata cannot grow process output without limit. Live warning diff --git a/Package.resolved b/Package.resolved index c9c2268..847bda4 100644 --- a/Package.resolved +++ b/Package.resolved @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/lynnswap/MachOObjCSection.git", "state" : { - "revision" : "8f0ff76f02c0865422a72662177b5e687e43522d" + "revision" : "cc9a70f46d69683882dedce7d6d293a565e7863a" } }, { @@ -67,7 +67,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/lynnswap/MachOSwiftSection.git", "state" : { - "revision" : "06ed57ab39fc24956f9079beeb407fffa30d50f4" + "revision" : "905703af9d192c778054417a1a5052a26051cc96" } }, { diff --git a/Package.swift b/Package.swift index a0d2693..718e912 100644 --- a/Package.swift +++ b/Package.swift @@ -37,7 +37,7 @@ let package = Package( ), .package( url: "https://github.com/lynnswap/MachOObjCSection.git", - revision: "8f0ff76f02c0865422a72662177b5e687e43522d" + revision: "cc9a70f46d69683882dedce7d6d293a565e7863a" ), .package( url: "https://github.com/MxIris-Reverse-Engineering/swift-objc-dump.git", @@ -45,7 +45,7 @@ let package = Package( ), .package( url: "https://github.com/lynnswap/MachOSwiftSection.git", - revision: "06ed57ab39fc24956f9079beeb407fffa30d50f4" + revision: "905703af9d192c778054417a1a5052a26051cc96" ), .package( url: "https://github.com/MxIris-Reverse-Engineering/swift-demangling", diff --git a/Sources/PrivateHeaderKitRawDumpCore/RawDumpObjCDiagnostics.swift b/Sources/PrivateHeaderKitRawDumpCore/RawDumpObjCDiagnostics.swift index bbfeee3..477087c 100644 --- a/Sources/PrivateHeaderKitRawDumpCore/RawDumpObjCDiagnostics.swift +++ b/Sources/PrivateHeaderKitRawDumpCore/RawDumpObjCDiagnostics.swift @@ -268,7 +268,7 @@ private func privateHeaderKitDiagnostic( ) } -private func rawDumpMetadataTableDiagnostic( +func rawDumpMetadataTableDiagnostic( owner: ObjCMetadataTableDiagnostic.Owner, site: ObjCMetadataTableDiagnostic.Site, failure: ObjCMetadataTableDiagnostic.Failure @@ -289,6 +289,11 @@ private func rawDumpMetadataTableDiagnostic( metadataDescription = "\(pointerWidthDescription(pointerWidth))" + " \(rootSectionDescription(section)) root table" + case let .loadedRWExtension(kind, pointerWidth): + ownerDescription = "Objective-C loaded RW-extension list arrays" + metadataDescription = + "\(pointerWidthDescription(pointerWidth))" + + " \(rwExtensionListKindDescription(kind)) list array" case let .loadedRelationship(subject, role): ownerDescription = subjectDescription(subject) metadataDescription = "\(loadedRelationshipDescription(role)) relationship" @@ -363,6 +368,16 @@ private func pointerWidthDescription( } } +private func rwExtensionListKindDescription( + _ kind: ObjCMetadataTableDiagnostic.RWExtensionListKind +) -> String { + switch kind { + case .method: "method" + case .property: "property" + case .protocol: "protocol" + } +} + private func loadedRelationshipDescription( _ role: ObjCMetadataTableDiagnostic.LoadedRelationshipRole ) -> String { @@ -690,5 +705,7 @@ private func failureDescription( case let .invalidEntryArithmetic(baseAddress, targetAddress): "target address \(targetAddress) cannot be represented relative" + " to base address \(baseAddress)" + case .relativeImageUnavailable(let imageIndex): + "cache image index \(imageIndex) is unavailable" } } diff --git a/Tests/PrivateHeaderKitHelperProtocolTests/PrivateHeaderKitHelperProtocolTests.swift b/Tests/PrivateHeaderKitHelperProtocolTests/PrivateHeaderKitHelperProtocolTests.swift index 7443cc2..1062683 100644 --- a/Tests/PrivateHeaderKitHelperProtocolTests/PrivateHeaderKitHelperProtocolTests.swift +++ b/Tests/PrivateHeaderKitHelperProtocolTests/PrivateHeaderKitHelperProtocolTests.swift @@ -292,7 +292,7 @@ struct PrivateHeaderKitHelperProtocolTests { let state = try #require(pin["state"] as? [String: Any]) #expect(pin["location"] as? String == "https://github.com/lynnswap/MachOObjCSection.git") - #expect(state["revision"] as? String == "8f0ff76f02c0865422a72662177b5e687e43522d") + #expect(state["revision"] as? String == "cc9a70f46d69683882dedce7d6d293a565e7863a") #expect(state["version"] == nil) let swiftSectionPin = try #require( @@ -307,7 +307,7 @@ struct PrivateHeaderKitHelperProtocolTests { ) #expect( swiftSectionState["revision"] as? String - == "06ed57ab39fc24956f9079beeb407fffa30d50f4" + == "905703af9d192c778054417a1a5052a26051cc96" ) #expect(swiftSectionState["version"] == nil) diff --git a/Tests/PrivateHeaderKitRawDumpTests/ObjCMemberListDiagnosticsTests.swift b/Tests/PrivateHeaderKitRawDumpTests/ObjCMemberListDiagnosticsTests.swift index 307a794..6a5dd45 100644 --- a/Tests/PrivateHeaderKitRawDumpTests/ObjCMemberListDiagnosticsTests.swift +++ b/Tests/PrivateHeaderKitRawDumpTests/ObjCMemberListDiagnosticsTests.swift @@ -56,6 +56,40 @@ struct ObjCMemberListDiagnosticsTests { ) } + @Test func loadedRWExtensionDiagnosticsKeepKindWidthAndUnavailableImage() throws { + let fixture = try InvalidFileRootFixture() + let seedDiagnostic = try #require( + fixture.machO.objc.readRoots().tableDiagnostics.first + ) + let cases: [( + ObjCMetadataTableDiagnostic.RWExtensionListKind, + ObjCMetadataTableDiagnostic.PointerWidth, + String + )] = [ + (.method, .bits64, "64-bit method"), + (.property, .bits32, "32-bit property"), + (.protocol, .bits64, "64-bit protocol"), + ] + + for (kind, pointerWidth, prefix) in cases { + let record = rawDumpMetadataTableDiagnostic( + owner: .loadedRWExtension( + kind: kind, + pointerWidth: pointerWidth + ), + site: seedDiagnostic.site, + failure: .relativeImageUnavailable(imageIndex: 1_194) + ) + + #expect(record.owner == "Objective-C loaded RW-extension list arrays") + #expect( + record.degradation + == "\(prefix) list array could not be fully read:" + + " cache image index 1194 is unavailable" + ) + } + } + @Test func wholeTableFailureKeepsMemberKindAndOuterOffset() { let record = rawDumpMemberListDiagnostic( className: "Owner",