mirror of
https://github.com/morluto/rea.git
synced 2026-11-08 07:46:28 +00:00
Keep independent Objective-C class, metaclass, category and protocol records when an adopted-protocol list is unreadable. The shared list reader retains readable prefixes through tagged Result failures; consumers preserve partial/unknown semantics with unchanged limits. Advance the source-owned reader commitment to v3 and reject stale v2 snapshot bindings. Validated with 232 focused tests, current-main and original-proposal RED checks, named provider-result/schema/identity controls, and a verified public GLFW Mach-O paired with independent LLVM/Python byte evidence. Ordinary binary results remain identical; a deliberately mutated count preserves ten rows instead of eight. The final head passes the real macOS CI lane, with twelve CLI tests including both new protocol-count cases over CLI and stdio MCP. Snapshot binding and same-version replay checks pass. The original unchecked human declarations are preserved. The explicit maintainer readiness exception applies after technical CI and automated review, without adding a human-review attestation. Fixes #8945 Full technical CI 42263548929 passes, including all eight shards and required aggregates. The Author readiness-only exception is explicitly authorized; no human-review attestation is added. Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
145 lines
4.7 KiB
TypeScript
145 lines
4.7 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { createHash } from "node:crypto";
|
|
import { join } from "node:path";
|
|
import { expect, it } from "vitest";
|
|
|
|
import { projectAnalysisError } from "../../../../src/domain/analysisErrorProjection.js";
|
|
import { NativeMacOSProvider } from "../../../../src/native/NativeMacOSProvider.js";
|
|
import { nativeDispatchMetadataResultSchema } from "../../../../src/domain/native/objcSwiftMetadata.js";
|
|
import {
|
|
NativeFixtureRunner,
|
|
nativeMachoTargetForFile,
|
|
} from "../../../fixtures/nativeCommands.js";
|
|
import {
|
|
objcAdoptedProtocolCountMacho,
|
|
objcRecordBudgetMacho,
|
|
} from "../../../fixtures/objcRecordBudgetMacho.js";
|
|
import { createTestTempDirectory } from "../../../fixtures/temporaryDirectory.js";
|
|
|
|
const sectionCases = [
|
|
{
|
|
section: "__objc_classlist",
|
|
size: 12,
|
|
reason: "Misaligned Objective-C class-list size",
|
|
},
|
|
{
|
|
section: "__objc_protolist",
|
|
size: 12,
|
|
reason: "Misaligned Objective-C protocol list",
|
|
},
|
|
{
|
|
section: "__objc_catlist",
|
|
size: 12,
|
|
reason: "Misaligned Objective-C category list",
|
|
},
|
|
{
|
|
section: "__swift5_types",
|
|
size: 6,
|
|
reason: "Misaligned Swift type section",
|
|
},
|
|
{
|
|
section: "__swift5_proto",
|
|
size: 6,
|
|
reason: "Misaligned Swift conformance section",
|
|
},
|
|
];
|
|
|
|
const inspect = async (bytes: Buffer) => {
|
|
const root = await createTestTempDirectory("rea-dispatch-format-");
|
|
const path = join(root, "fixture.macho");
|
|
await writeFile(path, bytes);
|
|
const client = new NativeMacOSProvider(
|
|
{},
|
|
new NativeFixtureRunner(),
|
|
"darwin",
|
|
).createClient(await nativeMachoTargetForFile(path));
|
|
try {
|
|
return {
|
|
path,
|
|
result: await client.execute("inspect_native_dispatch_metadata", {}),
|
|
};
|
|
} finally {
|
|
expect((await client.close()).ok).toBe(true);
|
|
}
|
|
};
|
|
|
|
it.each(sectionCases)(
|
|
"reports malformed $section bytes as a target refusal with the producing reason",
|
|
async ({ section, size, reason }) => {
|
|
const bytes = objcRecordBudgetMacho("class");
|
|
bytes.fill(0, 104, 120);
|
|
bytes.write(section, 104);
|
|
bytes.writeBigUInt64LE(BigInt(size), 144);
|
|
const { path, result } = await inspect(bytes);
|
|
expect(result.ok).toBe(false);
|
|
if (result.ok) throw new Error("Expected malformed target refusal");
|
|
expect(projectAnalysisError(result.error)).toMatchObject({
|
|
code: "unsupported_target",
|
|
category: "unsupported_target",
|
|
details: { operation: "inspect_native_dispatch_metadata", path, reason },
|
|
});
|
|
},
|
|
);
|
|
|
|
it("keeps an unsupported big-endian CPU declaration distinct from provider failure", async () => {
|
|
const bytes = Buffer.alloc(32);
|
|
bytes.writeUInt32BE(0xfeedfacf);
|
|
bytes.writeUInt32BE(0x0100000c, 4);
|
|
bytes.writeUInt32BE(2, 12);
|
|
const { path, result } = await inspect(bytes);
|
|
expect(result.ok).toBe(false);
|
|
if (result.ok) throw new Error("Expected unsupported target refusal");
|
|
expect(projectAnalysisError(result.error)).toMatchObject({
|
|
code: "unsupported_target",
|
|
category: "unsupported_target",
|
|
details: { path, reason: "Unsupported big-endian Mach-O CPU type" },
|
|
});
|
|
});
|
|
|
|
it("continues decoding the well-formed eight-byte class-list control", async () => {
|
|
const { result } = await inspect(objcRecordBudgetMacho("class"));
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) throw result.error;
|
|
expect(result.value.result).toMatchObject({
|
|
result: {
|
|
objc_classes: [expect.objectContaining({ name: "FixtureClass" })],
|
|
},
|
|
});
|
|
});
|
|
|
|
it.each([1n, 20001n])(
|
|
"retains class facts and source identity through provider delivery for protocol count %s",
|
|
async (count) => {
|
|
const bytes = objcAdoptedProtocolCountMacho(count);
|
|
const { result } = await inspect(bytes);
|
|
expect(result.ok).toBe(true);
|
|
if (!result.ok) throw result.error;
|
|
const report = nativeDispatchMetadataResultSchema.parse(
|
|
result.value.result,
|
|
);
|
|
expect(report.target_sha256).toBe(
|
|
createHash("sha256").update(bytes).digest("hex"),
|
|
);
|
|
expect(report.input_admission?.retained_bytes).toBe(bytes.length);
|
|
expect(report.result.objc_classes).toMatchObject([
|
|
{
|
|
name: "FixtureClass",
|
|
methods: [{ selector: "classMethod", method_type: "instance" }],
|
|
protocols: count === 1n ? ["FixtureProtocol"] : [],
|
|
decode:
|
|
count === 1n
|
|
? { status: "decoded", reason: null }
|
|
: { status: "partial", reason: "protocol_list_unreadable" },
|
|
},
|
|
]);
|
|
expect(report.result.objc_dispatch_implementations).toMatchObject([
|
|
{ class_name: "FixtureClass", selector: "classMethod" },
|
|
]);
|
|
expect(
|
|
report.result.coverage.find(
|
|
({ facet }) => facet === "objc_class_method_ivar_metadata",
|
|
)?.status,
|
|
).toBe(count === 1n ? "complete" : "partial");
|
|
},
|
|
);
|