mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
fix(dotnet): accept legacy small exception section sizes
Apply CoreCLR-compatible clause counting while validating and advancing by the physical section extent. Preserve malformed, reserved, chained and truncation checks. Validation: managed decoder suite passes; no native compiler or runtime verification claimed. Fixes #3279
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
buildManagedPeFixture,
|
||||
managedPeFixtureTarget,
|
||||
} from "./ManagedPe.fixture.js";
|
||||
import { parseExceptionRegions } from "./ManagedMemberInstructionDecoder.js";
|
||||
|
||||
const managedBodyWithSections = (...sections: Buffer[]) => {
|
||||
const header = Buffer.alloc(12);
|
||||
@@ -666,6 +667,59 @@ describe("managed exception region flags and filters", () => {
|
||||
});
|
||||
|
||||
describe("managed exception section decoding", () => {
|
||||
it("reads legacy small EH DataSize without counting its header", () => {
|
||||
const section = Buffer.alloc(16);
|
||||
section[0] = 0x01;
|
||||
section[1] = 12;
|
||||
|
||||
expect(managedBodyWithSections(section)).toMatchObject({
|
||||
status: "present",
|
||||
issue: null,
|
||||
exception_regions: [expect.any(Object)],
|
||||
normalized_il_sha256: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
it("advances a chained legacy section by its physical size", () => {
|
||||
const legacy = Buffer.alloc(16);
|
||||
legacy[0] = 0x81;
|
||||
legacy[1] = 12;
|
||||
const conformant = Buffer.alloc(16);
|
||||
conformant[0] = 0x01;
|
||||
conformant[1] = 16;
|
||||
|
||||
expect(managedBodyWithSections(legacy, conformant)).toMatchObject({
|
||||
status: "present",
|
||||
issue: null,
|
||||
exception_regions: [expect.any(Object), expect.any(Object)],
|
||||
normalized_il_sha256: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects a legacy-sized clause whose physical bytes leave the artifact", () => {
|
||||
const section = Buffer.alloc(12);
|
||||
section[0] = 0x01;
|
||||
section[1] = 12;
|
||||
|
||||
expect(parseExceptionRegions(section, 0, section.length)).toMatchObject({
|
||||
status: "malformed",
|
||||
regions: [],
|
||||
issue: "Exception section size leaves artifact",
|
||||
});
|
||||
});
|
||||
|
||||
it("still rejects a small EH DataSize that matches neither layout", () => {
|
||||
const section = Buffer.alloc(17);
|
||||
section[0] = 0x01;
|
||||
section[1] = 13;
|
||||
|
||||
expect(managedBodyWithSections(section)).toMatchObject({
|
||||
status: "malformed",
|
||||
exception_regions: [],
|
||||
issue: "Exception section size does not contain whole clauses",
|
||||
});
|
||||
});
|
||||
|
||||
it("marks an exception section with a partial clause as malformed", () => {
|
||||
const section = Buffer.alloc(17);
|
||||
section[0] = 0x01;
|
||||
@@ -695,6 +749,19 @@ describe("managed exception section decoding", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps small section reserved bytes invalid", () => {
|
||||
const section = Buffer.alloc(16);
|
||||
section[0] = 0x01;
|
||||
section[1] = 16;
|
||||
section[2] = 1;
|
||||
|
||||
expect(managedBodyWithSections(section)).toMatchObject({
|
||||
status: "malformed",
|
||||
exception_regions: [],
|
||||
issue: "Small exception section reserved bytes are nonzero",
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves decoded clauses when a chained section has an unsupported kind", () => {
|
||||
const first = Buffer.alloc(16);
|
||||
first[0] = 0x81;
|
||||
|
||||
@@ -543,11 +543,36 @@ export const parseExceptionRegions = (
|
||||
"Exception section size leaves artifact",
|
||||
regions,
|
||||
);
|
||||
if ((size - 4) % clauseSize !== 0)
|
||||
let count: number;
|
||||
let sectionSize = size;
|
||||
if (fat) {
|
||||
if ((size - 4) % clauseSize !== 0)
|
||||
return malformedExceptionRegions(
|
||||
"Exception section size does not contain whole clauses",
|
||||
regions,
|
||||
);
|
||||
count = (size - 4) / clauseSize;
|
||||
} else if ((size - 4) % clauseSize === 0) {
|
||||
count = (size - 4) / clauseSize;
|
||||
} else if (size >= clauseSize && size % clauseSize === 0) {
|
||||
// CoreCLR accommodates legacy VB/MC++ sections whose DataSize omits the
|
||||
// four-byte section header. DataSize is still not the physical extent.
|
||||
count = size / clauseSize;
|
||||
sectionSize = 4 + count * clauseSize;
|
||||
} else {
|
||||
return malformedExceptionRegions(
|
||||
"Exception section size does not contain whole clauses",
|
||||
regions,
|
||||
);
|
||||
}
|
||||
if (
|
||||
sectionOffset > methodEnd - sectionSize ||
|
||||
sectionOffset > bytes.length - sectionSize
|
||||
)
|
||||
return malformedExceptionRegions(
|
||||
"Exception section size leaves artifact",
|
||||
regions,
|
||||
);
|
||||
if (
|
||||
!fat &&
|
||||
(bytes[sectionOffset + 2] !== 0 || bytes[sectionOffset + 3] !== 0)
|
||||
@@ -557,7 +582,6 @@ export const parseExceptionRegions = (
|
||||
regions,
|
||||
);
|
||||
|
||||
const count = (size - 4) / clauseSize;
|
||||
// Accumulates with the method IL bound; the body reserves what it retains.
|
||||
budget?.admitTransient(count * 256, sectionOffset);
|
||||
for (const region of readExceptionClauses(
|
||||
@@ -569,7 +593,7 @@ export const parseExceptionRegions = (
|
||||
regions.push(region);
|
||||
|
||||
hasMoreSections = (kind & 0x80) !== 0;
|
||||
sectionOffset += size;
|
||||
sectionOffset += sectionSize;
|
||||
}
|
||||
return { status: "complete", regions };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user