runtime: [.NET 8] no longers works but throws build process for an infinite loop

Description

So far I built my ARM64 binary by dotnet publish -c Release -r linux-arm64 -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=true MyProject.csproj

Here are my project settings:

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<VersionPrefix>1.10.14</VersionPrefix>
		<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
		<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
		<EnableNETAnalyzers>False</EnableNETAnalyzers>
		<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
		<PublishTrimmed>true</PublishTrimmed>
	</PropertyGroup>

Turns out <PublishTrimmed>true</PublishTrimmed> no longers works: the build which tools ~3 minutes on .NET 7 now did not terminate the ‘optimization phase’ after > 9 hours.

What’s going wrong and how could I trim my build as before?

Reproduction Steps

Please see above

Expected behavior

Trimming should work with .NET8 as it worked with .NET 7

Actual behavior

Trimming does not work with .NET8 as it worked with .NET 7

Regression?

Yes

Known Workarounds

None

Configuration

No response

Other information

No response

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Comments: 17 (11 by maintainers)

Commits related to this issue

Most upvoted comments

@sbomer I guess you’re right. The trimmer should play it safe, and thus if it can’t figure something out, it should warn. In this case it might be annoying, but it’s probably better than saying “everything’s fine” (insert your favorite fire meme 😉)

@DierkDroth

Your app is not that big, although there is one method in it which is very large and has LOT of async calls in it. That’s what caused the problem. But overall it’s not that crazy (“only ~500 await calls”). The exponential state problem is that the tooling simulates all potential values a variable can take in the method, and it’s very easy to blow that set out of the water. For example:

				typeof (TestType).RequiresAll (); // Force data flow analysis

				object[] data = new object[20];
				if (true) data[0] = new object ();
				if (true) data[1] = new object ();
				if (true) data[2] = new object ();
				if (true) data[3] = new object ();
				if (true) data[4] = new object ();
				if (true) data[5] = new object ();
				if (true) data[6] = new object ();
				if (true) data[7] = new object ();
				if (true) data[8] = new object ();
				if (true) data[9] = new object ();
				if (true) data[10] = new object ();
				if (true) data[11] = new object ();
				if (true) data[12] = new object ();
				if (true) data[13] = new object ();
				if (true) data[14] = new object ();
				if (true) data[15] = new object ();
				if (true) data[16] = new object ();
				if (true) data[17] = new object ();
				if (true) data[18] = new object ();
				if (true) data[19] = new object ();

Now just assume that tool is not smart enough to figure out the condition, that it has to assume in each if both branches can be taken. Then the number of possible states for this test is on the order of 2^20. The tool obviously can’t represent it in memory, so we have to “give up” at some point.