在验证一些包含返回指针的不安全方法的代码时,我遇到了这个问题。
该示例可以表示如下:
public class A
{
public static unsafe int* GetAnswer()
{
int fakeValue = 42;
return &(fakeValue);
}
public static void Main()
{
int i = 0;
unsafe { i = *A.GetAnswer(); }
System.Console.WriteLine(i);
}
}我正在使用两个独立的验证工具,即ILVerify和Peverify。
复制步骤:
csc example.cs /t:library /unsafe编译示例代码peverify example.dllILVerify.exe -r C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll example.dll2和3都将导致以下错误消息:
IL: Error: C:\src\test\example.dll :a::GetAnswer()找到堆栈上Int32期望的数字类型的地址。 IL: Error: C:\src\test\example.dll :a::Main()在堆栈上找到了本机Int期望的ByRef。验证C:\src\test\example.dll的2错误
神秘的是,所有的东西都会像预期的那样编译和运行,它不会进行验证。有谁对为什么会这样有洞察力吗?
发布于 2018-01-22 14:23:32
从根本上说,不安全的代码是不可验证的。你得到的确切信息通常是模糊和混乱的,但话又说回来:不安全的代码(badum )也是如此!
更糟糕的是:问题中的代码是主动中断的--当您从已退出的堆栈帧访问指针时,没有定义的行为。在这种情况下,您通常会忽略它,并看到最后的值,但是:它没有定义。
如果您需要可验证的代码,则需要切换到ref return;例如:
static ref int GetAnswer(int[] arr)
{
return ref arr[0];
}
static void Main()
{
int i = 0;
int[] j = new int[] { 42 };
i = A.GetAnswer(j);
System.Console.WriteLine(i);
}这不使用不安全的代码。GetAnswer返回对数组中第一个元素的引用(而不是,第一个元素的值)-作为托管指针(ref T是托管指针;T*是非托管指针)。分配i = {someRef} (而不是i = ref {someRef})可以推断托管指针,就像i = *{somePtr}对非托管指针所做的那样。
这清楚地验证了:
Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.0
Copyright (c) Microsoft Corporation. All rights reserved.
All Classes and Methods in ConsoleApp35.exe Verified.https://stackoverflow.com/questions/48383066
复制相似问题