这种不安全的代码是否也可以在.NET Core 3中使用?

杰尔吉·科塞格(GyörgyKőszeg)

我正在重构我的库,以Span<T>尽可能避免堆分配,但是由于我也针对较旧的框架,因此我也在实现一些通用的后备解决方案。但是现在我发现了一个奇怪的问题,我不确定我是否在.NET Core 3中发现了错误,或者我是否在做违法的事情。

问题:

// This returns 1 as expected but cannot be used in older frameworks:
private static uint ReinterpretNew()
{
    Span<byte> bytes = stackalloc byte[4];
    bytes[0] = 1; // FillBytes(bytes);

    // returning bytes as uint:
    return Unsafe.As<byte, uint>(ref bytes.GetPinnableReference());
}

// This returns garbage in .NET Core 3.0 with release build:
private static unsafe uint ReinterpretOld()
{
    byte* bytes = stackalloc byte[4];
    bytes[0] = 1; // FillBytes(bytes);

    // returning bytes as uint:
    return *(uint*)bytes;
}

有趣的是,它ReinterpretOld在.NET Framework和.NET Core 2.0中都可以很好地工作(毕竟我可以对此感到满意),但是,这仍然让我有些困扰。

顺便说一句。ReinterpretOld只需稍作修改,即可在.NET Core 3.0中进行修复:

//return *(uint*)bytes;
uint* asUint = (uint*)bytes;
return *asUint;

我的问题:

这是一个错误,还是ReinterpretOld仅在偶然的情况下才在旧框架起作用,我是否也应该对它们应用此修复程序?

备注:

  • 调试版本也可以在.NET Core 3.0中使用
  • 我尝试申请[MethodImpl(MethodImplOptions.NoInlining)]ReinterpretOld但没有效果。
马克·格雷韦尔

哦,这是一个有趣的发现;这里发生的事情是您的本地人正在被优化-没有剩余的本地人,这意味着没有本地人.locals init,这意味着其stackalloc行为有所不同,并且不会擦除空间;

private static unsafe uint Reinterpret1()
{
    byte* bytes = stackalloc byte[4];
    bytes[0] = 1;

    return *(uint*)bytes;
}

private static unsafe uint Reinterpret2()
{
    byte* bytes = stackalloc byte[4];
    bytes[0] = 1;

    uint* asUint = (uint*)bytes;
    return *asUint;
}

变成:

.method private hidebysig static uint32 Reinterpret1() cil managed
{
    .maxstack 8
    L_0000: ldc.i4.4 
    L_0001: conv.u 
    L_0002: localloc 
    L_0004: dup 
    L_0005: ldc.i4.1 
    L_0006: stind.i1 
    L_0007: ldind.u4 
    L_0008: ret 
}

.method private hidebysig static uint32 Reinterpret2() cil managed
{
    .maxstack 3
    .locals init (
        [0] uint32* numPtr)
    L_0000: ldc.i4.4 
    L_0001: conv.u 
    L_0002: localloc 
    L_0004: dup 
    L_0005: ldc.i4.1 
    L_0006: stind.i1 
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: ldind.u4 
    L_000a: ret 
}

我会很高兴地说,这是一个编译器错误,或至少:一个不良的副作用和行为考虑到先前的决定已经到位,说“发出.locals初始化”特别是尝试和保持stackalloc理智-但是编译器人员是否同意取决于他们。

解决方法是:将stackalloc空间视为未定义空间(公平地说,这就是您要执行的操作);如果您希望它为零:请手动将其归零。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Java中是否存在“指针”或“不安全代码”的概念?

是否可以使用.NET Core Roslyn编译器编译单个C#代码文件?

在.NET Core中使用反射

即使在project.json中将allowunsafe标志设置为true后,.Net Core中仍存在不安全的代码编译错误

是否有一些Visual Studio扩展可以检查代码中潜在的线程不安全性?

.NET Core应用程序中是否可以从AWS Certificate Manager中检索证书并在HttpClient帖子中使用它?

可以在.Net Core 2.0中使用Azure Graph吗?

在.Net Core 2.0中使用会话

是否可以在NET Core中使用SQL数据提供程序?

如何避免EF Core中不安全的上下文操作?

在项目中允许使用不安全的代码是否会产生后果?

对加密不安全的随机数使用rand()是否可以接受?

在ASP.NET Core 3中使用来自单独类的Hub

是否可以在ASP.NET Core(Swashbucle)中基于响应HTTP代码设置响应内容类型?

我是否应该使用WinForms控件修改nuget包以在.NET Core 3应用程序中使用?

是否可以从针对.NET Standard 2.x的库中使用ASP .Net Core 3.1?

在.NET Core 3中使用NLog管理日志记录配置

在LINQ Query Net Core 3中使用功能逻辑

是否可以在Linux上使用.Net Core 3.1创建C ++ / CLI代码的C#DLL

如何在.NET Core 3中使用LINQ语法查询多个表

使用Canvas时是否可以避免“操作不安全”?

使用pinvoke会将.NET标记为不安全吗?

Firebase是否仍可以使用不安全的WebSocket?

在C#中使不安全代码安全

是否可以在带有.NET Framework的.NET Core中使用

我可以安全地在ASP.NET Core和EF Core中使用非泛型DbContextOptions吗?

如何在 ASP.Net Core 3 中使用 UseNodeModules?

是否可以在 ASP .NET Core 中使用 Swashbuckle 以 Swagger 2.0 和 Open API 3 格式公开相同的 Swagger JSON?

如何检查 .Net dll 是否使用不安全代码?