From 002503d0c09171c1cc510b0e75c80eef9dfde60e Mon Sep 17 00:00:00 2001 From: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:33:27 +0000 Subject: [PATCH] fix(artifacts): qualify weak and lazy findings below conditional loaders Weak and lazy unresolved-load findings on edges whose loader loads only conditionally now say that they apply only if that loader loads, as the required-load finding already did. Co-Authored-By: Claude Opus 5.5 --- src/domain/apple/dylibResolution.test.ts | 21 ++++++++++++++++----- src/domain/apple/dylibResolutionFindings.ts | 13 ++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/domain/apple/dylibResolution.test.ts b/src/domain/apple/dylibResolution.test.ts index d778c6ff2..bfd0a25b5 100644 --- a/src/domain/apple/dylibResolution.test.ts +++ b/src/domain/apple/dylibResolution.test.ts @@ -564,7 +564,13 @@ describe("conditional loads", () => { [VENDOR]: parsed( slice({ install_name: "@rpath/libvendor.dylib", - dependencies: [dependency("@loader_path/libgone.dylib")], + dependencies: [ + dependency("@loader_path/libgone.dylib"), + dependency("@loader_path/libweak.dylib", { weak: true }), + dependency("@loader_path/liblazy.dylib", { + command: "LC_LAZY_LOAD_DYLIB", + }), + ], }), ), [OTHER]: parsed( @@ -586,9 +592,14 @@ describe("conditional loads", () => { resolution: { status: "conditional", image: VENDOR }, loader_conditional: false, }); - expect( - trace.findings.find(({ kind }) => kind === "required-load-unresolved") - ?.explanation, - ).toContain(`${VENDOR} loads only conditionally`); + // Required, weak and lazy findings below the fallback are all qualified. + for (const kind of [ + "required-load-unresolved", + "weak-load-unresolved", + "lazy-load-unresolved", + ]) + expect( + trace.findings.find((finding) => finding.kind === kind)?.explanation, + ).toContain(`${VENDOR} loads only conditionally; if it loads,`); }); }); diff --git a/src/domain/apple/dylibResolutionFindings.ts b/src/domain/apple/dylibResolutionFindings.ts index 069323eb1..109ad0f7f 100644 --- a/src/domain/apple/dylibResolutionFindings.ts +++ b/src/domain/apple/dylibResolutionFindings.ts @@ -57,24 +57,27 @@ const unresolvedFinding = (edge: Edge, index: number): Finding => { image: edge.loader, basis: "derived", } as const; + const missing = `No candidate for ${edge.command === "LC_LAZY_LOAD_DYLIB" ? "lazily loaded " : edge.weak ? "weak dependency " : ""}${edge.install_name} exists in the analyzed root`; + // Below a conditional fallback, every consequence applies only if it loads. + const when = edge.loader_conditional + ? `. ${edge.loader} loads only conditionally; if it loads, ` + : "; "; if (edge.command === "LC_LAZY_LOAD_DYLIB") return { ...base, kind: "lazy-load-unresolved", - explanation: `No candidate for lazily loaded ${edge.install_name} exists in the analyzed root; dyld loads it on first use, which would fail unless the image is supplied elsewhere.`, + explanation: `${missing}${when}dyld loads it on first use, which would fail unless the image is supplied elsewhere.`, }; return edge.weak ? { ...base, kind: "weak-load-unresolved", - explanation: `No candidate for weak dependency ${edge.install_name} exists in the analyzed root; dyld continues without it.`, + explanation: `${missing}${when}dyld continues without it.`, } : { ...base, kind: "required-load-unresolved", - explanation: edge.loader_conditional - ? `No candidate for ${edge.install_name} exists in the analyzed root. ${edge.loader} loads only conditionally; if it loads, dyld would fail to launch ${edge.root} (${edge.architecture}) unless the image is supplied elsewhere.` - : `No candidate for ${edge.install_name} exists in the analyzed root; dyld would fail to launch ${edge.root} (${edge.architecture}) unless the image is supplied elsewhere.`, + explanation: `${missing}${when}dyld would fail to launch ${edge.root} (${edge.architecture}) unless the image is supplied elsewhere.`, }; };