MSBuild v14在极少数情况下编译语义错误的程序集

时间:2016-05-26 09:42:16

标签: c# compilation msbuild binary roslyn

在构建环境更新后,我们的一项Smoke Tests在TeamCity中爆发。调查结果显示,来自相同的源代码,

  • C:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild.exe生成正确的二进制文件
  • C:\ Program Files(x86)\ MSBuild \ 14.0 \ bin \ MSBuild.exe生成错误的二进制文件

何时发生

  • “params object []”用于
  • 只传递一个值,而不是显式包装在数组
  • 使用命名参数
  • 的顺序与方法签名中的顺序不同

重现的示例代码

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);
}

究竟发生了什么

错误的版本吞下单个参数,传递。反编译代码显示了差异:

正确的二进制文件:

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

错误的二进制文件:

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

如何修复

当我们将单个参数包装到对象数组中时,问题就消失了。另一个选择是不使用命名参数,和/或确保参数的出现顺序在调用和签名中是相同的。

但是:主要的问题是我们无法恢复到较旧的MSBuild(...),并且检查整个代码库(并通过我们的NuGet包中的每一个二进制文件)并不容易有效的解决方案。而且,这种错误可能会在以后的任何时候意外地重新引入代码库。因此,最好的解决方案可能是以某种方式修复MSBuild。

有没有人经历过这样的事情?可能是MSBuild中的一个错误?想法?

2 个答案:

答案 0 :(得分:4)

正如我在GitHub问题上已经提到的那样,我认为这是最初报告为#4197并在Roslyn 1.1中修复的错误。

答案 1 :(得分:2)

感谢您提供所有信息和建议。您分享了有助于我们追踪此问题的详细信息。原来,安装“Microsoft Build Tools 2015 with Update 2”解决了我们的问题。

再次感谢大家。 /大卫