为什么在优化代码时从byte转换为sbyte会给出错误的值?

15

如果已安装NUnit 3,则可以使用以下代码示例重现该问题。

[TestFixture]
public class SByteFixture
{
    [Test]
    public void Test()
    {
        var data = new byte[] { 0xFF };

        sbyte x = -128;
        data[0] = (byte) x;
        byte b1 = data[0];
        var b2 = (sbyte) b1;
        Assert.AreEqual(b1.ToString(), "128");
        Assert.AreEqual(b2.ToString(), "-128");
    }
}
  1. 这个项目应该是一个类库,因为在控制台应用程序中它不可再现。
  2. 应启用优化,即在csproj文件中添加以下设置:

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <Optimize>true</Optimize>
    </PropertyGroup>
    

Optimize 为 false 时,测试用例通过,但当 Optimize 为 true 时 (b2.ToString() 返回 "128"),测试用例则失败

使用 ReSharper 来运行测试用例或者 NUnitConsole,可以看到这种情况。但在 VS Test Explorer 中无法复现该问题。

这是怎么解释的呢?


12
这个 bug 只在启用优化的 64 位 jitter 中出现,可能是为什么它似乎难以复现的原因。我之前见过这种问题,优化器的这部分很脆弱。问题出在 (sbyte) 转换产生了错误的代码,应该使用 MOVSX 处理器指令(从字节到整型的符号扩展),但却使用了 MOVZX。不正确的零扩展会生成一个正数。点击新建议题按钮,让他们知道这个问题。 - Hans Passant
有人可以将这个问题展示给新用户作为如何撰写问题的示例吗?谢谢。 - Liam
4
听起来像是一个答案 ;) - BartoszKP
2
找到即时编译器的错误总是很有趣 :) - usr
1个回答

1

正如@HansPassant所建议的那样,我已在GitHub上报告了此问题,并且似乎是一个已确认的错误。

以下是来自mikedn的有关此问题的引用:

你可以在类库中复现而无法在控制台应用程序中复现,这可能意味着你正在使用.NET Framework而不是.NET Core。在.NET Framework控制台应用程序默认为32位,因此它们使用旧版JIT32而不是RyuJIT。64位.NET Framework应用程序使用RyuJIT,但通常比.NET Core使用的版本旧。

我可以使用64位.NET Framework 4.7.2来复现此问题,但在当前的.NET Core主版本中无法。可以使用.NET Core 2.1来重现它,因此很可能已经在主版本中修复了此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接