首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CLR中的堆栈合并点和托管指针

CLR中的堆栈合并点和托管指针
EN

Stack Overflow用户
提问于 2022-06-22 22:34:23
回答 1查看 92关注 0票数 1

我的理解是允许运行“不可验证的”和“可验证的”.NET字节码。但是,在这两种情况下,字节码在ECMA-CIL方面都必须是“正确的CIL”。使用C#的不安全特性可以生成正确但不可验证的字节码。可验证的字节码可以来自日常的C#。

无论哪种方式,.NET CLR必须以某种方式保证字节码是正确的。为此,必须在每次指令之前静态推断有关堆栈状态的基本信息。例如,元素的数量和非常粗糙的类型推断。如果推断的信息有一个以上的前身,则必须在基本块的开头合并它。

我的问题是,是否允许合并不同类型的托管指针?我指的是正确的CIL,但不一定是可验证的CIL。

代码语言:javascript
复制
.method public static void Bar (int32& a, uint32& b, bool d) cil managed
{
    .maxstack 8
    IL_0003: ldarg.2
    IL_0004: brfalse.s IL_000b

    IL_0006: ldarg.0
    IL_0009: br.s IL_000d

    IL_000b: ldarg.1

    IL_000d: pop
    IL_000e: ret
}

ILVerify报告:

代码语言:javascript
复制
IL]: Error [PathStackUnexpected]: [Test.dll : .Test::Bar(int32&, uint32&, bool)][offset 0x00000006][found address of Int32][expected address of UInt32] Non-compatible types on stack depending on path.

我的问题是,我不知道这是关于字节码的可验证性还是正确性。我指的是“可验证性”和“正确性”,就像ECMA中定义的那样。我也不知道我是否误解了标准。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-31 13:10:58

ECMA-335,第83页说:

程序中任意给定点的堆栈类型状态(堆栈深度和堆栈上每个元素的类型)对于所有可能的控制流路径都应该是相同的。例如,在每次迭代时循环未知次数并在堆栈上推送一个新元素的程序将被禁止。

第85页加强了这一点:

无论允许执行到那里的控制流是什么,堆栈上的每个插槽在方法主体内的任何给定点上都应该具有相同的数据类型。

因此,一般来说,堆栈上的元素类型必须是相同的。但是,第I.12.3.2.1节继续指定计算堆栈仅由以下类型组成:int64int32native intF&O、*( native int&)或任意用户定义的值类型。

这似乎意味着,虽然CIL将int32&uint32&视为不同类型,但评估堆栈将它们都视为&,因此对于两个控件流而言,“类型状态”是相同的。因此,CIL是正确的。

可验证性是一个更强的标准,确保程序最终是内存安全的,并且在程序内存的所有情况下都有可预测的结果。验证不使用CLI用于计算堆栈的有限数量的类型,而是要求类型状态是兼容的,通常是通过具有相同的验证类型。

在您的例子中,重要的是引用变量的类型:int32uint32。如第36页所述:

类型T的验证类型如下:

..。

2.如果T是托管指针类型S&而减少的S类型是:

..。

int32,那么它的验证类型是is 32&。

同样,在同一页上:

T类型的简化类型如下:

1.如果T的基本类型是:

..。

int32,或无符号int32,则其简化类型为int32。

因此,简化的类型都是int32,因此这两个参数的验证类型都是int32&,而不管它们的签名性如何,因此CLI是可验证的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72722687

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档