fix(managed): classify 32-bit-preferred assemblies as platform neutral (#2342)
The CLI header's 32BITREQUIRED and 32BITPREFERRED bits are one two-bit field. Reading 32BITREQUIRED on its own reported Prefer32Bit assemblies (flags 0x00020003) as x86-only with requires_32bit true, and left anycpu-prefer-32 reachable only through the reserved combination. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1ca5fd38b4
commit
36132d3e17
|
|
@ -292,6 +292,30 @@ describe("managed artifact inventory", () => {
|
|||
]);
|
||||
expect(result.coverage).toMatchObject({ state: "complete", issues: [] });
|
||||
});
|
||||
|
||||
// dotnet/runtime corhdr.h: 32BITREQUIRED and 32BITPREFERRED form one
|
||||
// two-bit field, so neither bit can be read on its own.
|
||||
it.each([
|
||||
["neither bit", 0x0000_0001, "anycpu", false],
|
||||
["32BITREQUIRED alone", 0x0000_0003, "x86", true],
|
||||
["both bits", 0x0002_0003, "anycpu-prefer-32", false],
|
||||
["the reserved 32BITPREFERRED alone", 0x0002_0001, "anycpu", false],
|
||||
] as const)(
|
||||
"reads %s as one 32-bit requirement",
|
||||
(_label, cliFlags, architecture, requires32Bit) => {
|
||||
const bytes = buildManagedPeFixture({ cliFlags });
|
||||
const target = managedPeFixtureTarget(bytes);
|
||||
|
||||
expect(
|
||||
inspectManagedArtifactBytes(bytes, target).classification
|
||||
.managed_architecture,
|
||||
).toBe(architecture);
|
||||
expect(
|
||||
inspectManagedNativeBoundariesBytes(bytes, target).cli_native
|
||||
?.requires_32bit,
|
||||
).toBe(requires32Bit);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("managed artifact coded indexes", () => {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
type ManagedParseIssue,
|
||||
} from "../domain/managed/managedArtifact.js";
|
||||
import {
|
||||
managedCli32BitRequirement,
|
||||
readManagedPeLayout,
|
||||
type ManagedCliHeader,
|
||||
type ManagedPeLayout,
|
||||
|
|
@ -249,9 +250,9 @@ const managedArchitectureFor = (
|
|||
): ManagedArtifactInspection["classification"]["managed_architecture"] => {
|
||||
if (layout.architecture !== "x86" || (cli.flags & 1) === 0)
|
||||
return layout.architecture;
|
||||
if ((cli.flags & 0x0000_0002) !== 0) return "x86";
|
||||
if ((cli.flags & 0x0002_0000) !== 0) return "anycpu-prefer-32";
|
||||
return "anycpu";
|
||||
const requirement = managedCli32BitRequirement(cli.flags);
|
||||
if (requirement === "required") return "x86";
|
||||
return requirement === "preferred" ? "anycpu-prefer-32" : "anycpu";
|
||||
};
|
||||
|
||||
const runtimeClassification = ({
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ import {
|
|||
} from "./ManagedMetadataHeaps.js";
|
||||
import { managedTableRowCounts } from "./ManagedMetadataInventory.js";
|
||||
import type { ManagedMetadataInventory } from "./ManagedMetadataInventory.js";
|
||||
import type { ManagedPeLayout } from "./ManagedPeReader.js";
|
||||
import {
|
||||
managedCli32BitRequirement,
|
||||
type ManagedPeLayout,
|
||||
} from "./ManagedPeReader.js";
|
||||
import { readManagedValue } from "./ManagedReaderFailure.js";
|
||||
|
||||
type ModuleRef = ManagedNativeBoundaryInspection["module_refs"][number];
|
||||
|
|
@ -380,7 +383,7 @@ export const cliNative = (
|
|||
if (pe.cli === null) return null;
|
||||
return {
|
||||
il_only: (pe.cli.flags & 0x0000_0001) !== 0,
|
||||
requires_32bit: (pe.cli.flags & 0x0000_0002) !== 0,
|
||||
requires_32bit: managedCli32BitRequirement(pe.cli.flags) === "required",
|
||||
strong_name_signed: (pe.cli.flags & 0x0000_0008) !== 0,
|
||||
native_entry_point: (pe.cli.flags & 0x0000_0010) !== 0,
|
||||
ready_to_run_signature: pe.cli.readyToRunSignature,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,20 @@ export interface ManagedCliHeader {
|
|||
readonly readyToRunSignature: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* How the CLI header constrains process bitness. 32BITREQUIRED and
|
||||
* 32BITPREFERRED are one two-bit field: required alone is x86-only, both set
|
||||
* is platform-neutral code that prefers a 32-bit process, and preferred alone
|
||||
* is reserved and constrains nothing.
|
||||
*/
|
||||
export const managedCli32BitRequirement = (
|
||||
flags: number,
|
||||
): "required" | "preferred" | "none" => {
|
||||
const pair = flags & 0x0002_0002;
|
||||
if (pair === 0x0000_0002) return "required";
|
||||
return pair === 0x0002_0002 ? "preferred" : "none";
|
||||
};
|
||||
|
||||
export interface ManagedPeLayout {
|
||||
readonly machine: number;
|
||||
readonly architecture: "x86" | "x86_64" | "arm" | "arm64";
|
||||
|
|
|
|||
Loading…
Reference in New Issue