mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 00:36:35 +00:00
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>
This commit is contained in:
1 parent
ec7d09176b
commit
da3bb5aa7b
5 files changed
+58
-7
No files matched your search
@@ -650,7 +650,8 @@ unchanged signature. Comparison retains exact byte-based pairs for malformed
|
||||
signatures, including empty, truncated, or invalid headers, but reports them as
|
||||
unknown with a `signature-malformed` limitation when no change is observed.
|
||||
This applies to historical Evidence without signature-resolution attestation as
|
||||
well. Runtime-provided methods are counted separately in
|
||||
well. Runtime-provided methods have the Runtime code type or the InternalCall
|
||||
implementation flag, as core library FCalls do. They are counted separately in
|
||||
`native_implementations.runtime_provided`; they have no file-backed native body
|
||||
for this workflow to map and do not increase `native_body_unresolved`. Historical
|
||||
verification Evidence without this separate count leaves it unknown (`null`).
|
||||
|
||||
@@ -128,10 +128,11 @@ export const methodBody = (
|
||||
const native =
|
||||
context.implementation.codeType !== "il" ||
|
||||
context.implementation.managedKind !== "managed" ||
|
||||
context.implementation.pinvokeFlag;
|
||||
context.implementation.pinvokeFlag ||
|
||||
context.implementation.internalCall;
|
||||
if (native) {
|
||||
const issue =
|
||||
"CIL decoding is unavailable for native, runtime, unmanaged, or P/Invoke implementations";
|
||||
"CIL decoding is unavailable for native, runtime, InternalCall, unmanaged, or P/Invoke implementations";
|
||||
return {
|
||||
body: emptyMethodBody(rva, "partial", issue),
|
||||
tokenInstructions: [],
|
||||
|
||||
@@ -6,6 +6,8 @@ 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;
|
||||
@@ -42,6 +44,7 @@ export const readMethodDefinitionRow = (
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -321,9 +321,15 @@ export const nativeImplementations = (
|
||||
const implementations: NativeImplementation[] = [];
|
||||
for (const method of methods) {
|
||||
if (method.kind !== "method") continue;
|
||||
const { codeType, managedKind, pinvokeFlag } = method.implementation;
|
||||
const { codeType, managedKind, pinvokeFlag, internalCall } =
|
||||
method.implementation;
|
||||
const pinvokeDeclared = pinvokeTokens.has(method.token) || pinvokeFlag;
|
||||
if (!pinvokeDeclared && codeType === "il" && managedKind === "managed")
|
||||
if (
|
||||
!pinvokeDeclared &&
|
||||
!internalCall &&
|
||||
codeType === "il" &&
|
||||
managedKind === "managed"
|
||||
)
|
||||
continue;
|
||||
implementations.push({
|
||||
token: method.token,
|
||||
@@ -335,7 +341,12 @@ export const nativeImplementations = (
|
||||
code_type: codeType,
|
||||
managed_kind: managedKind,
|
||||
pinvoke_declared: pinvokeDeclared,
|
||||
boundary_kind: boundaryKind(pinvokeDeclared, codeType, managedKind),
|
||||
boundary_kind: boundaryKind(
|
||||
pinvokeDeclared,
|
||||
codeType,
|
||||
managedKind,
|
||||
internalCall,
|
||||
),
|
||||
body_interpretation:
|
||||
method.rva === 0 ? "not-file-backed" : "native-or-runtime",
|
||||
});
|
||||
@@ -347,10 +358,11 @@ const boundaryKind = (
|
||||
pinvokeDeclared: boolean,
|
||||
codeType: ManagedMethodImplementationFlags["codeType"],
|
||||
managedKind: ManagedMethodImplementationFlags["managedKind"],
|
||||
internalCall: boolean,
|
||||
): NativeImplementation["boundary_kind"] => {
|
||||
if (pinvokeDeclared) return "pinvoke";
|
||||
if (codeType === "native") return "native-body";
|
||||
if (codeType === "runtime") return "runtime-provided";
|
||||
if (codeType === "runtime" || internalCall) return "runtime-provided";
|
||||
if (managedKind === "unmanaged") return "unmanaged-method";
|
||||
return "mixed-or-unknown";
|
||||
};
|
||||
|
||||
@@ -524,6 +524,40 @@ it.each([
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ zeroRva: true, status: "absent", interpretation: "not-file-backed" },
|
||||
{ zeroRva: false, status: "partial", interpretation: "native-or-runtime" },
|
||||
])(
|
||||
"publishes an InternalCall method as a runtime-provided boundary consistently with body admission (zero RVA: $zeroRva)",
|
||||
({ zeroRva, status, interpretation }) => {
|
||||
// MethodImplOptions.InternalCall: the runtime implements the body. Core
|
||||
// library FCalls carry this bit with IL code type and no RVA. A malformed
|
||||
// row can keep IL flags and a file-backed RVA, which the runtime rejects.
|
||||
const { members, boundaries } = inspectImplementationFixture({
|
||||
implFlags: 0x1000,
|
||||
zeroRva,
|
||||
});
|
||||
expect(boundaries.native_implementations).toMatchObject([
|
||||
{
|
||||
token: members.methods[0]?.token,
|
||||
impl_flags: 0x1000,
|
||||
code_type: "il",
|
||||
managed_kind: "managed",
|
||||
pinvoke_declared: false,
|
||||
boundary_kind: "runtime-provided",
|
||||
body_interpretation: interpretation,
|
||||
},
|
||||
]);
|
||||
expect(boundaries.summary.native_implementation_count).toBe(1);
|
||||
expect(members.methods[0]?.body).toMatchObject({
|
||||
status,
|
||||
il_sha256: null,
|
||||
});
|
||||
if (!zeroRva) expect(members.methods[0]?.body.issue).toMatch(/CIL/u);
|
||||
else expect(members.methods[0]?.body.issue).toBeNull();
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "PInvoke flag on managed IL",
|
||||
|
||||
Reference in new issue
Block a user