他们固定它4.0,打破了2.0:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication13
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
// For .NET 4.0
//[System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions]
static unsafe void Main(string[] args)
{
IntPtr ptr = VirtualAlloc(
IntPtr.Zero,
(IntPtr)(4096 * 2),
0x1000 /* MEM_COMMIT */ | 0x2000 /* MEM_RESERVE */,
0x04 /* PAGE_READWRITE */);
IntPtr page1 = ptr;
IntPtr page2 = (IntPtr)((long)ptr + 4096);
uint oldAccess;
bool res = VirtualProtect(page2, 4096, 0x01 /* PAGE_NOACCESS */, out oldAccess);
try
{
Marshal.WriteByte(page1, 1);
Console.WriteLine("OK");
}
catch (AccessViolationException)
{
Console.WriteLine("KO");
}
try
{
Marshal.WriteByte(page2, 1);
Console.WriteLine("KO");
}
catch (AccessViolationException)
{
Console.WriteLine("OK");
}
try
{
byte b1 = Marshal.ReadByte(page1);
Console.WriteLine("OK");
}
catch (AccessViolationException)
{
Console.WriteLine("KO");
}
try
{
byte b2 = Marshal.ReadByte(page2);
Console.WriteLine("KO");
}
catch (AccessViolationException)
{
Console.WriteLine("OK");
}
for (int i = 0; i < 4096; i++)
{
Marshal.WriteByte(page1, i, (byte)'A');
}
sbyte* ptr2 = (sbyte*)page1;
try
{
var st1 = new string(ptr2, 0, 4096);
Console.WriteLine("OK");
}
catch (ArgumentOutOfRangeException)
{
Console.WriteLine("KO");
}
}
}
}
你必须取消注释一行在.NET 4.0中。请注意,此代码不会释放它分配的内存,但它不是一个大问题,因为当进程结束时,操作系统会回收内存。
这个程序做了什么?它使用VirtualAlloc
分配8192字节(2页)。通过使用VirtualAlloc
这两页是页面对齐的。它禁止访问第二页(使用VirtualProtect
)。然后它填写'A'
的第一页。然后它会尝试从第一页创建一个string
。在.NET 2.0上,string
构造函数尝试读取第二页的第一个字节(即使您告诉它该字符串只有很长的4096字节)。
在中间有一些测试,检查,如果页面可以被读取/写入。
一般而言,这是难以检查该条件,因为它很难有一个内存块,这正是在所分配的可读存储器空间的末尾。