Skip to content

Fix trimming for Marshal.StructureToPtr with ByVal DateTime arrays#128020

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/add-trimming-test-structuretoptr-byvaldatearray
Draft

Fix trimming for Marshal.StructureToPtr with ByVal DateTime arrays#128020
Copilot wants to merge 4 commits intomainfrom
copilot/add-trimming-test-structuretoptr-byvaldatearray

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 11, 2026

Description

Fixes a trimming issue from #127952 where Marshal.StructureToPtr / Marshal.DestroyStructure on a struct containing a [MarshalAs(UnmanagedType.ByValArray)] DateTime[] field could throw System.Security.VerificationException after trimming because required array marshaler metadata was removed.

The fix preserves the array marshaler interfaces and DateMarshaler members in System.Private.CoreLib's shared ILLink descriptor so StubHelpers.FreeArrayContents<T, TMarshaler> generic constraints and concrete interface implementations remain valid after trimming.

Changes

  • ILLink.Descriptors.Shared.xml — preserves System.StubHelpers.IArrayMarshaler\2, System.StubHelpers.IArrayElementMarshaler`2, and System.StubHelpers.DateMarshaler` members.
  • TrimmingTests/MarshalStructureToPtrByValDateArray.cs — adds a standalone trimming regression test mirroring StructureToPtrTests.StructureToPtr_ByValDateArray_Success.
  • System.Runtime.InteropServices.TrimmingTests.proj — registers the new trimming test file.
public struct StructWithDateArray
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public DateTime[] array;
}

Marshal.StructureToPtr(structure, memory, fDeleteOld: true);
Marshal.DestroyStructure(memory, structure.GetType());

Changes to the tests

  • Added MarshalStructureToPtrByValDateArray.cs under src/libraries/System.Runtime.InteropServices/tests/TrimmingTests/.
  • Verified the new trimming test passes locally with dotnet build System.Runtime.InteropServices.TrimmingTests.proj /p:TestTrimming=true.

Microsoft Reviewers: Open in VS Code

Original prompt

Create a new trimming test in src/libraries/System.Runtime.InteropServices/tests/TrimmingTests in dotnet/runtime.

Context:

  • Related issue: [ci-scan] Test failure: StructureToPtrTests.StructureToPtr_ByValDateArray_Success on tvos-arm64 #127952
  • The issue reports that System.Runtime.InteropServices.Tests.StructureToPtrTests.StructureToPtr_ByValDateArray_Success fails on tvos-arm64 with:
    System.Security.VerificationException : Method System.StubHelpers.StubHelpers.FreeArrayContents: type argument 'System.StubHelpers.DateMarshaler' violates the constraint of type parameter 'TMarshaler'.
  • The goal of this PR is to add a trimming test that reproduces the same behavior through CI validation. The expected result is that the new test will fail with the same failure mode; the failure will be fixed after CI confirms it.

Task:

  1. Inspect src/libraries/System.Runtime.InteropServices/tests/TrimmingTests for existing trimming test samples and match its conventions, project structure, attributes, and test patterns.
  2. Add a new trimming test under src/libraries/System.Runtime.InteropServices/tests/TrimmingTests.
  3. The contents/logic of the new trimming test should mirror what the existing libraries test StructureToPtrTests.StructureToPtr_ByValDateArray_Success does.
    • Locate the existing StructureToPtr_ByValDateArray_Success test in the repo.
    • Reuse/adapt the same struct definitions, marshaling attributes, allocations, Marshal.StructureToPtr, Marshal.DestroyStructure, assertions, and cleanup behavior as appropriate for a trimming test.
  4. Follow repository conventions:
    • Read any relevant README.md files in src/libraries/System.Runtime.InteropServices/tests/TrimmingTests and its parent directories before changing files.
    • Follow .editorconfig and the user’s C# style guidance.
    • Prefer adding to existing test files if that is the local convention; otherwise match sibling test layout.
    • If new files are added, include them in project files if sibling files are explicitly listed.
  5. Build and run the relevant test(s) after changes if feasible. If the test is expected to fail by design, clearly document the command(s) run and the observed failure. Do not claim unrelated builds/tests pass unless actually run.

