Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSBuild v14 compiles a semantically incorrect assembly under some rare circumstances

After a build environment update, one of our Smoke Tests broke in TeamCity. Investigation turned out that from the same source code,

  • C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe produces correct binary
  • C:\Program Files (x86)\MSBuild\14.0\bin\MSBuild.exe produces incorrect binary

When does this occur

  • “params object[]” is used
  • only a single value is passed, without being explicitly wrapped within an array
  • named parameters are used
  • in a different order than they were in the method signature

Sample code to reproduce it

static void Main(string[] args)
{
    var customerId = Guid.NewGuid();

    // Produces buggy code when compiled with MSBuild v14
    TestMethodWithParams(args: customerId, whatever: "foo");

    //All the calls below result correct behavior, regardless of the version of MSBuild, order and naming of parameters
    TestMethodWithParams("foo", customerId);
    TestMethodWithParams(whatever: "foo", args: customerId);

    TestMethodWithParams(args: new object[] { customerId }, whatever: "foo");
    TestMethodWithParams("foo", new object[] { customerId });
    TestMethodWithParams(whatever: "foo", args: new object[] {customerId});
}

private static void TestMethodWithParams(string whatever, params object[] args)
{
    Console.WriteLine("args: '{0}'", args);
}

What exactly happens

The incorrect version just swallows the single parameter, null is being passed. Decompiled code shows the difference:

In correct binary:

Guid guid = Guid.NewGuid();
Program.TestMethodWithParams("foo", new object[]
{
    guid
});

In incorrect binary:

Guid guid = Guid.NewGuid();
object obj;
Program.TestMethodWithParams("foo", new object[]
{
    obj // <- this is and will always be null
});

How to fix it

When we wrapped the single parameter into an object array, the problem was gone. Another option would be not to use named arguments, and/or make sure that the order of occurence of parameters is the same in the invocation and in the signature.

BUT: The main problem is that we cannot revert to an older MSBuild (...), and checking the whole codebase (and going through each and every binary in the crowd of our NuGet packages as well) is not an easy and effective solution. Moreover, this kind of error might be reintroduced into the codebase any time later accidentally. So the best solution would probably be to somehow fix MSBuild.

Has anyone experienced something like this? Might it be a bug in MSBuild? Ideas?

like image 750
Dávid Tereánszky Avatar asked May 26 '16 09:05

Dávid Tereánszky


2 Answers

As I already mentioned on the GitHub issue, I believe this is the bug that was originally reported as #4197 and was fixed in Roslyn 1.1.

like image 143
svick Avatar answered Oct 31 '22 05:10

svick


thank you for all the info and suggestions. You shared details that helped us to track down this issue. Turned out that installing "Microsoft Build Tools 2015 with Update 2" solved our problem.

Thanks again everyone. /David

like image 29
Dávid Tereánszky Avatar answered Oct 31 '22 06:10

Dávid Tereánszky