使用Peverify和ILVerify对不安全的c#返回类型进行验证错误

时间:2018-01-22 13:47:05

标签: c# cil peverify

在验证包含返回指针的不安全方法的某些代码时,我遇到了这个问题。

示例可以表示为:

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。

重现的步骤:

  1. 使用csc example.cs /t:library /unsafe
  2. 编译示例代码
  3. 验证peverify example.dll
  4. 验证ILVerify.exe -r C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll example.dll
  5. 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

    神秘之处在于,一切都按预期编译和运行,它无法验证。有没有人对这种情况有什么见解?

1 个答案:

答案 0 :(得分:7)

基本上:不安全的代码无法验证。你得到的确切消息往往是模糊和混乱,但又一次:不安全的代码(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);
}

这不使用不安全的代码。 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.