ヒープ割り当てを回避するために_Span<T>
_を使用するようにライブラリをリファクタリングしていますが、古いフレームワークも対象としているため、いくつかの一般的なフォールバックソリューションも実装しています。しかし今、私は奇妙な問題を発見しました。NETCore 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
が誤って機能するのですか。また、それらにも修正プログラムを適用する必要がありますか?
備考:
[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 initを放出する」と言う場で 、具体的にはstackalloc
sane-コンパイラを人々は同意することは彼ら次第です。
回避策は次のとおりです。stackalloc
スペースを未定義として扱います(公平にするために、これはあなたが意図していることです)。ゼロになることが予想される場合:手動でゼロにします。