[GH-ISSUE #3981] [Bug] Overlapping DOS relocations produce a false load-image mismatch #1576

Closed
opened 2026-10-16 21:07:21 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 15, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/3981

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

An admitted DOS MZ image with two overlapping relocation words receives status: "mismatch" from inspect_native_load_image even when the observations describe the correct fully relocated bytes. In the executed simulated-provider MCP case, every check except relocation_records matched. The comparison expects an intermediate word that a later relocation has changed.

Reproduction

  1. In the baseline checkout with its locked dependencies installed, save the following probe as src/ghidra/loadImageReproduction.test.ts. It constructs a DOS MZ image whose 48-byte header contains relocation records for module offsets 9 then 8. Both original words are zero. The probe computes the final bytes and digests independently, supplies the observations through a simulated provider client, then calls the registered MCP tools.
import { createHash } from "node:crypto";
import { writeFile, rm } from "node:fs/promises";
import { join } from "node:path";
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { expect, it } from "vitest";
import { fixtureDosLoadImage } from "./GhidraLoadImage.fixture.js";
import { GhidraProvider } from "./GhidraProvider.js";
import { GHIDRA_SESSION_CAPABILITIES } from "./GhidraSessionValues.js";
import { parseConfig } from "../config/parseConfig.js";
import { parseDosMzHeader } from "../domain/dosMz.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
import { ok } from "../domain/result.js";
import { silentLogger } from "../logger.js";
import { AnalysisProviderRegistry } from "../application/binary/AnalysisProviderRegistry.js";
import { composeBinarySession } from "../application/binary/BinarySessionComposition.js";
import { createServer } from "../server/createServer.js";

const hash = (bytes: Buffer) => createHash("sha256").update(bytes).digest("hex");
it("compares final loaded bytes through the public MCP operation", async () => {
  const fixture = fixtureDosLoadImage();
  const bytes = Buffer.concat([Buffer.alloc(16), fixture.bytes]);
  fixture.bytes.copy(bytes, 0, 0, 28);
  bytes.fill(0, 28, 48);
  bytes.writeUInt16LE(bytes.length - 23, 2);
  bytes.writeUInt16LE(3, 8);
  bytes.writeUInt16LE(2, 6);
  bytes.writeUInt16LE(9, 28);
  bytes.writeUInt16LE(8, 32);
  bytes.fill(0, 56, 59);
  expect(parseDosMzHeader(bytes)).toMatchObject({ok: true, value: {
    headerBytes: 48, moduleBytes: 128, overlayBytes: 23, relocationCount: 2,
  }});
  const modified = Buffer.from(bytes);
  // Apply the two in-place DOS additions in relocation-table order.
  for (const offset of [9, 8]) {
    const at = 48 + offset;
    modified.writeUInt16LE((modified.readUInt16LE(at) + 0x1000) & 0xffff, at);
  }
  expect(modified.subarray(56, 59).toString("hex")).toBe("001010");
  const observation = structuredClone(fixture.observation);
  Object.assign(observation.source_files[0], {
    size: bytes.length, original_sha256: hash(bytes), modified_sha256: hash(modified),
  });
  Object.assign(observation.mappings[0], {
    length: 48, end: "HEADER:0x2f", sha256: hash(bytes.subarray(0, 48)),
  });
  Object.assign(observation.mappings[1], {
    file_offset: 48, sha256: hash(modified.subarray(48, 176)),
  });
  observation.relocations = [9, 8].map((offset) => ({
    address: `0x${(0x10000 + offset).toString(16)}`, segment: 0x1000, offset,
    status: "APPLIED", type: 0, values: [0, offset, 0x1000],
    original_bytes_hex: "0000",
    memory_bytes_hex: modified.subarray(48 + offset, 50 + offset).toString("hex"),
  }));
  const config = parseConfig({ GHIDRA_INSTALL_DIR: "/opt/ghidra_12.1.4_PUBLIC" });
  if (!config.ok) throw config.error;
  const provider = new GhidraProvider(config.value, silentLogger, {}, {
    platform: "linux", architecture: "x64",
    readText: () => "application.version=12.1.4\napplication.java.min=21\n",
    executable: () => true,
    probeJava: () => ({ osArch: "amd64", osName: "Linux", version: "21.0.11",
      major: 21, home: "/usr/lib/jvm/jdk-21", bits: 64, runtime: "jdk",
      vmName: "OpenJDK 64-Bit Server VM" }),
  }, () => ({
    start: () => Promise.resolve(ok({
      name: "REA Ghidra bridge", run_id: "11111111-1111-4111-8111-111111111111",
      profile_digest: "a".repeat(64), provider: { id: "ghidra", version: "12.1.4" },
      read_only: false, analysis_complete: true, analysis_timed_out: false,
      capabilities: [...GHIDRA_SESSION_CAPABILITIES],
      target: { name: "fixture", language_id: "x86:LE:16:Real Mode",
        compiler_spec_id: "default", image_base: "0x0",
        default_address_space: "ram", sha256: hash(bytes) },
    })),
    callTool: () => Promise.resolve(ok(jsonValueSchema.parse(observation))),
    readTargetSnapshot: () => Promise.resolve(ok({kind: "captured", bytes})),
    close: () => Promise.resolve(ok(null)),
  }));
  const session = composeBinarySession(new AnalysisProviderRegistry([provider]));
  const server = createServer({kind: "session", session}, {logger: silentLogger});
  const mcp = new Client({name: "load-image-reproduction", version: "1.0.0"});
  const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
  const target = join(process.env.HOME!, "overlap.exe");
  await writeFile(target, bytes);
  try {
    await server.connect(serverTransport);
    await mcp.connect(clientTransport);
    const opened = await mcp.callTool({name: "open_binary", arguments: {
      path: target, provider_id: "ghidra",
    }});
    expect(opened.isError).not.toBe(true);
    const result = await mcp.callTool({name: "inspect_native_load_image", arguments: {}});
    expect(result.isError).not.toBe(true);
    const image = (result.structuredContent as any).normalized_result;
    const failed = image.checks.filter((row: any) => !row.matched);
    console.log(JSON.stringify({case: "final-memory", status: image.status, failed}));
    expect(image.status).toBe("mismatch");
    expect(failed.map((row: any) => row.name)).toEqual(["relocation_records"]);
    // Discriminate the issue from other mismatching fields in this fake observation.
    observation.relocations[0]!.memory_bytes_hex = "0010";
    const intermediate = await mcp.callTool({name: "inspect_native_load_image", arguments: {}});
    const control = (intermediate.structuredContent as any).normalized_result;
    console.log(JSON.stringify({case: "intermediate-memory-control", status: control.status}));
    expect(control.status).toBe("verified");
  } finally {
    await mcp.close();
    await server.close();
    await session.close();
    await rm(target, {force: true});
  }
});
  1. Run the focused probe with an isolated home directory, then remove the probe and its disposable home. The probe ran under an equivalent temporary filename and isolated home. These commands require no Ghidra process or external service.
repro_home="$(mktemp -d)"
HOME="$repro_home" npx vitest run src/ghidra/loadImageReproduction.test.ts
rm src/ghidra/loadImageReproduction.test.ts
rm -rf "$repro_home"
  1. Read the final-memory output. The open_binary call succeeds with provider_id: "ghidra". The inspect_native_load_image call with {} succeeds as an MCP request but reports status: "mismatch" with only relocation_records unmatched. The control changes only the first relocation observation to the intermediate memory word; that second call reports verified.

Expected behavior

For the admitted DOS MZ image, independent load-image verification should return verified when the snapshot identity, complete modified bytes, mappings, external entry and both relocation records agree with the final loaded Program. Each relocation record's memory window must correspond to the current loaded bytes, including changes made by later overlapping relocations. Multiplicity and both distinct relocation addresses must remain visible.

Impact and scope

A bounded DOS MZ input gives an incorrect independent attestation result despite matching complete final-file and mapping digests. The reproduced failure concerns load-image evidence; ordinary disassembly, executable integrity and runtime execution were not shown to fail.

Raw observations are returned, but no alternative independent attestation for the same unchanged image was demonstrated. Substituting the intermediate observation makes the records disagree with final loaded memory, so that control is not a valid workaround.

REA version

rea 6.5.0 at source commit 4692bb3330

Runtime and platform

Node 24.18.0; macOS arm64

Target and artifact context

Generated DOS MZ fixture; two in-bounds relocation words at module offsets 9 then 8; simulated Ghidra observations.

Interface

MCP

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

  • Expected source: docs/ghidra-dos.md:118, "Loaded-image evidence", promises independent comparison against the loaded Program, including relocation fixups and records with multiplicity. src/contracts/officialToolContracts.ts:46 registers the empty-input operation for DOS MZ; docs/mcp-contracts.md:11 identifies the normalized MCP result field.
  • Failure source: The executed production MCP probe above returned the sole failed check relocation_records. src/ghidra/GhidraLoadImageValues.ts:41 captures expected memory words during sequential relocation application. bridge/ghidra/ReaGhidraBridge.java:648 enumerates records and reads each current Program memory window at line 669.

The probe asserts that the parser admits the exact image and that its final bytes are 001010. Production open_binary also admitted it, and the registered inspection tool reached the Ghidra adapter and attestation. Source inspection at src/domain/dosMz.ts:159 confirms that relocation validation checks the module extent without rejecting overlap. The fake replaces engine observations and snapshot acquisition; it does not replace the session, attestation or MCP result path. The bridge read timing was inspected in source rather than measured in a real Ghidra process.

The executed MCP case returned mismatch. Applying the relocation at offset 9 writes 00 10 at offsets 9 and 10. Applying the next at offset 8 writes 00 10 at offsets 8 and 9. Final module bytes 8 through 10 are therefore 00 10 10, so the first record's final memory window is 10 10. The failing check instead expected 00 10 for that record. All whole-file and mapping digests matched the final relocated buffer.

The observed output reduces to:

{
  "case": "final-memory",
  "status": "mismatch",
  "failed_checks": ["relocation_records"],
  "address": "0x10009",
  "expected_memory_bytes_hex": "0010",
  "observed_memory_bytes_hex": "1010"
}

As a discriminating control, replacing only the first record's observation with "0010" produced status: "verified", while the source and mapping digests still described the final relocated buffer. The focused probe passed once with both calls asserted. The existing load-image test file also passed all 38 tests. This establishes the adapter's comparison behavior with the simulated observations; the real bridge's current-memory semantics are source-derived. It does not establish source-file mutation, incorrect DOS execution, or a real-engine loader failure.

Typed outcome or recovery expected

With the same source image and final-memory observations, the public MCP request should return verified and all checks should match. The deliberately intermediate 0010 first-record observation must fail the relocation check because its final memory window is 1010. Keep both records and their addresses, and preserve rejection of an actually incorrect modified-file digest or mapping digest. Dropping a record, ignoring relocation windows or rejecting the previously admitted image would not restore the documented verification contract.

Analysis or suspected cause

The source references above explain the observed behavior. Runtime claims are limited to the explicitly described simulation boundaries.

Additional context

Runtime claims above describe the supplied local reproduction at the baseline commit. Real-provider frequency remains unmeasured.

The relevant failure code is unchanged on current origin/main fc712b3750.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3981 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior An admitted DOS MZ image with two overlapping relocation words receives `status: "mismatch"` from `inspect_native_load_image` even when the observations describe the correct fully relocated bytes. In the executed simulated-provider MCP case, every check except `relocation_records` matched. The comparison expects an intermediate word that a later relocation has changed. ### Reproduction 1. In the baseline checkout with its locked dependencies installed, save the following probe as `src/ghidra/loadImageReproduction.test.ts`. It constructs a DOS MZ image whose 48-byte header contains relocation records for module offsets 9 then 8. Both original words are zero. The probe computes the final bytes and digests independently, supplies the observations through a simulated provider client, then calls the registered MCP tools. ```ts import { createHash } from "node:crypto"; import { writeFile, rm } from "node:fs/promises"; import { join } from "node:path"; import { Client, InMemoryTransport } from "@modelcontextprotocol/client"; import { expect, it } from "vitest"; import { fixtureDosLoadImage } from "./GhidraLoadImage.fixture.js"; import { GhidraProvider } from "./GhidraProvider.js"; import { GHIDRA_SESSION_CAPABILITIES } from "./GhidraSessionValues.js"; import { parseConfig } from "../config/parseConfig.js"; import { parseDosMzHeader } from "../domain/dosMz.js"; import { jsonValueSchema } from "../domain/jsonValue.js"; import { ok } from "../domain/result.js"; import { silentLogger } from "../logger.js"; import { AnalysisProviderRegistry } from "../application/binary/AnalysisProviderRegistry.js"; import { composeBinarySession } from "../application/binary/BinarySessionComposition.js"; import { createServer } from "../server/createServer.js"; const hash = (bytes: Buffer) => createHash("sha256").update(bytes).digest("hex"); it("compares final loaded bytes through the public MCP operation", async () => { const fixture = fixtureDosLoadImage(); const bytes = Buffer.concat([Buffer.alloc(16), fixture.bytes]); fixture.bytes.copy(bytes, 0, 0, 28); bytes.fill(0, 28, 48); bytes.writeUInt16LE(bytes.length - 23, 2); bytes.writeUInt16LE(3, 8); bytes.writeUInt16LE(2, 6); bytes.writeUInt16LE(9, 28); bytes.writeUInt16LE(8, 32); bytes.fill(0, 56, 59); expect(parseDosMzHeader(bytes)).toMatchObject({ok: true, value: { headerBytes: 48, moduleBytes: 128, overlayBytes: 23, relocationCount: 2, }}); const modified = Buffer.from(bytes); // Apply the two in-place DOS additions in relocation-table order. for (const offset of [9, 8]) { const at = 48 + offset; modified.writeUInt16LE((modified.readUInt16LE(at) + 0x1000) & 0xffff, at); } expect(modified.subarray(56, 59).toString("hex")).toBe("001010"); const observation = structuredClone(fixture.observation); Object.assign(observation.source_files[0], { size: bytes.length, original_sha256: hash(bytes), modified_sha256: hash(modified), }); Object.assign(observation.mappings[0], { length: 48, end: "HEADER:0x2f", sha256: hash(bytes.subarray(0, 48)), }); Object.assign(observation.mappings[1], { file_offset: 48, sha256: hash(modified.subarray(48, 176)), }); observation.relocations = [9, 8].map((offset) => ({ address: `0x${(0x10000 + offset).toString(16)}`, segment: 0x1000, offset, status: "APPLIED", type: 0, values: [0, offset, 0x1000], original_bytes_hex: "0000", memory_bytes_hex: modified.subarray(48 + offset, 50 + offset).toString("hex"), })); const config = parseConfig({ GHIDRA_INSTALL_DIR: "/opt/ghidra_12.1.4_PUBLIC" }); if (!config.ok) throw config.error; const provider = new GhidraProvider(config.value, silentLogger, {}, { platform: "linux", architecture: "x64", readText: () => "application.version=12.1.4\napplication.java.min=21\n", executable: () => true, probeJava: () => ({ osArch: "amd64", osName: "Linux", version: "21.0.11", major: 21, home: "/usr/lib/jvm/jdk-21", bits: 64, runtime: "jdk", vmName: "OpenJDK 64-Bit Server VM" }), }, () => ({ start: () => Promise.resolve(ok({ name: "REA Ghidra bridge", run_id: "11111111-1111-4111-8111-111111111111", profile_digest: "a".repeat(64), provider: { id: "ghidra", version: "12.1.4" }, read_only: false, analysis_complete: true, analysis_timed_out: false, capabilities: [...GHIDRA_SESSION_CAPABILITIES], target: { name: "fixture", language_id: "x86:LE:16:Real Mode", compiler_spec_id: "default", image_base: "0x0", default_address_space: "ram", sha256: hash(bytes) }, })), callTool: () => Promise.resolve(ok(jsonValueSchema.parse(observation))), readTargetSnapshot: () => Promise.resolve(ok({kind: "captured", bytes})), close: () => Promise.resolve(ok(null)), })); const session = composeBinarySession(new AnalysisProviderRegistry([provider])); const server = createServer({kind: "session", session}, {logger: silentLogger}); const mcp = new Client({name: "load-image-reproduction", version: "1.0.0"}); const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); const target = join(process.env.HOME!, "overlap.exe"); await writeFile(target, bytes); try { await server.connect(serverTransport); await mcp.connect(clientTransport); const opened = await mcp.callTool({name: "open_binary", arguments: { path: target, provider_id: "ghidra", }}); expect(opened.isError).not.toBe(true); const result = await mcp.callTool({name: "inspect_native_load_image", arguments: {}}); expect(result.isError).not.toBe(true); const image = (result.structuredContent as any).normalized_result; const failed = image.checks.filter((row: any) => !row.matched); console.log(JSON.stringify({case: "final-memory", status: image.status, failed})); expect(image.status).toBe("mismatch"); expect(failed.map((row: any) => row.name)).toEqual(["relocation_records"]); // Discriminate the issue from other mismatching fields in this fake observation. observation.relocations[0]!.memory_bytes_hex = "0010"; const intermediate = await mcp.callTool({name: "inspect_native_load_image", arguments: {}}); const control = (intermediate.structuredContent as any).normalized_result; console.log(JSON.stringify({case: "intermediate-memory-control", status: control.status})); expect(control.status).toBe("verified"); } finally { await mcp.close(); await server.close(); await session.close(); await rm(target, {force: true}); } }); ``` 2. Run the focused probe with an isolated home directory, then remove the probe and its disposable home. The probe ran under an equivalent temporary filename and isolated home. These commands require no Ghidra process or external service. ```sh repro_home="$(mktemp -d)" HOME="$repro_home" npx vitest run src/ghidra/loadImageReproduction.test.ts rm src/ghidra/loadImageReproduction.test.ts rm -rf "$repro_home" ``` 3. Read the `final-memory` output. The `open_binary` call succeeds with `provider_id: "ghidra"`. The `inspect_native_load_image` call with `{}` succeeds as an MCP request but reports `status: "mismatch"` with only `relocation_records` unmatched. The control changes only the first relocation observation to the intermediate memory word; that second call reports `verified`. ### Expected behavior For the admitted DOS MZ image, independent load-image verification should return `verified` when the snapshot identity, complete modified bytes, mappings, external entry and both relocation records agree with the final loaded Program. Each relocation record's memory window must correspond to the current loaded bytes, including changes made by later overlapping relocations. Multiplicity and both distinct relocation addresses must remain visible. ### Impact and scope A bounded DOS MZ input gives an incorrect independent attestation result despite matching complete final-file and mapping digests. The reproduced failure concerns load-image evidence; ordinary disassembly, executable integrity and runtime execution were not shown to fail. Raw observations are returned, but no alternative independent attestation for the same unchanged image was demonstrated. Substituting the intermediate observation makes the records disagree with final loaded memory, so that control is not a valid workaround. ### REA version rea 6.5.0 at source commit 4692bb33300c7cb77b095b6cc0c33da861c1b860 ### Runtime and platform Node 24.18.0; macOS arm64 ### Target and artifact context Generated DOS MZ fixture; two in-bounds relocation words at module offsets 9 then 8; simulated Ghidra observations. ### Interface MCP ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence - Expected source: `docs/ghidra-dos.md:118`, "Loaded-image evidence", promises independent comparison against the loaded Program, including relocation fixups and records with multiplicity. `src/contracts/officialToolContracts.ts:46` registers the empty-input operation for DOS MZ; `docs/mcp-contracts.md:11` identifies the normalized MCP result field. - Failure source: The executed production MCP probe above returned the sole failed check `relocation_records`. `src/ghidra/GhidraLoadImageValues.ts:41` captures expected memory words during sequential relocation application. `bridge/ghidra/ReaGhidraBridge.java:648` enumerates records and reads each current Program memory window at line 669. The probe asserts that the parser admits the exact image and that its final bytes are `001010`. Production `open_binary` also admitted it, and the registered inspection tool reached the Ghidra adapter and attestation. Source inspection at `src/domain/dosMz.ts:159` confirms that relocation validation checks the module extent without rejecting overlap. The fake replaces engine observations and snapshot acquisition; it does not replace the session, attestation or MCP result path. The bridge read timing was inspected in source rather than measured in a real Ghidra process. The executed MCP case returned `mismatch`. Applying the relocation at offset 9 writes `00 10` at offsets 9 and 10. Applying the next at offset 8 writes `00 10` at offsets 8 and 9. Final module bytes 8 through 10 are therefore `00 10 10`, so the first record's final memory window is `10 10`. The failing check instead expected `00 10` for that record. All whole-file and mapping digests matched the final relocated buffer. The observed output reduces to: ```json { "case": "final-memory", "status": "mismatch", "failed_checks": ["relocation_records"], "address": "0x10009", "expected_memory_bytes_hex": "0010", "observed_memory_bytes_hex": "1010" } ``` As a discriminating control, replacing only the first record's observation with `"0010"` produced `status: "verified"`, while the source and mapping digests still described the final relocated buffer. The focused probe passed once with both calls asserted. The existing load-image test file also passed all 38 tests. This establishes the adapter's comparison behavior with the simulated observations; the real bridge's current-memory semantics are source-derived. It does not establish source-file mutation, incorrect DOS execution, or a real-engine loader failure. ### Typed outcome or recovery expected With the same source image and final-memory observations, the public MCP request should return `verified` and all checks should match. The deliberately intermediate `0010` first-record observation must fail the relocation check because its final memory window is `1010`. Keep both records and their addresses, and preserve rejection of an actually incorrect modified-file digest or mapping digest. Dropping a record, ignoring relocation windows or rejecting the previously admitted image would not restore the documented verification contract. ### Analysis or suspected cause The source references above explain the observed behavior. Runtime claims are limited to the explicitly described simulation boundaries. ### Additional context Runtime claims above describe the supplied local reproduction at the baseline commit. Real-provider frequency remains unmeasured. The relevant failure code is unchanged on current `origin/main` fc712b3750cbe16755c4f78c1f90fdf09fbaca31.
Author
Owner

@morluto commented on GitHub (Oct 17, 2026):

Fixed on main in 969aafcf28, adapting @berelels' correction and authored control from #4156 to the prepared MZ image owner introduced by #4770.

The producer retains each fixup's pre-application bytes and applied value, then derives every memory window from the completed relocated image. Comparison also consumes the producer's load segment instead of defining it again. Only the MZ evidence profile advances, to independent-mz-mapping-relocations-v2.

At baseline 2f9b9c48b, two real-file controls failed: final windows produced mismatch, while a deliberately intermediate first word produced verified. Both are corrected. The final first window is 1410; the stale 0410 window now fails only relocation_records.

Rebased validation: 152 source/comparison/shared-MCP checks passed, 41 selected provider checks passed (81 deselected), and 14 lifecycle checks passed (74 deselected): 207 distinct focused checks. Static checks, runtime build and docs checks passed, including 5 README checks. Seven MCP overlap controls retain Evidence and distinguish stale windows, missing/duplicate records and unrelated source/mapping digest mismatches; record reordering is accepted. Two scoped source reviews found no blocker. The eight changed files and source-comparison dependencies remained byte-identical through rebase over 34239d445; affected checks were rerun.

Twelve completed normal source-comparison tasks (160-byte authored image, overlays 23/65,539 bytes, real descriptor reads) retained byte-identical full replies at 2199/2180 cl100k_base token estimates. Warm-repeat baseline/candidate medians:

Overlay bytes Elapsed seconds CPU seconds OS peak RSS bytes
23 0.060896 /0.061412 0.052596 /0.050825 70,508,544 /70,279,168
65,539 0.061261 /0.061238 0.053403 /0.051340 70,590,464 /70,369,280

Every task used a fresh Node process; first attempts were separated from two alternating repeats with existing OS caches. No true-cold or persistent-runtime-cache claim. One Node process/no children: wait4 peak RSS represents its process-family peak; periodic samples were incomplete. These tiny samples establish no speed or memory improvement. Full public provider/Evidence replies intentionally change profile revision and were not the performance comparison. Whole-agent/catalog tokens, real engines, maximal relocation counts, large inputs and failure-path costs remain unmeasured.

No real Ghidra/target execution was performed here. #4156's reported real-engine observations remain the PR author's evidence. Pinned Ghidra 12.1.4 MzLoader source uses original-file fixup values and HashSet iteration; loader/model differences for other overlap orders or duplicate source relocations remain separate and can correctly produce mismatches. This correction preserves cumulative DOS comparison semantics. Heavy profiling/stress remains stopped.

<!-- gh-comment-id:6233388912 --> @morluto commented on GitHub (Oct 17, 2026): Fixed on main in 969aafcf28b20599e34e47a11c06863aee06f15b, adapting @berelels' correction and authored control from #4156 to the prepared MZ image owner introduced by #4770. The producer retains each fixup's pre-application bytes and applied value, then derives every memory window from the completed relocated image. Comparison also consumes the producer's load segment instead of defining it again. Only the MZ evidence profile advances, to `independent-mz-mapping-relocations-v2`. At baseline 2f9b9c48b, two real-file controls failed: final windows produced `mismatch`, while a deliberately intermediate first word produced `verified`. Both are corrected. The final first window is `1410`; the stale `0410` window now fails only `relocation_records`. Rebased validation: 152 source/comparison/shared-MCP checks passed, 41 selected provider checks passed (81 deselected), and 14 lifecycle checks passed (74 deselected): 207 distinct focused checks. Static checks, runtime build and docs checks passed, including 5 README checks. Seven MCP overlap controls retain Evidence and distinguish stale windows, missing/duplicate records and unrelated source/mapping digest mismatches; record reordering is accepted. Two scoped source reviews found no blocker. The eight changed files and source-comparison dependencies remained byte-identical through rebase over 34239d445; affected checks were rerun. Twelve completed normal source-comparison tasks (160-byte authored image, overlays 23/65,539 bytes, real descriptor reads) retained byte-identical full replies at 2199/2180 cl100k_base token estimates. Warm-repeat baseline/candidate medians: | Overlay bytes | Elapsed seconds | CPU seconds | OS peak RSS bytes | |---|---|---|---| |23|0.060896 /0.061412|0.052596 /0.050825|70,508,544 /70,279,168| |65,539|0.061261 /0.061238|0.053403 /0.051340|70,590,464 /70,369,280| Every task used a fresh Node process; first attempts were separated from two alternating repeats with existing OS caches. No true-cold or persistent-runtime-cache claim. One Node process/no children: wait4 peak RSS represents its process-family peak; periodic samples were incomplete. These tiny samples establish no speed or memory improvement. Full public provider/Evidence replies intentionally change profile revision and were not the performance comparison. Whole-agent/catalog tokens, real engines, maximal relocation counts, large inputs and failure-path costs remain unmeasured. No real Ghidra/target execution was performed here. #4156's reported real-engine observations remain the PR author's evidence. Pinned [Ghidra 12.1.4 MzLoader source](https://github.com/NationalSecurityAgency/ghidra/blob/Ghidra_12.1.4_build/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java#L424) uses original-file fixup values and HashSet iteration; loader/model differences for other overlap orders or duplicate source relocations remain separate and can correctly produce mismatches. This correction preserves cumulative DOS comparison semantics. Heavy profiling/stress remains stopped.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1576
No description provided.