Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non constant BindingFlags causes ILLinker to trim required methods #1617

Closed
eerhardt opened this issue Nov 10, 2020 · 2 comments · Fixed by #1701
Closed

Non constant BindingFlags causes ILLinker to trim required methods #1617

eerhardt opened this issue Nov 10, 2020 · 2 comments · Fixed by #1701
Assignees
Milestone

Comments

@eerhardt
Copy link
Member

When a non-public method is called through Reflection, but the BindingFlags parameter is not a constant, the ILLinker won't preserve the called method, and it won't log a warning. Thus the user thinks their app will work successfully, but the app doesn't since the called method is trimmed.

This scenario was found in System.Private.Xml and is one of the underlying causes of issue dotnet/runtime#41389.

https://github.com/dotnet/runtime/blob/819a3cc69e2bf606787a44f9f107ebbbed0fcb11/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs#L24-L28

Example

Fully trim the following application:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <Target Name="EnsureAllAssembliesAreLinked"
        BeforeTargets="PrepareForILLink">
    <ItemGroup>
      <ManagedAssemblyToLink>
        <TrimMode>link</TrimMode>
      </ManagedAssemblyToLink>

      <!-- Pass the app assembly as a root -->
      <TrimmerRootAssembly Include="@(IntermediateAssembly)" />
    </ItemGroup>
  </Target>
</Project>
    internal class CodeGenerator
    {
        internal static BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
    }

    public abstract class XmlSerializationWriter
    {
        protected void WriteStartDocument()
        {
        }
    }

    internal class Program
    {
        public static void Main()
        {
            MethodInfo XmlSerializationWriter_WriteStartDocument = typeof(XmlSerializationWriter).GetMethod(
                "WriteStartDocument",
                CodeGenerator.InstanceBindingFlags,
                null,
                Array.Empty<Type>(),
                null
                )!;
            Console.WriteLine(XmlSerializationWriter_WriteStartDocument.Name);
        }
    }

When trimmed, the application will throw:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at ConsoleApp111.Program.Main() in C:\Users\eerhardt\source\repos\ConsoleApp111\ConsoleApp111\Program.cs:line 29

cc @vitek-karas

vitek-karas added a commit to vitek-karas/linker that referenced this issue Nov 10, 2020
@vitek-karas
Copy link
Member

#1619 has a sample test case for this.

The bug is that we only recognize binding flags if they are constants. If not, we actually behave as if an overload of GetMethod which doesn't take any binding flags was called, and so we "fallback" to "Public|Instance|Static" binding flags.

The correct behavior is to fallback to "annotations" (in spirit, not in implementation) and mark all methods on the affected type. Basically the same thing we do if IgnoreCase binding flag is specified.

This bug likely affects fields and properties and potentially other things as well.

@vitek-karas
Copy link
Member

@tlakollo could you please take a look at this and possibly fix it?

@vitek-karas vitek-karas added this to the .NET 6.0 milestone Nov 10, 2020
eerhardt added a commit to eerhardt/runtime that referenced this issue Nov 17, 2020
Make XmlSerializer work correctly with ILLinker trimming.

1. Use constant BindingFlags to work around dotnet/linker#1617
2. Annotate CodeGenerator.CreateTypeBuilder correctly to preserve base class members

Fix dotnet#41389
eerhardt added a commit to dotnet/runtime that referenced this issue Dec 4, 2020
* XmlSerializer.Serialize doesn't work when using TrimMode=link

Make XmlSerializer work correctly with ILLinker trimming.

1. Use constant BindingFlags to work around dotnet/linker#1617
2. Annotate CodeGenerator.CreateTypeBuilder correctly to preserve base class members

Fix #41389

* Update ILLinker suppressions file.

* PR feedback.

Fix ILLinker suppresions.
agocke pushed a commit to dotnet/runtime that referenced this issue Nov 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants