Skip to content

Improve managed ilasm test coverage - #131509

Open
jkoritzinsky wants to merge 14 commits into
ilasm-fixupsfrom
ilasm-more-tests
Open

Improve managed ilasm test coverage#131509
jkoritzinsky wants to merge 14 commits into
ilasm-fixupsfrom
ilasm-more-tests

Conversation

@jkoritzinsky

@jkoritzinsky jkoritzinsky commented Jul 28, 2026

Copy link
Copy Markdown
Member

Add feature-focused metadata and PE validation tests and fix emitter issues exposed by them.

With these unit tests (amongst others added in the stack) we can have more confidence in the managed ilasm implementation. In the future, we may even be able to move ilasm round-trip testing to an "outerloop" experience for ilasm instead of being the primary validation pipeline.

This PR also includes fixes and corresponding tests for failures identified with ildasm/ilasm round-trip testing (all except one, which is addressed by #132346).


Stack created with GitHub Stacks CLIGive Feedback 💬

Note

This PR description was generated with GitHub Copilot.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
16 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@jkoritzinsky jkoritzinsky changed the title ilasm more tests Improve ILAssembler test coverage Jul 28, 2026
@jkoritzinsky jkoritzinsky changed the title Improve ILAssembler test coverage Improve managed ilasm test coverage Jul 28, 2026
@jkoritzinsky
jkoritzinsky marked this pull request as ready for review July 28, 2026 23:33
Copilot AI lite review requested due to automatic review settings July 28, 2026 23:33
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
16 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR significantly expands the managed ilasm unit test suite to validate emitted metadata/PE structures (exports, resources, PDBs, signatures, marshalling, etc.), and adjusts the managed ilasm emitter/parser to satisfy the newly-covered scenarios.

Changes:

  • Add many new ILAssembler.Tests cases that decode emitted metadata/PE/PDB and validate specific directives and operand forms.
  • Fix/extend ilasm implementation details in GrammarVisitor (e.g., custom attribute serialization, .module handling, sequence points, callconv explicit/instance) and VTableExportPEBuilder (vtable fixup directory offset + export table layout).
  • Improve test infra helpers to compile IL text and decode IL token operands/signatures more easily.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/tools/ilasm/tests/ILAssembler.Tests/VTableTests.cs Minor formatting-only change.
src/tools/ilasm/tests/ILAssembler.Tests/TypeSignatureTests.cs Add tests for multidimensional array local signature shapes.
src/tools/ilasm/tests/ILAssembler.Tests/TypeReferenceTests.cs Add tests for .this/.base/.nester/mdtoken type refs, module-scoped refs, typelist parsing.
src/tools/ilasm/tests/ILAssembler.Tests/TypedefTests.cs Add tests for .typedef aliases for fields and custom attributes.
src/tools/ilasm/tests/ILAssembler.Tests/TypeDefinitionTests.cs Add tests for type name splitting, class flags/attributes, nested types, interface impl metadata.
src/tools/ilasm/tests/ILAssembler.Tests/SourceDirectiveTests.cs Strengthen .line/.language coverage and validate emitted embedded PDB details + string escape correctness.
src/tools/ilasm/tests/ILAssembler.Tests/SecurityTests.cs Add extensive .permissionset emission/shape tests (incl. tolerant-mode behavior).
src/tools/ilasm/tests/ILAssembler.Tests/PropertyTests.cs Add property attribute/accessor/signature metadata validation.
src/tools/ilasm/tests/ILAssembler.Tests/PropertyEventTests.cs New test file covering PropertyMap/EventMap + MethodSemantics emission.
src/tools/ilasm/tests/ILAssembler.Tests/PreprocessorIntegrationTests.cs New integration tests for nested includes, conditional compilation, multi-token macros.
src/tools/ilasm/tests/ILAssembler.Tests/ParameterTests.cs Add tests for parameter attribute forms and raw flag parsing.
src/tools/ilasm/tests/ILAssembler.Tests/NativeExportTests.cs New tests validating when exports are (not) emitted and verifying export directory/stubs.
src/tools/ilasm/tests/ILAssembler.Tests/ModuleTests.cs Add tests for .file, .module extern, bare .module, and global method/module metadata + PDB.
src/tools/ilasm/tests/ILAssembler.Tests/MethodTests.cs Add tests for method attributes/impl flags, method body directives, entrypoint token, override forms.
src/tools/ilasm/tests/ILAssembler.Tests/MemberReferenceTests.cs Add tests for vararg MemberRef signatures, generic-instantiation MemberRefs, method spec emission.
src/tools/ilasm/tests/ILAssembler.Tests/ManifestResourceTests.cs New tests for embedded/assembly/file-backed manifest resources + tolerant/deterministic behaviors.
src/tools/ilasm/tests/ILAssembler.Tests/InteropTests.cs Add marshalling and P/Invoke import metadata tests (incl. complex native type payloads).
src/tools/ilasm/tests/ILAssembler.Tests/InstructionTests.cs Add coverage for float bit-pattern literals, calli sigs, ldstr forms, switch table forms, token operands.
src/tools/ilasm/tests/ILAssembler.Tests/GenericTests.cs Add generic parameter name/bounds/variance/custom attribute/constraint metadata tests.
src/tools/ilasm/tests/ILAssembler.Tests/FunctionPointerTests.cs Update function pointer signature assertions to use decoded signatures; add vararg fnptr test.
src/tools/ilasm/tests/ILAssembler.Tests/FieldTests.cs Add tests for field attribute flags, volatile/literal/nullref constant emission.
src/tools/ilasm/tests/ILAssembler.Tests/ExportedTypeTests.cs Add tests for exported type attributes/implementations + custom attributes.
src/tools/ilasm/tests/ILAssembler.Tests/ExceptionHandlingTests.cs Add tests validating EH region bounds/kinds for multiple clause forms.
src/tools/ilasm/tests/ILAssembler.Tests/EventTests.cs Add tests for event raise accessor, event “other” accessor, and attribute emission.
src/tools/ilasm/tests/ILAssembler.Tests/DocumentCompilerTests.cs New test validating diagnostics pathing across multi-document compilation in tolerant mode.
src/tools/ilasm/tests/ILAssembler.Tests/DocumentCompilerTestHelpers.cs Add decoder + richer compile helpers and IL token operand extraction.
src/tools/ilasm/tests/ILAssembler.Tests/DataTests.cs Add tests for .data directive typed byte emission, repeats, and class-scoped .data.
src/tools/ilasm/tests/ILAssembler.Tests/CustomAttributeTests.cs Add broad structured custom attribute decoding tests (arrays, boxed values, owner targeting, type args).
src/tools/ilasm/tests/ILAssembler.Tests/CompilerOptionsTests.cs New tests validating Options-driven PE/header/corflags/debug/pdb/determinism/keyfile behaviors.
src/tools/ilasm/tests/ILAssembler.Tests/AssemblyTests.cs Add tests for assembly reference identity metadata and aliased reference/assembly attributes.
src/tools/ilasm/src/ILAssembler/VTableExportPEBuilder.cs Fix COR header vtable fixup directory offset; refactor vtable slot serialization and export table layout.
src/tools/ilasm/src/ILAssembler/GrammarVisitor.cs Numerous parser/emitter fixes to support new metadata/PDB/custom-attribute/directive scenarios.
Comments suppressed due to low confidence (1)

src/tools/ilasm/src/ILAssembler/GrammarVisitor.cs:2924

  • Same as above: ToImmutable() copies; MoveToImmutable() can transfer the backing array without allocating, which is preferable in a potentially hot parsing path.
            return new(builder.ToImmutable().SerializeSequence());

Comment thread src/tools/ilasm/tests/ILAssembler.Tests/SourceDirectiveTests.cs
Comment thread src/tools/ilasm/src/ILAssembler/GrammarVisitor.cs Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @dotnet/jit-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI review requested due to automatic review settings July 29, 2026 00:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 29, 2026 00:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

src/tools/ilasm/tests/ILAssembler.Tests/TypeSignatureTests.cs:92

  • This test assumes the locals signature is always StandAloneSig row 1. Using the method body's LocalSignature handle avoids tying the assertion to metadata row ordering.
            var signature = reader.GetStandaloneSignature(MetadataTokens.StandaloneSignatureHandle(1));

src/tools/ilasm/tests/ILAssembler.Tests/TypeSignatureTests.cs:125

  • Hard-coding StandaloneSignatureHandle(1) here couples the test to metadata emission order. Use the method body's LocalSignature to make the test robust against unrelated StandAloneSig additions.
            var signature = reader.GetStandaloneSignature(MetadataTokens.StandaloneSignatureHandle(1));

src/tools/ilasm/tests/ILAssembler.Tests/TypeSignatureTests.cs:66

  • This test hard-codes StandaloneSignatureHandle(1), which makes it brittle if the compiler ever emits another StandAloneSig row before the locals signature. Prefer using the method body's LocalSignature handle so the test is resilient to unrelated metadata changes.

This issue also appears in the following locations of the same file:

  • line 92
  • line 125
            var signature = reader.GetStandaloneSignature(MetadataTokens.StandaloneSignatureHandle(1));

Copilot AI review requested due to automatic review settings July 29, 2026 00:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/tools/ilasm/src/ILAssembler/GrammarVisitor.cs:5573

  • In structured custom attribute encoding, a boxed object(...) value must include the SerializationTypeCode.TaggedObject (0x51) prefix, followed by the embedded value’s FieldOrPropType and value bytes. The current object(...) branch writes only the embedded type/value and omits the TaggedObject prefix, which will make decoding object arguments invalid (and can break object[] element encoding too).
            if (context.serInit() is CILParser.SerInitContext serInit)
            {
                Debug.Assert(context.OBJECT() is not null);
                BlobBuilder taggedObjectBlob = new();
                WriteCustomAttributeFieldOrPropType(taggedObjectBlob, serInit);
                taggedObjectBlob.LinkSuffix(VisitSerInit(serInit).Value);
                return new(taggedObjectBlob);

Comment thread src/tools/ilasm/src/ILAssembler/GrammarVisitor.cs
Copilot AI review requested due to automatic review settings July 29, 2026 00:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/tools/ilasm/tests/ILAssembler.Tests/DocumentCompilerTestHelpers.cs:123

  • GetTokenOperands reads the method body without validating RelativeVirtualAddress > 0, so callers get an exception from PEReader.GetMethodBody instead of a clear test failure message when the target method has no body (e.g., runtime/abstract methods). This helper already has a good pattern in GetFirstTokenOperand; it should mirror that assert for consistency and debuggability.
            var method = reader.MethodDefinitions
                .Select(reader.GetMethodDefinition)
                .First(definition => reader.GetString(definition.Name) == methodName);
            byte[] il = pe.GetMethodBody(method.RelativeVirtualAddress).GetILBytes()!;
            var operands = ImmutableArray.CreateBuilder<int>();

Copilot AI review requested due to automatic review settings July 29, 2026 19:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated 1 comment.

Comment on lines +412 to +423
int baseOrdinal = int.MaxValue;
int maxOrdinal = 0;
foreach (ExportInfo export in _exports)
{
baseOrdinal = Math.Min(baseOrdinal, export.Ordinal);
maxOrdinal = Math.Max(maxOrdinal, export.Ordinal);
}
if (baseOrdinal == int.MaxValue)
{
baseOrdinal = 1;
}
int numFunctions = numExports > 0 ? maxOrdinal - baseOrdinal + 1 : 0;
Copilot AI review requested due to automatic review settings August 10, 2026 17:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/tools/ilasm/src/ILAssembler/VTableExportPEBuilder.cs:452

  • There’s an unused local (exportDirTotalSize) declared a couple of lines above. This will trigger an unused-local warning (and can break the build if warnings are treated as errors). It also makes it unclear whether the value is supposed to feed _exportDirectorySize.
        // Store total size for COR header patching (only vtfixup directory, not stubs/exports)
        _sdataSize = vtfDirSize;

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/tools/ilasm/src/ILAssembler/VTableExportPEBuilder.cs:423

  • numFunctions is derived from maxOrdinal - baseOrdinal + 1 using unchecked int arithmetic. With large/sparse ordinals this can overflow (or become extremely large), which then feeds offset calculations and the EAT loop and can produce a corrupted PE or very large allocations/work.

At minimum, compute this with checked so invalid inputs fail fast instead of silently corrupting the export directory layout.

        if (baseOrdinal == int.MaxValue)
        {
            baseOrdinal = 1;
        }
        int numFunctions = numExports > 0 ? maxOrdinal - baseOrdinal + 1 : 0;

src/tools/ilasm/src/ILAssembler/VTableExportPEBuilder.cs:453

  • exportDirTotalSize (computed just above) is unused. In many runtime projects warnings are treated as errors, so this risks breaking the build. Either remove it or wire it into the export directory sizing logic.
        // Store total size for COR header patching (only vtfixup directory, not stubs/exports)
        _sdataSize = vtfDirSize;

src/tools/ilasm/tests/ILAssembler.Tests/CompilerOptionsTests.cs:318

  • The cleanup uses Directory.Delete(tempDirectory) (non-recursive). If the key file deletion fails for any reason (e.g., transient file lock), this will throw and fail the test even though the assertions passed. Using recursive deletion here makes the cleanup more robust.
                if (Directory.Exists(tempDirectory))
                {
                    Directory.Delete(tempDirectory);
                }

@jkoritzinsky
jkoritzinsky changed the base branch from managed-ilasm-rt-ci to ilasm-fixups August 14, 2026 17:13
jkoritzinsky and others added 14 commits August 14, 2026 15:33
Reserve and populate the MVID from the deterministic PE content ID, and add in-process byte-for-byte coverage for DLL and EXE output.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2fb9f1ef-f721-49e0-bf48-4a7a9458d53a
Use content-based portable PDB IDs for deterministic builds and add in-process coverage for byte-identical PDB output and non-empty PDB ID GUIDs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2fb9f1ef-f721-49e0-bf48-4a7a9458d53a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2fb9f1ef-f721-49e0-bf48-4a7a9458d53a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2fb9f1ef-f721-49e0-bf48-4a7a9458d53a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2fb9f1ef-f721-49e0-bf48-4a7a9458d53a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2fb9f1ef-f721-49e0-bf48-4a7a9458d53a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 106f96fe-da32-41d4-8aa5-7431edb36fc6
…ompiler, it's a compiler that's AOT compiled)
Add feature-focused metadata and PE validation tests and fix emitter issues exposed by them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4307156b-37a7-495d-9af6-fe9174c05b0b
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
… attribute encoding

When an object(...) element in an object[] custom attribute had nested
object() wrappers (e.g. object(object(bool(true)))), VisitSerInit's
object() branch would call WriteCustomAttributeFieldOrPropType on the
inner object() context, producing TaggedObject (0x51) as the element
type code. The .NET metadata decoder does not accept 0x51 as a
FieldOrPropType for object[] elements and throws BadImageFormatException.

Fix VisitObjSeq to fully unwrap any object(...) nesting using a while
loop, so that WriteCustomAttributeFieldOrPropType is always called with
the innermost concrete typed element (bool, int32, string, etc.). This
also makes type-byte handling uniform - always done by VisitObjSeq
rather than split between caller and callee.

Add a regression test CustomAttribute_ObjectArrayWithNestedObjectWrapper
_DecodesProperly that exercises object[](object(bool(true)) object(int32
(42))) and verifies the attribute decodes correctly.
Use comma separators between double-quoted GUID arguments so the tests match the supported .language grammar.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: adc580d5-8f1c-4772-bfc2-7a943aa0959d
Pre-size floating-point sequence builders and transfer their arrays without copying. Handle empty floating-point and string sequences and cover their custom attribute encoding.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: adc580d5-8f1c-4772-bfc2-7a943aa0959d
Copilot AI review requested due to automatic review settings August 14, 2026 22:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants