为什么这个 .NET IL 空值检查没有按预期工作?
Why is this .NET IL null check not working as expected?
我正在编写一些自定义 IL,需要与 return SomeStaticField != null;
等效的东西。这是我的自然结论:
volatile.ldsfld ...SomeStaticField //volatile is needed here for unrelated reasons
ldnull
ceq
not
ret
但是,这似乎不起作用。我确认 SomeStaticField 为 null,但此函数最终将返回 true。我知道 C# 为这样的构造使用分支,我也可以使用它,但令我困惑的是为什么这不会有预期的行为
完整且可验证的示例(作为库):
.assembly extern /*23000001*/ mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly 'BareMetal'
{
.custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() = (
01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module BareMetal.dll
.namespace Earlz.BareMetal
{
.class public auto ansi abstract sealed beforefieldinit BareMetal
extends [mscorlib]System.Object
{
.method public static hidebysig
default bool FooTest () cil managed
{
.maxstack 2
ldnull
ldnull
ceq
not
ret
}
}
}
not
计算其操作数的按位补码:~1
是 -2
,它非零,为真。否定布尔值的规范方法是 ldc.i4.0 ; ceq
.
而且,正如@HansPassant 指出的那样,直接进行 != null
比较的规范方法是 cgt.un
——所有有效引用在被解释为无符号值时都是 "greater than zero"。 ECMA-335 部分 I.12.1.5:
中明确记录了此类比较是安全的
In particular, object references can be:
...
- Created as a null reference (
ldnull
)
...
Managed pointers have several additional base operations.
...
- Unsigned comparison and conditional branches based on two managed pointers (
bge.un
, bge.un.s
, bgt.un
, bgt.un.s
, ble.un
,
ble.un.s
, blt.un
, blt.un.s
, cgt.un
, clt.un
).
我正在编写一些自定义 IL,需要与 return SomeStaticField != null;
等效的东西。这是我的自然结论:
volatile.ldsfld ...SomeStaticField //volatile is needed here for unrelated reasons
ldnull
ceq
not
ret
但是,这似乎不起作用。我确认 SomeStaticField 为 null,但此函数最终将返回 true。我知道 C# 为这样的构造使用分支,我也可以使用它,但令我困惑的是为什么这不会有预期的行为
完整且可验证的示例(作为库):
.assembly extern /*23000001*/ mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly 'BareMetal'
{
.custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() = (
01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module BareMetal.dll
.namespace Earlz.BareMetal
{
.class public auto ansi abstract sealed beforefieldinit BareMetal
extends [mscorlib]System.Object
{
.method public static hidebysig
default bool FooTest () cil managed
{
.maxstack 2
ldnull
ldnull
ceq
not
ret
}
}
}
not
计算其操作数的按位补码:~1
是 -2
,它非零,为真。否定布尔值的规范方法是 ldc.i4.0 ; ceq
.
而且,正如@HansPassant 指出的那样,直接进行 != null
比较的规范方法是 cgt.un
——所有有效引用在被解释为无符号值时都是 "greater than zero"。 ECMA-335 部分 I.12.1.5:
In particular, object references can be:
...
- Created as a null reference (
ldnull
)...
Managed pointers have several additional base operations.
...
- Unsigned comparison and conditional branches based on two managed pointers (
bge.un
,bge.un.s
,bgt.un
,bgt.un.s
,ble.un
,ble.un.s
,blt.un
,blt.un.s
,cgt.un
,clt.un
).