fix(native): preserve whitespace in Mach-O segment and section names (#6842)

Fixes #6818

Co-authored-by: Abelo9996 <Abelo9996@users.noreply.github.com>
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-24 04:13:45 +08:00
1 parent f713087132
commit af3b039d31
2 files changed
+53

No files matched your search

+9
View File
@@ -507,10 +507,19 @@ const TEXT_FIELDS = /^(?:segname|sectname|string #\d+)$/u;
*/
const OFFSET_STRING_FIELD = /^(name|path) (.* \(offset \d+\))$/u;
/**
* otool prints segment and section names as `<key> %.16s`: one separator
* space, then the fixed-width name, whose own leading and trailing whitespace
* belongs to the Mach-O value.
*/
const MACHO_NAME_FIELD = /^(segname|sectname)(?: (.*))?$/u;
const parseField = (rawLine: string): readonly [string, string] | undefined => {
const offsetString = OFFSET_STRING_FIELD.exec(rawLine.trimStart());
if (offsetString?.[1] !== undefined && offsetString[2] !== undefined)
return [offsetString[1], offsetString[2]];
const name = MACHO_NAME_FIELD.exec(rawLine.trimStart());
if (name?.[1] !== undefined) return [name[1], name[2] ?? ""];
// otool prints each linker option as `string #n <option>`; keep the option
// exactly, including surrounding spaces, under otool's ordinal label.
const option = /^\s*(string #[1-9]\d*)(?: (.*))?$/u.exec(rawLine);
@@ -207,6 +207,50 @@ it.each([
},
);
it("keeps the surrounding spaces of segment and section names", () => {
// Captured from `otool -l` on an object whose section is " sec " in segment
// " seg ": otool prints one space after the label, then the stored name.
const output = [
"Load command 0",
" cmd LC_SEGMENT_64",
" cmdsize 152",
" segname ",
" vmaddr 0x0000000000000000",
" vmsize 0x0000000000000008",
" fileoff 184",
" filesize 8",
" maxprot 0x00000007",
" initprot 0x00000007",
" nsects 1",
" flags 0x0",
"Section",
" sectname sec ",
" segname seg ",
" addr 0x0000000000000000",
" size 0x0000000000000008",
" offset 184",
" align 2^0 (1)",
" reloff 0",
" nreloc 0",
" flags 0x00000000",
" reserved1 0",
" reserved2 0",
"",
].join("\n");
expect(
parseOtoolLoadCommands(withOtoolMachHeader(output)).segments,
).toMatchObject([
{ name: "", sections: [{ segment: " seg ", name: " sec " }] },
]);
const named = parseOtoolLoadCommands(
withOtoolMachHeader(output.replace(" segname \n", " segname seg \n")),
);
expect(named.commands[0]?.fields.segname).toBe(" seg ");
expect(named.segments[0]?.name).toBe(" seg ");
});
it("preserves dependency install names that begin with the word stamp", () => {
const load = parseOtoolLoadCommands(
withOtoolMachHeader(