Skip to content

[mono] msbuild aborts due to 4.7 dependencies #2618

Closed
@uweigand

Description

@uweigand

Building the .NET 6 final source-build on s390x (using the Mono runtime) results in an msbuild assembly that will always crash on startup, via an exception along these lines:

MSBUILD : error MSB1025: An internal failure occurred while running MSBuild. 
System.TypeLoadException: Could not load type of field 'Microsoft.Build.Evaluation.ToolsetConfigurationReader:_configurationSection' (0) due to: Could not load file or assembly 'System.Configuration.ConfigurationManager, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. 
  at Microsoft.Build.Evaluation.ProjectCollection.InitializeToolsetCollection(ToolsetConfigurationReader configReader) 
  at Microsoft.Build.Evaluation.ProjectCollection..ctor(IDictionary`2 globalProperties, IEnumerable`1 loggers, IEnumerable`1 remoteLoggers, ToolsetDefinitionLocations toolsetDefinitionLocations, Int32 maxNodeCount, Boolean onlyLogCriticalEvents, Boolean loadProjectsReadOnly) 
  at Microsoft.Build.CommandLine.MSBuildApp.BuildProject(String projectFile, String[] targets, String toolsVersion, Dictionary`2 globalProperties, Dictionary`2 restoreProperties, ILogger[] loggers, LoggerVerbosity verbosity, DistributedLoggerRecord[] distributedLoggerRecords, Int32 cpuCount, Boolean enableNodeReuse, TextWriter preprocessWriter, TextWriter targetsWriter, Boolean detailedSummary, ISet`1 warningsAsErrors, ISet`1 warningsAsMessages, Boolean enableRestore, ProfilerLogger profilerLogger, Boolean enableProfiler, Boolean interactive, Boolean isolateProjects, GraphBuildOptions graphBuildOptions, Boolean lowPriority, String[] inputResultsCaches, String outputResultsCache) 
  at Microsoft.Build.CommandLine.MSBuildApp.Execute(String[] commandLine)

The System.Configuration.ConfigurationManager assembly that is missing here is hard-coded to use a 4.7.0 version in the msbuild eng/Packages.props file:

    <PackageReference Update="System.Configuration.ConfigurationManager" Version="4.7.0" />

When doing a non-source-build build, the version of this assembly gets restored from a nuget package and is actually included in the resulting SDK tarball.

However, when using source-build, that nuget package is not used, and the assembly is not present in the SDK tarball, but there is still a dependency on it from msbuild, as can be seen e.g. in the sdk/6.0.100/MSBuild.deps.json file that is in the tarball:

      "Microsoft.Build/17.0.0": {
        "dependencies": {
          "Microsoft.Build.Framework": "17.0.0",
          "Microsoft.NET.StringTools": "1.0.0",
          "Microsoft.Win32.Registry": "4.3.0",
          "System.Collections.Immutable": "5.0.0",
          "System.Configuration.ConfigurationManager": "4.7.0",
          "System.Reflection.Metadata": "1.8.0",
          "System.Security.Principal.Windows": "4.7.0",
          "System.Text.Encoding.CodePages": "6.0.0",
          "System.Text.Json": "6.0.0",
          "System.Threading.Tasks.Dataflow": "4.9.0"
        },

Types defined by the missing assembly are used for members of ToolsetConfigurationReader, which is why the Mono JIT aborts when attempting to build the constructor (or other functions) of that class. This happens in particular when building the routine InitializeToolsetCollection from the above error message, which is always called on msbuild startup.

Now, I think that this happens to work even in the absence of that assembly on CoreCLR, because the ToolsetConfigurationReader is not actually used when running msbuild on Linux, instances of it are just passed around. That is because any actual use of the configuration reader is guarded (in ToolsetReader.ReadAllToolsets) by this check:

            if ((locations & ToolsetDefinitionLocations.ConfigurationFile) == ToolsetDefinitionLocations.ConfigurationFile)

and the default value of locations is provided by Microsoft.Build.Evaluation.ToolsetDefinitionLocation:Default, which is defined as:

        Default = None
#if FEATURE_SYSTEM_CONFIGURATION
                | ConfigurationFile
#endif
#if FEATURE_REGISTRY_TOOLSETS
                | Registry
#endif
#if !FEATURE_SYSTEM_CONFIGURATION && !FEATURE_REGISTRY_TOOLSETS
                | Local
#endif

Note that when building on Linux, the FEATURE_SYSTEM_CONFIGURATION define is false, and therefore ConfigurationFile is not included in the Default value.

And indeed, adding a FEATURE_SYSTEM_CONFIGURATION guard to all places where ToolsetConfigurationReader is referenced makes the abort go away, with no apparent adverse effect on the operation of msbuild otherwise. However, there are still places in the msbuild unit test that apparently deliberately use the ConfigurationFile setting even on Linux - not sure what to do about those.


There is a second missing dependency on a 4.7 assembly, System.Security.Permissions, which causes similar aborts during JIT. In this case, the function Microsoft.Build.Shared.ExceptionHandling.IsXmlException cannot be compiled on Mono as it refers to a type XmlSyntaxException defined by System.Security.Permissions.

This case triggers much more rarely, only when msbuild runs into some other exception that it would otherwise be able to recover from. I've seen this when building the runtime repo on s390x - msbuild gets a DirectoryNotFoundException during a restore operation since some crossgen2 directory is not present (due to building for Mono which doesn't support crossgen2), and it would normally just recover and ignore that exception, but in the process the IsXmlException routine is called, but it cannot be JITed.

Putting the use of XmlSyntaxException under a #if FEATURE_SECURITY_PERMISSIONS guard makes that abort go away for me as well. With those two work-arounds applies, I can bootstrap source-build (i.e run the source-build using a source-built SDK) on s390x successfully.


It seems strange that a Linux build of the SDK even has any references to those 4.7 assemblies (which I understand are Windows only?) in the first place. What is the appropriate fix for these issues?

CC @crummel @leecow @omajid @tmds

Metadata

Metadata

Assignees

Labels

area-upstream-fixNeeds a change in a contributing repo

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions