diff --git a/src/dotnet/ManagedMemberInspector.ts b/src/dotnet/ManagedMemberInspector.ts index 4bf93305c..f18d4ec5c 100644 --- a/src/dotnet/ManagedMemberInspector.ts +++ b/src/dotnet/ManagedMemberInspector.ts @@ -362,6 +362,11 @@ const ELEMENT_TYPES = new Map([ [0x1c, "object"], ]); +const ELEMENT_TYPE_SUFFIXES = new Map([ + [0x0f, "*"], + [0x10, "&"], +]); + const readTypeSignature = ( blob: Buffer, offset: number, @@ -370,13 +375,10 @@ const readTypeSignature = ( if (kind === undefined) throw new RangeError("truncated type signature"); const named = ELEMENT_TYPES.get(kind); if (named !== undefined) return { value: named, next: offset + 1 }; - if (kind === 0x0f) { + const suffix = ELEMENT_TYPE_SUFFIXES.get(kind); + if (suffix !== undefined) { const inner = readTypeSignature(blob, offset + 1); - return { value: `${inner.value}&`, next: inner.next }; - } - if (kind === 0x10) { - const inner = readTypeSignature(blob, offset + 1); - return { value: `${inner.value}*`, next: inner.next }; + return { value: `${inner.value}${suffix}`, next: inner.next }; } if (kind === 0x11 || kind === 0x12) { const token = readCompressed(blob, offset + 1); diff --git a/tests/fixtures/managedPe.ts b/tests/fixtures/managedPe.ts index b6ff5db1a..f5e936196 100644 --- a/tests/fixtures/managedPe.ts +++ b/tests/fixtures/managedPe.ts @@ -2,9 +2,11 @@ interface ManagedPeFixtureOptions { readonly cliFlags?: number; readonly corruptMetadataSignature?: boolean; readonly fieldName?: string; + readonly fieldSignature?: Buffer; readonly ilBody?: Buffer; readonly metadataValidMaskExtra?: bigint; readonly methodName?: string; + readonly methodSignature?: Buffer; readonly mvid?: Buffer; readonly pinvoke?: { readonly importName?: string; @@ -292,8 +294,12 @@ export const buildManagedPeFixture = ( strings.add(name), ); const tokenBlob = blobs.add(Buffer.from("b77a5c561934e089", "hex")); - const fieldSignature = blobs.add(Buffer.from([0x06, 0x08])); - const methodSignature = blobs.add(Buffer.from([0x00, 0x00, 0x01])); + const fieldSignature = blobs.add( + options.fieldSignature ?? Buffer.from([0x06, 0x08]), + ); + const methodSignature = blobs.add( + options.methodSignature ?? Buffer.from([0x00, 0x00, 0x01]), + ); const constructorSignature = blobs.add(Buffer.from([0x20, 0x01, 0x01, 0x0e])); const attributeBlob = blobs.add( fixedStringAttributeBlob( diff --git a/tests/managedArtifactProvider.test.ts b/tests/managedArtifactProvider.test.ts index cff14dfac..c305f6142 100644 --- a/tests/managedArtifactProvider.test.ts +++ b/tests/managedArtifactProvider.test.ts @@ -153,6 +153,30 @@ describe("managed PE/CLI static provider", () => { expect(boundaries.identity_scope.requires_mvid).toBe(result.module?.mvid); }); + it("decodes ECMA-335 pointer and byref element types without swapping them", () => { + const bytes = buildManagedPeFixture({ + fieldSignature: Buffer.from([0x06, 0x1d, 0x0f, 0x0f, 0x08]), + methodSignature: Buffer.from([ + 0x00, 0x02, 0x10, 0x08, 0x0f, 0x08, 0x10, 0x0e, + ]), + }); + const result = inspectManagedMembersBytes( + bytes, + target(bytes), + memberLimits, + ); + + expect(result.fields.items[0]?.signature).toMatchObject({ + parse_status: "decoded", + field_type: "i4**[]", + }); + expect(result.methods.items[0]?.signature).toMatchObject({ + parse_status: "decoded", + return_type: "i4&", + parameter_types: ["i4*", "string&"], + }); + }); + it("reads fat method header size from the full flags-and-size word", () => { const il = Buffer.from([ 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x22, 0x00,