Files
reverse-engineering-anything/src/dotnet/ManagedMethodDefinitionRows.ts
T
RRFZandmorluto da3bb5aa7b fix(managed): report InternalCall methods as runtime-provided boundaries (#9547)
* fix(managed): report InternalCall methods as runtime-provided boundaries

inspect_managed_native_boundaries listed P/Invoke, native, runtime and
unmanaged methods, but not methods with MethodImplOptions.InternalCall
(0x1000). The runtime implements those bodies; mscorlib and
System.Private.CoreLib declare hundreds of them as FCalls. They now appear
in native_implementations with boundary_kind runtime-provided.

* fix(managed): keep InternalCall bodies out of CIL decoding

The native-boundary view reports InternalCall methods as runtime-provided.
Body admission still decoded CIL from a nonzero RVA when the row kept IL
and managed flags. CoreCLR rejects such a row (BFA_INTERNAL_METHOD_WITH_RVA).

Body admission now treats InternalCall like the Runtime code type. The
method gets a partial body with no instructions. The InternalCall test
covers both a zero and a nonzero RVA.

* test(javascript): distinguish package scope in route fixtures

* test(apple): separate identity and refusal fixture groups

* fix(managed): honor InternalCall during body admission

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-11-09 21:46:45 +08:00

51 lines
1.8 KiB
TypeScript

import type { ManagedMetadataLayout } from "./ManagedMetadataLayout.js";
import { metadataRowCursor, metadataToken } from "./ManagedMetadataHeaps.js";
/** Meaning of the MethodDef implementation bits, independent of RVA or ImplMap evidence. */
export interface ManagedMethodImplementationFlags {
readonly codeType: "il" | "native" | "optil" | "runtime";
readonly managedKind: "managed" | "unmanaged";
readonly pinvokeFlag: boolean;
/** MethodImplOptions.InternalCall (0x1000): the runtime implements the body. */
readonly internalCall: boolean;
}
const METHOD_CODE_TYPES = ["il", "native", "optil", "runtime"] as const;
/** Scalar MethodDef facts; consumers own heap admission and method selection. */
export const readMethodDefinitionRow = (
bytes: Buffer,
layout: ManagedMetadataLayout,
row: number,
): {
readonly token: string;
readonly rowOffset: number;
readonly rva: number;
readonly implFlags: number;
readonly flags: number;
readonly nameIndex: number;
readonly signatureIndex: number;
readonly implementation: ManagedMethodImplementationFlags;
} => {
// Layout admission bounds the whole fixed-width row before a cursor is created.
const cursor = metadataRowCursor(bytes, layout, 6, row);
const rva = cursor.readUInt32();
const implFlags = cursor.readUInt16();
const flags = cursor.readUInt16();
return {
token: metadataToken(6, row),
rowOffset: cursor.start,
rva,
implFlags,
flags,
nameIndex: cursor.readIndex(layout.stringIndexSize),
signatureIndex: cursor.readIndex(layout.blobIndexSize),
implementation: {
codeType: METHOD_CODE_TYPES[(implFlags & 0x0003) as 0 | 1 | 2 | 3],
managedKind: (implFlags & 0x0004) === 0 ? "managed" : "unmanaged",
pinvokeFlag: (flags & 0x2000) !== 0,
internalCall: (implFlags & 0x1000) !== 0,
},
};
};