You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中VirtualAlloc分配内存后写入字节数组读取异常求助

C#虚拟内存操作:Marshal.Copy写入后读取数据不符问题

在C#中使用VirtualAlloc分配虚拟内存后,通过Marshal.Copy写入字节数组,但从同一地址读取时得到错误数据。原代码如下:

byte[] arr = {1,2,3,4,5,6,7,8,9,10};

Console.WriteLine("arr: ");
for (int i = 0; i < arr.Length; i++){ 
    Console.Write("0x{0:X2} , ", arr[i]);
}
Console.WriteLine("");

UInt32 codeAddr = VirtualAlloc(0, (UInt32)arr.Length, MEM_COMMIT, PAGE_READWRITE);
Console.WriteLine("Code Address: 0x{0:X8}",codeAddr);

Marshal.Copy(arr, 0, (IntPtr) (codeAddr), arr.Length);

Console.WriteLine("arr at 0x{0:X8}: ",codeAddr);  
byte value=0;
for (int i = 0; i < arr.Length; i++){
    value = Marshal.ReadByte(codeAddr, i);
    Console.Write("0x{0:X2} , ", value);
}
Console.WriteLine("");

运行输出:

C:\Users\thm\Desktop>koko.exe 
arr:
0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0A ,
Code Address: 0x00770000
arr at 0x00770000:
0x00 , 0x00 , 0x77 , 0x00 , 0x0A , 0xD5 , 0x0A , 0x00 , 0xB7 , 0x46 ,

问题原因

错误核心在Marshal.ReadByte(codeAddr, i)这一行:

  • Marshal.ReadByte有两个重载:ReadByte(IntPtr ptr, int offset)(读取指定非托管内存地址的字节)和ReadByte(Object obj, int offset)(读取托管对象内存中指定偏移的字节)。
  • 你传入的codeAddr是UInt32类型,会被匹配到ReadByte(Object, int)重载,此时函数会把codeAddr当作一个托管值类型对象,读取的是该对象在托管堆中的内存数据,而非你通过VirtualAlloc分配的虚拟内存地址。

另外,用UInt32存储内存地址在64位系统下存在风险——64位地址长度超出UInt32的范围,会导致地址截断,引发更严重的错误。

修复方案

  1. 使用IntPtr类型存储内存地址(IntPtr是专门适配32/64位系统的内存地址存储类型)。
  2. 调用Marshal.ReadByte时,确保传入IntPtr类型的地址。

修复后的代码:

byte[] arr = {1,2,3,4,5,6,7,8,9,10};

Console.WriteLine("arr: ");
for (int i = 0; i < arr.Length; i++){ 
    Console.Write("0x{0:X2} , ", arr[i]);
}
Console.WriteLine("");

// 用IntPtr存储内存地址
IntPtr codeAddr = VirtualAlloc(IntPtr.Zero, (UInt32)arr.Length, MEM_COMMIT, PAGE_READWRITE);
Console.WriteLine("Code Address: 0x{0:X8}",codeAddr);

Marshal.Copy(arr, 0, codeAddr, arr.Length);

Console.WriteLine("arr at 0x{0:X8}: ",codeAddr);  
byte value=0;
for (int i = 0; i < arr.Length; i++){
    // 传入IntPtr类型的地址
    value = Marshal.ReadByte(codeAddr, i);
    Console.Write("0x{0:X2} , ", value);
}
Console.WriteLine("");

修复后运行,读取的字节序列会和写入的完全一致。

内容的提问来源于stack exchange,提问作者Amr Alasmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 22:44:50