fix(native): preserve source attribution and compiler ownership
This commit is contained in:
parent
60c34b6907
commit
b576b347b1
|
|
@ -4,7 +4,6 @@ import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|||
import { tmpdir } from "node:os";
|
||||
import { isAbsolute, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
import {
|
||||
artifactCli,
|
||||
|
|
@ -12,7 +11,44 @@ import {
|
|||
withArtifactMcp,
|
||||
} from "./lib/artifact-e2e.mjs";
|
||||
|
||||
const execute = promisify(execFile);
|
||||
const execute = (command, arguments_, { timeout }) =>
|
||||
new Promise((resolve, reject) => {
|
||||
let timedOut = false;
|
||||
const child = execFile(
|
||||
command,
|
||||
arguments_,
|
||||
{ detached: true, encoding: "utf8" },
|
||||
(error, stdout, stderr) => {
|
||||
clearTimeout(deadline);
|
||||
if (timedOut) {
|
||||
const failure = new Error(`Command timed out after ${timeout} ms`);
|
||||
Object.assign(failure, {
|
||||
code: "ETIMEDOUT",
|
||||
killed: true,
|
||||
signal: "SIGKILL",
|
||||
stdout,
|
||||
stderr,
|
||||
});
|
||||
reject(failure);
|
||||
} else if (error !== null) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve({ stdout, stderr });
|
||||
}
|
||||
},
|
||||
);
|
||||
const deadline = setTimeout(() => {
|
||||
timedOut = true;
|
||||
if (child.pid === undefined) return;
|
||||
try {
|
||||
// This script only runs on macOS. detached:true gives the owned
|
||||
// compiler invocation its own process group, inherited by FPC tools.
|
||||
process.kill(-child.pid, "SIGKILL");
|
||||
} catch (cause) {
|
||||
if (cause.code !== "ESRCH") child.kill("SIGKILL");
|
||||
}
|
||||
}, timeout);
|
||||
});
|
||||
const compiler = process.env.REA_VERIFY_FPC_COMMAND;
|
||||
if (process.platform !== "darwin" || !isAbsolute(compiler ?? ""))
|
||||
throw new Error(
|
||||
|
|
@ -79,12 +115,11 @@ const stable = (result) =>
|
|||
}));
|
||||
try {
|
||||
const version = (
|
||||
await execute(compiler, ["-iV"], { timeout: 30_000, killSignal: "SIGKILL" })
|
||||
await execute(compiler, ["-iV"], { timeout: 30_000 })
|
||||
).stdout.trim();
|
||||
const architecture = (
|
||||
await execute(compiler, ["-iTP"], {
|
||||
timeout: 30_000,
|
||||
killSignal: "SIGKILL",
|
||||
})
|
||||
).stdout.trim();
|
||||
await execute(
|
||||
|
|
@ -98,7 +133,7 @@ try {
|
|||
`-FU${directory}`,
|
||||
source,
|
||||
],
|
||||
{ timeout: 120_000, killSignal: "SIGKILL" },
|
||||
{ timeout: 120_000 },
|
||||
);
|
||||
const binary = join(directory, "calls");
|
||||
const cli = await artifactCli(
|
||||
|
|
|
|||
|
|
@ -122,7 +122,10 @@ export const nativeCodeLocationSchema = z.strictObject({
|
|||
column: z.number().int().positive().nullable(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
.optional()
|
||||
.describe(
|
||||
"Compiler or debugger source attribution only; REA does not read or verify the named source-file bytes.",
|
||||
),
|
||||
});
|
||||
|
||||
/** One observed entry into a requested function or method. */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export const NATIVE_CALL_OBSERVATION_LIMITATIONS = [
|
|||
"Registers are the raw integer argument registers at entry. For Objective-C methods the first two hold the receiver and the selector.",
|
||||
"Receiver classes come from LLDB's Objective-C runtime reader without running target code; they are null for class methods and for receivers LLDB cannot classify.",
|
||||
"Calls that never reach a symbol's entry, such as inlined code or objc_direct methods called directly, are not observed.",
|
||||
"Source locations come from LLDB line-table metadata; REA does not read or verify the named source-file contents.",
|
||||
"The target is launched directly under LLDB, not through LaunchServices; LLDB disables ASLR for it, so load addresses can equal file addresses.",
|
||||
"The observation window is checked about once a second, and recording pauses the process at every entry, which slows it.",
|
||||
] as const;
|
||||
|
|
|
|||
Loading…
Reference in New Issue