fix(native): retain command cleanup across source finalization (#10009)

This commit is contained in:
morluto authored and GitHub committed 2026-11-11 17:20:14 +08:00
1 parent 12a32d934a
commit e7c4a26316
3 files changed
+432 -8

No files matched your search

+77 -6
View File
@@ -1055,6 +1055,19 @@ class NativeMacOSClient implements AnalysisClient {
// Verify failed captures too: a disappearing target is not a codesign
// execution failure, and later captures must never use another version.
const after = await verifySignatureTarget(this.target, binding, signal);
if (!capture.ok && !after.ok) {
const primary =
after.error instanceof AnalysisCancelledError
? analysisErrorWithCancellation(capture.error, after.error)
: after.error;
return err(
nativeFailureWithCommandCleanup(
primary,
capture.error,
"inspect_signature",
),
);
}
return after.ok ? capture : after;
}
@@ -1817,6 +1830,7 @@ const nativeMachoCompletion = (
: new AnalysisCancelledError(operation, {
cause: completion.cancellation.reason,
...(completedFailure === undefined ||
completedFailure.cleanupIncomplete ||
(cause instanceof ArtifactReaderFailure &&
cause.cleanup !== undefined)
? {}
@@ -1831,6 +1845,40 @@ const nativeMachoCompletion = (
return { observation, completedFailure, completionCancellation };
};
/** Every native reclassification retains the command and independent file owners. */
const nativeFailureWithCommandCleanup = (
primary: AnalysisError,
producer: AnalysisError,
operation: string,
descriptorCleanup?: AnalysisError,
): AnalysisError => {
if (!producer.cleanupIncomplete) return primary;
const cleanup = descriptorCleanup ?? producer;
return cleanup === primary
? primary
: analysisErrorWithCleanupFailure(
primary,
cleanup,
operation,
).bindCleanupDependencies([
primary,
producer,
...(descriptorCleanup === undefined ? [] : [descriptorCleanup]),
]);
};
/** The exact callback error remains an owner even if verification reclassifies it. */
const nativeMachoProducerFailure = (
cause: unknown,
): AnalysisError | undefined => {
if (cause instanceof AnalysisError) return cause;
if (!(cause instanceof NativeMachoSourceVerificationFailure))
return undefined;
return cause.outcome.kind === "failed"
? nativeMachoProducerFailure(cause.outcome.cause)
: nativeMachoCompletedFailure(cause.outcome.value);
};
const nativeMachoSourceFailure = (
cause: unknown,
target: BinaryTarget,
@@ -1839,6 +1887,31 @@ const nativeMachoSourceFailure = (
): AnalysisError => {
const { observation, completedFailure, completionCancellation } =
nativeMachoCompletion(cause, target, parameters, operation);
const source = artifactFilePrimaryFacts(cause);
const producerFailure =
completedFailure ?? nativeMachoProducerFailure(source.cause);
// Classification and ownership are independent: neither a changed source nor
// a released descriptor settles the command's retained cleanup capability.
const retainOwnedCleanup = (
selected: AnalysisError,
descriptorCleanup?: AnalysisError,
): AnalysisError => {
if (!producerFailure?.cleanupIncomplete) return selected;
const primary =
selected === descriptorCleanup
? (descriptorCleanup.cleanupPrimary ?? producerFailure)
: selected === completionCancellation
? producerFailure
: selected;
if (completionCancellation !== undefined)
analysisErrorWithCancellation(primary, completionCancellation);
return nativeFailureWithCommandCleanup(
primary,
producerFailure,
operation,
descriptorCleanup,
);
};
if (cause instanceof ArtifactReaderFailure && cause.cleanup !== undefined) {
const physical =
cause instanceof ArtifactFileCleanupFailure
@@ -1887,17 +1960,15 @@ const nativeMachoSourceFailure = (
if (observation !== undefined)
completionCancellation?.retainPartialObservation(observation);
bindArtifactFileCleanup(cause, failure);
return failure;
return retainOwnedCleanup(failure, failure);
}
if (completionCancellation !== undefined) {
if (observation !== undefined)
completionCancellation.retainPartialObservation(observation);
return completionCancellation;
return retainOwnedCleanup(completionCancellation);
}
return nativeMachoSourcePrimary(
artifactFilePrimaryFacts(cause),
target.path,
operation,
return retainOwnedCleanup(
nativeMachoSourcePrimary(source, target.path, operation),
);
};