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

Binaries using YamlDotNet built with the "Trim unused code" option fail at runtime #753

Closed
RobotsOnDrugs opened this issue Dec 6, 2022 · 3 comments

Comments

@RobotsOnDrugs
Copy link

Describe the bug
Trimmed binaries fail to deserialize and throw an exception at runtime.

To Reproduce
Publish a project with the "Trim unused code" option.
Build log:

Build started...
1>------ Build started: Project: Project, Configuration: Release x64 ------
1>Project -> C:\Users\iamtheclaw\source\repos\Project\bin\x64\Release\net7.0-windows10.0.19041.0\Project.dll
2>------ Publish started: Project: Project, Configuration: Release x64 ------
2>Determining projects to restore...
2>Restored C:\Users\iamtheclaw\source\repos\Project\Project.csproj (in 829 ms).
2>C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\Roslyn\csc.exe /noconfig /unsafe+ /checked- /nowarn:RCS1001,RCS1003,1701,1702,IL2121,1701,1702,2008 /fullpaths /nostdlib+ /platform:x64 /errorreport:prompt /warn:9999 /define:TRACE;RELEASE;NET;NET7_0;NETCOREAPP;WINDOWS;WINDOWS10_0_19041_0;NET5_0_OR_GREATER;NET6_0_OR_GREATER;NET7_0_OR_GREATER;NETCOREAPP1_0_OR_GREATER;NETCOREAPP1_1_OR_GREATER;NETCOREAPP2_0_OR_GREATER;NETCOREAPP2_1_OR_GREATER;NETCOREAPP2_2_OR_GREATER;NETCOREAPP3_0_OR_GREATER;NETCOREAPP3_1_OR_GREATER;WINDOWS10_0_19041_0_OR_GREATER;WINDOWS10_0_19041_0_OR_GREATER;WINDOWS10_0_18362_0_OR_GREATER;WINDOWS10_0_18362_0_OR_GREATER;WINDOWS10_0_17763_0_OR_GREATER;WINDOWS10_0_17763_0_OR_GREATER;WINDOWS8_0_OR_GREATER;WINDOWS7_0_OR_GREATER /main:Project.Project /errorendlocation /preferreduilang:en-US /highentropyva+ /nullable:enable <other references omitted> /reference:C:\Users\iamtheclaw\.nuget\packages\yamldotnet\12.1.0\lib\net6.0\YamlDotNet.dll /debug- /debug:embedded /filealign:512 /optimize+ /out:obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\Project.dll /refout:obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\refint\Project.dll /target:exe /warnaserror- /utf8output /deterministic+ /langversion:11.0 /analyzerconfig:C:\Users\iamtheclaw\source\repos\Project\.editorconfig /analyzerconfig:obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\Project.GeneratedMSBuildEditorConfig.editorconfig /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\analyzers\Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\analyzers\Microsoft.CodeAnalysis.NetAnalyzers.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\analyzers\ILLink.CodeFixProvider.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\analyzers\ILLink.RoslynAnalyzer.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.Fixes.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\codestyle\cs\Microsoft.CodeAnalysis.CSharp.CodeStyle.dll" /analyzer:"C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.Sdk\targets\..\codestyle\cs\Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.dll" /analyzer:"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.0\analyzers/dotnet/cs/Microsoft.Interop.JavaScript.JSImportGenerator.dll" /analyzer:"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.0\analyzers/dotnet/cs/Microsoft.Interop.LibraryImportGenerator.dll" /analyzer:"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.0\analyzers/dotnet/cs/Microsoft.Interop.SourceGeneration.dll" /analyzer:"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.0\analyzers/dotnet/cs/System.Text.Json.SourceGeneration.dll" /analyzer:"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.0\analyzers/dotnet/cs/System.Text.RegularExpressions.Generator.dll" Project.cs Configuration.cs PathMapping.cs UtilityFunctions.cs obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\Project.GlobalUsings.g.cs "obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\.NETCoreApp,Version=v7.0.AssemblyAttributes.cs" obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\Project.AssemblyInfo.cs /warnaserror+:NU1605,SYSLIB0011
2>Project -> C:\Users\iamtheclaw\source\repos\Project\bin\x64\Release\net7.0-windows10.0.19041.0\win-x64\Project.dll
2>Optimizing assemblies for size. This process might take a while.
2>C:\Program Files\dotnet\dotnet.exe "C:\Program Files\dotnet\sdk\7.0.100\Sdks\Microsoft.NET.ILLink.Tasks\tools\net7.0\illink.dll" -a "obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\Project.dll"
2>--singlewarn
2>--trim-mode link
2>--action link
2>-reference "C:\Users\iamtheclaw\.nuget\packages\fluentftp\42.1.0\lib\net6.0\FluentFTP.dll"
2>-reference "C:\Users\iamtheclaw\.nuget\packages\microsoft.extensions.logging.abstractions\2.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll"
2>-reference "C:\Users\iamtheclaw\.nuget\packages\nlog\5.1.0\lib\netstandard2.0\NLog.dll"
2>-reference "C:\Users\iamtheclaw\.nuget\packages\shellprogressbar\5.2.0\lib\netstandard2.0\ShellProgressBar.dll"
2>-reference "C:\Users\iamtheclaw\.nuget\packages\yamldotnet\12.1.0\lib\net6.0\YamlDotNet.dll"
<other references omitted>
2>--singlewarn- "Project"
2>-out "obj\x64\Release\net7.0-windows10.0.19041.0\win-x64\linked"
2>--nowarn "RCS1001;RCS1003;1701;1702;IL2121;1701;1702;2008"
2>--warn "5"
2>--warnaserror- --warnaserror ";NU1605;SYSLIB0011"
2>--feature Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability true
2>--feature System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization false
2>--feature System.Reflection.Metadata.MetadataUpdater.IsSupported false
2>--feature System.Resources.ResourceManager.AllowCustomResourceTypes false
2>--feature System.Runtime.InteropServices.BuiltInComInterop.IsSupported false
2>--feature System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting false
2>--feature System.Runtime.InteropServices.EnableCppCLIHostActivation false
2>--feature System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization false
2>--feature System.StartupHookProvider.IsSupported false
2>--feature System.Threading.Thread.EnableAutoreleasePool false
2>--feature System.Text.Encoding.EnableUnsafeUTF7Encoding false
2>-b
2>--skip-unresolved true 
2>
2>Assembly 'FluentFTP' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'NLog' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Assembly 'YamlDotNet' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries
2>Project -> C:\Users\iamtheclaw\source\repos\Project\bin\x64\Release\net7.0-windows10.0.19041.0\publish\win-x64\
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Elapsed 00:18.268 ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========
========== Elapsed 00:18.268 ==========

