fix(dotnet): preserve leading Unicode content in metadata strings (#667)

Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
This commit is contained in:
Rudy Mizrahi Celekli
2026-10-06 03:18:01 -05:00
committed by GitHub
parent 94cc8475e0
commit ddea06360a
5 changed files with 71 additions and 2 deletions
@@ -139,3 +139,19 @@ describe("managed artifact inventory", () => {
});
});
});
it("preserves U+FEFF in references and fixed attribute strings", () => {
const bytes = buildManagedPeFixture({
references: ["\uFEFFSystem.Runtime", "System.\uFEFFRuntime"],
targetFramework: "\uFEFF.NETCoreApp,Version=v8.0",
});
const result = inspectManagedArtifactBytes(
bytes,
managedPeFixtureTarget(bytes),
);
expect(result.references.map((reference) => reference.name)).toEqual([
"\uFEFFSystem.Runtime",
"System.\uFEFFRuntime",
]);
expect(result.target_frameworks).toEqual(["\uFEFF.NETCoreApp,Version=v8.0"]);
});
+19
View File
@@ -146,3 +146,22 @@ it("keeps an admitted but unimplemented element type unsupported", () => {
issue: "unsupported element type 0x14",
});
});
it("preserves leading U+FEFF as metadata name content", () => {
const bytes = buildManagedPeFixture({
typeNamespace: "\uFEFFFixture",
typeName: "\uFEFFProgram",
methodName: "\uFEFFMain",
fieldName: "\uFEFFcounter",
});
const result = inspectManagedMembersBytes(
bytes,
managedPeFixtureTarget(bytes),
);
expect(result.types[0]?.full_name).toBe("\uFEFFFixture.\uFEFFProgram");
expect(result.methods[0]?.name).toBe("\uFEFFMain");
expect(result.fields[0]?.name).toBe("\uFEFFcounter");
expect(result.call_edges[0]?.caller).toBe(
"\uFEFFFixture.\uFEFFProgram.\uFEFFMain",
);
});
+1 -1
View File
@@ -131,7 +131,7 @@ export const readMetadataString = (
start,
);
try {
return new TextDecoder("utf-8", { fatal: true }).decode(
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
bytes.subarray(start, end),
);
} catch (cause: unknown) {
+1 -1
View File
@@ -345,7 +345,7 @@ const decodeFixedString = (blob: Buffer): string | null => {
const start = 2 + length.prefix;
if (start > blob.length - length.length) return null;
try {
return new TextDecoder("utf-8", { fatal: true }).decode(
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
blob.subarray(start, start + length.length),
);
} catch (cause: unknown) {
@@ -147,3 +147,37 @@ const asManagedMemberResult = (execution: AnalysisExecution) =>
const asManagedNativeBoundaryResult = (execution: AnalysisExecution) =>
managedNativeBoundaryInspectionSchema.parse(execution.result);
it("retains U+FEFF metadata through the filesystem target and provider", async () => {
const directory = await createTestTempDirectory("rea-managed-bom-");
const path = join(directory, "fixture.exe");
await writeFile(
path,
buildManagedPeFixture({
typeName: "\uFEFFProgram",
methodName: "\uFEFFMain",
fieldName: "\uFEFFcounter",
references: ["\uFEFFSystem.Runtime"],
targetFramework: "\uFEFF.NETCoreApp,Version=v8.0",
}),
);
const parsed = await parseBinaryTarget(path);
expect(parsed.ok).toBe(true);
if (!parsed.ok) return;
const client = new ManagedStaticProvider().createClient(parsed.value);
const artifact = await client.execute("inspect_managed_artifact", {});
expect(artifact.ok).toBe(true);
if (!artifact.ok) return;
expect(asManagedResult(artifact.value)).toMatchObject({
references: [expect.objectContaining({ name: "\uFEFFSystem.Runtime" })],
target_frameworks: ["\uFEFF.NETCoreApp,Version=v8.0"],
});
const members = await client.execute("inspect_managed_members", {});
expect(members.ok).toBe(true);
if (!members.ok) return;
expect(asManagedMemberResult(members.value)).toMatchObject({
types: [expect.objectContaining({ name: "\uFEFFProgram" })],
methods: [expect.objectContaining({ name: "\uFEFFMain" })],
fields: [expect.objectContaining({ name: "\uFEFFcounter" })],
});
});