diff --git a/src/native/parsers/lipo.ts b/src/native/parsers/lipo.ts index 263affada..26eba9b72 100644 --- a/src/native/parsers/lipo.ts +++ b/src/native/parsers/lipo.ts @@ -58,7 +58,7 @@ export const parseLipoArchitectures = (output: string): LipoArchitecture[] => { }; const integer = (value: string | undefined): number | null => { - if (value === undefined) return null; + if (value === undefined || !/^\d+$/u.test(value)) return null; const parsed = Number.parseInt(value, 10); return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : null; }; diff --git a/src/native/parsers/otool.ts b/src/native/parsers/otool.ts index e03916261..619c20a00 100644 --- a/src/native/parsers/otool.ts +++ b/src/native/parsers/otool.ts @@ -167,7 +167,7 @@ const parseFields = (block: string): Record => { const fields: Record = {}; for (const rawLine of block.split(/\r?\n/u).slice(1)) { const line = rawLine.trim(); - const match = /^(\S+(?:\s+version)?)\s+(.+)$/u.exec(line); + const match = /^(\S+(?:\s+(?:version|stamp))?)\s+(.+)$/u.exec(line); if (match?.[1] === undefined || match[2] === undefined) continue; const value = match[2].trim(); fields[match[1]] = numeric(value) ?? value; diff --git a/tests/boundary/providers/native/nativeMachoHeader.golden.test.ts b/tests/boundary/providers/native/nativeMachoHeader.golden.test.ts index 8582e9934..dc13e769a 100644 --- a/tests/boundary/providers/native/nativeMachoHeader.golden.test.ts +++ b/tests/boundary/providers/native/nativeMachoHeader.golden.test.ts @@ -42,3 +42,13 @@ it("does not reinterpret segment and section flags as Mach header flags", async true, ); }); + +it("keeps multi-word field names such as time stamp intact", async () => { + const load = parseOtoolLoadCommands(await nativeFixture("otool-load.txt")); + const stamped = load.commands.filter( + (command) => "time stamp" in command.fields, + ); + expect(stamped.length).toBeGreaterThan(0); + expect(load.commands.some((command) => "time" in command.fields)).toBe(false); + expect(stamped[0]?.fields["time stamp"]).toMatch(/^2 Thu Jan/); +}); diff --git a/tests/boundary/providers/native/nativeProvider.test.ts b/tests/boundary/providers/native/nativeProvider.test.ts index 8712e9cbc..592432418 100644 --- a/tests/boundary/providers/native/nativeProvider.test.ts +++ b/tests/boundary/providers/native/nativeProvider.test.ts @@ -305,6 +305,20 @@ describe("native macOS provider failures and parsing", () => { ], ); }); + + it("rejects trailing text in lipo numeric fields instead of truncating", () => { + const output = [ + "architecture arm64", + " cputype CPU_TYPE_ARM64", + " cpusubtype CPU_SUBTYPE_ARM64_ALL", + " offset 16384 trailing-junk", + " size 0x10", + " align 2^14 (16384)", + ].join("\n"); + expect(parseLipoArchitectures(output)).toMatchObject([ + { name: "arm64", file_offset: null, size: null, alignment: 16384 }, + ]); + }); }); class FailingRunner implements NativeCommandRunner {