> Build started at 00:08 and took 17.358 seconds

Exception thrown at runtime:

[2022-12-06 00:14:35.9673] Error:    at YamlDotNet.Serialization.NodeDeserializers.ObjectNodeDeserializer.YamlDotNet.Serialization.INodeDeserializer.Deserialize(IParser, Type, Func`3 , Object& )
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser, Type, SerializerState, IValueDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser, Type, SerializerState, IValueDeserializer)
   at YamlDotNet.Serialization.Deserializer.Deserialize(IParser, Type)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](IParser)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](TextReader)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](String)
   at Project.Project.Main() in C:\Users\iamtheclaw\source\repos\Project\Project.cs:line 38
[2022-12-06 00:14:35.9985] Error: Property 'GamePath' not found on type 'Project.Configuration+UserConfiguration'.
[2022-12-06 00:14:35.9985] Error: Could not load configuration file. Aborting.
Press any key to exit.

And in case it matters:
Relevant source code lines from my project:

StreamReader reader = File.OpenText("UserConfiguration.yaml");
string ReadAndDispose(StreamReader reader) { string yaml = reader.ReadToEnd(); reader.Dispose(); return yaml; }
_config = new Deserializer().Deserialize<UserConfiguration>(ReadAndDispose(reader));

The object definition:

public record Configuration
{
	public readonly record struct RepoConnectionInfo
	{
		public required string Address { get; init; }
		public required string Username { get; init; }
		public string EffectivePassword => Password ?? Encoding.UTF8.GetString(Convert.FromBase64String(PasswordB64 ?? ""));
		public required string? Password { get; init; }
		public required string? PasswordB64 { get; init; }
		public required int Port { get; init; }
		public required string RootPath { get; init; }
		public required int MaxConnections { get; init; }
	}
	public readonly record struct UserConfiguration
	{
		public required string GamePath { get; init; }
		public required RepoConnectionInfo ConnectionInfo { get; init; }
		public required bool PromptToContinue { get; init; }
		public required string[] BaseSideloaderDirectories { get; init; }
	}
}

And the yaml it reads:

GamePath: C:\Game
ConnectionInfo:
  Address: <omitted>
  Username: <omitted>
  Password: null
  PasswordB64: <omitted>
  Port: 2121
  RootPath: /AI/
  MaxConnections: 5
PromptToContinue: true
BaseSideloaderDirectories:
# All searches are recursive
# relative remote directory | relative local directory | delete files that don't exist in the repo
- mods/Sideloader Modpack | mods\Sideloader Modpack | true
- mods/Sideloader Modpack - Maps | mods\Sideloader Modpack - Maps | true
- mods/Sideloader Modpack - MaterialEditor Shaders | mods\Sideloader Modpack - MaterialEditor Shaders | true
- mods/Sideloader Modpack - Studio | mods\Sideloader Modpack - Studio | true
- mods/SideloaderModpack-BleedingEdge | mods\Sideloader Modpack - Bleeding Edge | true
- mods/SideloaderModpack-UncensorSelector | mods\Sideloader Modpack - Uncensor Selector | true

Untrimmed binaries from the same source code do not throw this exception and read the yaml just fine.

@EdwardCooke
Copy link
Collaborator

This is a duplicate of #740. We make heavy use of reflection which doesn’t work well with trimmed libraries. The reason being, is that the compiler doesn’t know that all properties/constructors/methods/etc are being used so it strips them out. I’ve found a few attributes we can add to the code to support it, just haven’t had time to work on it lately. I have the constructor working, just need to work on the properties now.

@RobotsOnDrugs
Copy link
Author

Ah, okay. I'll watch that issue. It's much appreciated that supporting and taking advantage of features in newer versions of .NET and other things is important for the project.

@EdwardCooke
Copy link
Collaborator

I'm going to close this issue since we're tracking it in #740.

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

No branches or pull requests

2 participants