I have run into this issue when verifying some code containing an unsafe method that returns a pointer.
The example can be expressed as this:
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);
}
}
I am using two separate verification tools, namely ILVerify and Peverify.
Steps to reproduce:
csc example.cs /t:library /unsafe
peverify example.dll
ILVerify.exe -r C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll example.dll
Both 2. and 3. will result in the error message below:
[IL]: Error: [C:\src\test\example.dll : A::GetAnswer()][offset 0x00000006][found address of Int32] Expected numeric type on the stack.
[IL]: Error: [C:\src\test\example.dll : A::Main()][offset 0x00000009][found Native Int] Expected ByRef on the stack. 2 Error(s) Verifying C:\src\test\example.dll
The mystery is that everything compiles and runs as expected, it will not verify. Does anyone have some insight knowledge about why this is the case?
Fundamentally: unsafe code is unverifiable. The exact messages you get back will often be vague and confusing, but then again: so is unsafe code (badum tsh)!
Worse: the code in the question is actively broken - there is no defined behaviour for what happens when you access a pointer from a stack-frame that has exited. In this case you'll usually get away with it and see the last values, but: it isn't defined.
If you want verifiable code, you're going to need to switch to ref return
; for example:
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);
}
This uses no unsafe code. GetAnswer
returns a reference to the first element in the array (not the value of the first element) - as a managed pointer (ref T
is a managed pointer; T*
is an unmanaged pointer). Assigning i = {someRef}
(rather than i = ref {someRef}
) deferences the managed pointer, exactly like i = *{somePtr}
does for an unmanaged pointer.
This verifies cleanly:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With