Important: create the pull request even though the new trimming test is expected to expose/fail with the issue from #127952. Include in the PR description that this is intentionally adding coverage expected to reproduce the issue in CI.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: make a new TrimmingTest under src\libraries\System.Runtime.InteropServices\tests\TrimmingTests (look in this directory for samples). the contents of the trimming test should be what the StructureToPtr_ByValDateArray_Success libraries test does. create a PR with this. our expectation is the test will fail with the failure mode observed at @dotnet/runtime/issues/127952 . we'll fix failure once the PR is created and the CI infrastructure validates we really see the failure

Assistant: I’m waiting for your response to the confirmation dialog so I can continue creating the PR.

This pull request was created from Copilot chat.

…y (issue #127952)

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d5cc9194-87ba-4a47-aab5-a1c8f5c11865

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 11, 2026 02:00
Copilot AI changed the title [WIP] Add trimming test for StructureToPtr_ByValDateArray Add trimming test for Marshal.StructureToPtr with ByVal DateTime array (dotnet/runtime#127952) May 11, 2026
Copilot AI requested a review from MichalStrehovsky May 11, 2026 02:01
@MichalStrehovsky
Copy link
Copy Markdown
Member

Confirmed this test reproduces the issue:

  Unhandled exception. System.Security.VerificationException: Method System.StubHelpers.StubHelpers.FreeArrayContents: type argument 'System.StubHelpers.DateMarshaler' violates the constraint of type parameter 'TMarshaler'.
     at System.StubHelpers.StructureMarshaler`1.FreeCore(T& managed, Byte* unmanaged, CleanupWorkListElement& cleanupWorkList)
     at System.StubHelpers.StructureMarshaler`1.Free(T& managed, Byte* unmanaged, CleanupWorkListElement& cleanupWorkList)
     at System.StubHelpers.StructureMarshaler`1.ConvertToUnmanaged(T& managed, Byte* unmanaged, CleanupWorkListElement& cleanupWorkList)
     at System.StubHelpers.BoxedLayoutTypeMarshaler`1.ConvertToUnmanaged(Object managed, Byte* unmanaged, CleanupWorkListElement& cleanupWorkList)
     at System.Runtime.InteropServices.Marshal.LayoutTypeMarshalerMethods.ConvertToUnmanaged(Object obj, Byte* native, CleanupWorkListElement& cleanupWorkList)
     at System.Runtime.InteropServices.Marshal.StructureToPtr(Object structure, IntPtr ptr, Boolean fDeleteOld)
     at System.Runtime.InteropServices.Marshal.StructureToPtr[T](T structure, IntPtr ptr, Boolean fDeleteOld)

Now to the fix.

@copilot the theory is that the issue is that trimming is removing the interface that TMarshaler is constrained with (IArrayMarshaler). We need to make sure IArrayMarshaler is considered used when trimming the app.

Add the interface to src/coreclr/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml and ensure all members on it are kept. The docs on the XML file format are at docs/tools/illink/data-formats.md (it's the "Descriptor Format").

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/9c7a3bc4-8522-45c9-baab-648e64213b45

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 11, 2026 04:56
@dotnet-policy-service dotnet-policy-service Bot added the linkable-framework Issues associated with delivering a linker friendly framework label May 11, 2026
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/9c7a3bc4-8522-45c9-baab-648e64213b45

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 11, 2026 04:57
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 11, 2026

Confirmed this test reproduces the issue:

...

Implemented in 376b174, with comment cleanup in 15c4b5b. I preserved IArrayMarshaler<T, TSelf> and also kept the inherited IArrayElementMarshaler<T, TSelf> plus DateMarshaler members, which were required for the concrete DateMarshaler interface implementation to survive trimming. The new trimming test now passes locally with dotnet build System.Runtime.InteropServices.TrimmingTests.proj /p:TestTrimming=true.

Copilot AI changed the title Add trimming test for Marshal.StructureToPtr with ByVal DateTime array (dotnet/runtime#127952) Fix trimming for Marshal.StructureToPtr with ByVal DateTime arrays May 11, 2026
@MichalStrehovsky
Copy link
Copy Markdown
Member

The test now passes (it doesn't with Mono, but that's a Mono problem with marshalling DateTime in general).

However, I'm not convinced this is the right fix, I'll need to study what exactly is the reflection-like mechanism that #126911 introduced here.

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

Labels

area-System.Runtime.InteropServices linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants