我在验证一些包含返回指针的不安全方法的代码时遇到了这个问题.
示例可以表示为:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我使用两个单独的验证工具,即ILVerify和Peverify.
重现步骤:
csc example.cs /t:library /unsafepeverify example.dllILVerify.exe -r C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll example.dll 2.和3.都将导致以下错误消息:
[IL]:错误:[C:\ src\test\example.dll:A :: GetAnswer()] [偏移量0x00000006] [找到Int32的地址]堆栈上的预期数字类型.
[IL]:错误:[C:\ src\test\example.dll:A :: Main()] [offset 0x00000009] [找到Native Int]预期在堆栈上的ByRef.2错误验证C:\ src\test\example.dll
神秘的是,一切都按预期编译和运行,它不会验证.有没有人对这种情况有什么了解?
从根本上说:不安全的代码是无法验证的.你得到的确切消息往往是模糊和混乱,但再次:不安全的代码(badum tsh)!
更糟糕的是:问题中的代码被主动打破 - 当你从已经退出的堆栈框架访问指针时,没有定义的行为.在这种情况下,您通常会使用它并查看最后的值,但是:它没有定义.
如果你想要可验证的代码,你将需要切换到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);
}
Run Code Online (Sandbox Code Playgroud)
这不使用不安全的代码.GetAnswer返回对数组中第一个元素的引用(不是第一个元素的值) - 作为托管指针(ref T是托管指针; T*是非托管指针).为托管指针分配i = {someRef}(而不是i = ref {someRef})deferences,就像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.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
238 次 |
| 最近记录: |