mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
fix(apple): preserve line terminators in dyld path expansion (#5363)
Signed-off-by: 李永祺 <doribelove@gmail.com>
This commit is contained in:
@@ -87,7 +87,8 @@ export const expandPrefix = (
|
||||
readonly rootRelativePath: (absolutePath: string) => string | undefined;
|
||||
},
|
||||
): Expansion => {
|
||||
const variable = /^@(executable_path|loader_path)(?:\/(.*))?$/u.exec(raw);
|
||||
// Load-command paths can contain line terminators; the suffix is not a text line.
|
||||
const variable = /^@(executable_path|loader_path)(?:\/(.*))?$/su.exec(raw);
|
||||
if (variable !== null) {
|
||||
const rest = variable[2] ?? "";
|
||||
if (variable[1] === "loader_path")
|
||||
|
||||
@@ -109,6 +109,57 @@ const edgeFor = (
|
||||
return edge;
|
||||
};
|
||||
|
||||
it.each(["\n", "\r", "\r\n", "\u2028", "\u2029"])(
|
||||
"preserves line terminator %j in dependency names and rpaths",
|
||||
async (separator) => {
|
||||
const direct = `lib${separator}direct.dylib`;
|
||||
const fromExecutable = `libexecutable.dylib${separator}`;
|
||||
const directory = `Libraries${separator}Nested`;
|
||||
const trace = await traceDylibLoading(
|
||||
memoryView({
|
||||
[MAIN]: executable({
|
||||
dependencies: [
|
||||
dependency(`@loader_path/${direct}`),
|
||||
dependency(`@executable_path/${fromExecutable}`),
|
||||
dependency("@rpath/libsearch.dylib"),
|
||||
],
|
||||
rpaths: [`@loader_path/${directory}`],
|
||||
}),
|
||||
[`Contents/MacOS/${direct}`]: parsed(slice()),
|
||||
[`Contents/MacOS/${fromExecutable}`]: parsed(slice()),
|
||||
[`Contents/MacOS/${directory}/libsearch.dylib`]: parsed(slice()),
|
||||
}),
|
||||
{ roots: [MAIN] },
|
||||
);
|
||||
expect(trace.edges.map(({ resolution }) => resolution)).toEqual([
|
||||
{ status: "resolved", image: `Contents/MacOS/${direct}` },
|
||||
{ status: "resolved", image: `Contents/MacOS/${fromExecutable}` },
|
||||
{
|
||||
status: "resolved",
|
||||
image: `Contents/MacOS/${directory}/libsearch.dylib`,
|
||||
},
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(["@loader_path_suffix", "@executable_path_suffix", "@loader_path\n"])(
|
||||
"does not expand a lookalike path token %j",
|
||||
async (token) => {
|
||||
const name = `${token}/lib.dylib`;
|
||||
const trace = await traceDylibLoading(
|
||||
memoryView({
|
||||
[MAIN]: executable({ dependencies: [dependency(name)] }),
|
||||
"Contents/MacOS/lib.dylib": parsed(slice()),
|
||||
}),
|
||||
{ roots: [MAIN] },
|
||||
);
|
||||
expect(edgeFor(trace, MAIN, name).resolution).toEqual({
|
||||
status: "undetermined",
|
||||
image: null,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
describe("dyld path expansion", () => {
|
||||
it("searches the loading image's rpaths before its loaders'", async () => {
|
||||
const core = "Contents/Frameworks/Core.framework/Versions/A/Core";
|
||||
|
||||
@@ -161,6 +161,68 @@ cliTest(
|
||||
},
|
||||
);
|
||||
|
||||
cliTest(
|
||||
"resolves dependency names and rpaths containing Unicode line separators",
|
||||
async ({ cli }) => {
|
||||
const app = await fixtureApp();
|
||||
const library = "lib\u2028core.dylib";
|
||||
const directory = "Libraries\u2029Nested";
|
||||
await writeFiles(app, {
|
||||
"Contents/MacOS/App": machoImage({
|
||||
commands: [
|
||||
buildVersionCommand(1),
|
||||
dylibCommand(LC.LOAD_DYLIB, `@loader_path/${library}`),
|
||||
rpathCommand(`@executable_path/${directory}`),
|
||||
dylibCommand(LC.LOAD_DYLIB, "@rpath/libsearch.dylib"),
|
||||
],
|
||||
}),
|
||||
[`Contents/MacOS/${library}`]: machoImage({
|
||||
fileType: FILE_TYPE.dylib,
|
||||
commands: [buildVersionCommand(1)],
|
||||
}),
|
||||
[`Contents/MacOS/${directory}/libsearch.dylib`]: machoImage({
|
||||
fileType: FILE_TYPE.dylib,
|
||||
commands: [buildVersionCommand(1)],
|
||||
}),
|
||||
});
|
||||
const output = await cli.run({
|
||||
arguments: [
|
||||
"trace-dylib-resolution",
|
||||
app,
|
||||
"--root",
|
||||
"Contents/MacOS/App",
|
||||
"--json",
|
||||
],
|
||||
environment: ENVIRONMENT,
|
||||
});
|
||||
expect(output.exitCode, output.stderr).toBe(0);
|
||||
const trace = dylibResolutionResultSchema.parse(
|
||||
parseEvidence(output.json).normalized_result,
|
||||
);
|
||||
expect(
|
||||
trace.edges.map(({ install_name, resolution }) => ({
|
||||
install_name,
|
||||
resolution,
|
||||
})),
|
||||
).toEqual([
|
||||
{
|
||||
install_name: `@loader_path/${library}`,
|
||||
resolution: {
|
||||
status: "resolved",
|
||||
image: `Contents/MacOS/${library}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
install_name: "@rpath/libsearch.dylib",
|
||||
resolution: {
|
||||
status: "resolved",
|
||||
image: `Contents/MacOS/${directory}/libsearch.dylib`,
|
||||
},
|
||||
},
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
describe("trace-dylib-resolution CLI", () => {
|
||||
cliTest("traces every executable root of an app bundle", async ({ cli }) => {
|
||||
const app = await fixtureApp();
|
||||
|
||||
Reference in New Issue
Block a user