Have method, property, ivar, and adopted-protocol list owners flag real budget omissions on returned class, protocol, and category records. Preserve known empty lists and existing decode reasons. Validated 59 source tests, two built CLI controls, five static inspections of an Apple-clang fixture, and typecheck/lint. The target was never executed. Fixes #5543.
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
const base = 0x100000000n;
|
|
|
|
/** Minimal inert Mach-O with one class instance method and protocol method. */
|
|
export const objcRecordBudgetMacho = (owner: "class" | "protocol"): Buffer => {
|
|
const bytes = Buffer.alloc(4096);
|
|
const u32 = (offset: number, value: number) =>
|
|
bytes.writeUInt32LE(value, offset);
|
|
const pointer = (offset: number, target: number) =>
|
|
bytes.writeBigUInt64LE(base + BigInt(target), offset);
|
|
const nullPointer = (offset: number) => bytes.writeBigUInt64LE(0n, offset);
|
|
|
|
u32(0, 0xfeedfacf);
|
|
u32(4, 0x0100000c);
|
|
u32(12, 2);
|
|
u32(16, 1);
|
|
u32(20, owner === "protocol" ? 232 : 152);
|
|
u32(32, 0x19);
|
|
u32(36, owner === "protocol" ? 232 : 152);
|
|
bytes.write("__DATA", 40);
|
|
pointer(56, 0);
|
|
bytes.writeBigUInt64LE(4096n, 64);
|
|
bytes.writeBigUInt64LE(4096n, 80);
|
|
u32(88, 7);
|
|
u32(92, 5);
|
|
u32(96, owner === "protocol" ? 2 : 1);
|
|
bytes.write("__objc_classlist", 104);
|
|
bytes.write("__DATA", 120);
|
|
pointer(136, 0x180);
|
|
bytes.writeBigUInt64LE(8n, 144);
|
|
u32(152, 0x180);
|
|
if (owner === "protocol") {
|
|
bytes.write("__objc_protolist", 184);
|
|
bytes.write("__DATA", 200);
|
|
pointer(216, 0x6c0);
|
|
bytes.writeBigUInt64LE(8n, 224);
|
|
u32(232, 0x6c0);
|
|
pointer(0x6c0, 0x740);
|
|
}
|
|
|
|
pointer(0x180, 0x200);
|
|
// class_t: zero isa/superclass; class_ro_t is root, named and has one method.
|
|
nullPointer(0x200);
|
|
nullPointer(0x208);
|
|
pointer(0x220, 0x300);
|
|
u32(0x300, 2);
|
|
u32(0x308, 8);
|
|
pointer(0x318, 0x900);
|
|
pointer(0x320, 0x500);
|
|
nullPointer(0x328);
|
|
nullPointer(0x330);
|
|
nullPointer(0x340);
|
|
bytes.write("FixtureClass\0", 0x900);
|
|
u32(0x500, 24);
|
|
u32(0x504, 1);
|
|
pointer(0x508, 0x920);
|
|
pointer(0x510, 0x940);
|
|
pointer(0x518, 0x700);
|
|
bytes.write("classMethod\0", 0x920);
|
|
bytes.write("v@:\0", 0x940);
|
|
|
|
// Protocol method lists use the same declaration boundary and budget.
|
|
pointer(0x6c0, 0x740);
|
|
pointer(0x748, 0x980);
|
|
pointer(0x758, 0x800);
|
|
u32(0x780, 72);
|
|
u32(0x800, 24);
|
|
u32(0x804, 1);
|
|
pointer(0x808, 0x9a0);
|
|
bytes.write("FixtureProtocol\0", 0x980);
|
|
bytes.write("protocolMethod\0", 0x9a0);
|
|
return bytes;
|
|
};
|