获取指向字节数组的指针的不安全方法
本文关键字:指针 不安全 方法 数组 字节数 取指 字节 获取 | 更新日期: 2023-09-27 18:30:35
此行为在 C# 中是否有效
public class MyClass
{
private byte[] data;
public MyClass()
{
this.data = new byte[1024];
}
public unsafe byte* getData()
{
byte* result = null;
fixed (byte* dataPtr = data)
{
result = dataPtr;
}
return result;
}
}
如果您要关闭安全系统,那么您有责任确保程序的内存安全。一旦你这样做,你就需要在没有安全系统帮助你的情况下安全地做所有事情。这就是"不安全"的意思。
正如 C# 规范明确指出的那样:
可移动变量的地址只能使用 fixed 语句获取,并且该地址仅在该固定语句的持续时间内保持有效。
您正在获取可移动变量的地址,然后在固定语句的持续时间之后使用它,因此该地址不再有效。因此,您被特别要求不要完全按照您正在做的事情去做。
在您对必须遵循的规则有透彻和深入的了解之前,您不应该编写任何不安全的代码。首先阅读规范的第 18 章。
这段代码可以很好地编译,但它会导致运行时问题。 代码实质上是偷运出指向堆中未固定对象的指针。 移动MyClass
类型的下一个 GC 也将随之移动data
引用,以前从 getData
返回的任何值现在都将指向不正确的位置。
var obj = new MyClass();
unsafe byte* pValue = obj.getData();
// Assuming no GC has happened (bad assumption) then this works fine
*pValue = 42;
// Assume a GC has now happened and `obj` moved around in the heap. The
// following code is now over writing memory it simply doesn't own
*pValue = 42;
最后一行是否导致应用程序崩溃,覆盖另一种类型的string
值,或者只是将值戳到未初始化的数组中,然后在其他地方搞砸数学问题? 你不知道。 最好的结果是代码只是很快崩溃,但在所有可能的引擎盖上,它会做一些更微妙和邪恶的事情。
Marshal.StructureToPtr()
方法代替不安全的魔法:)
StructureToPtr
将结构的内容复制到预分配 PTR 参数指向的内存块。
Marshal.StructureToPtr Method (Object, IntPtr, Boolean)
此代码将不起作用(它将编译,但在运行时会导致问题)。固定区域结束后,不再固定数据。
不,一旦您离开fixed
块,result
的值就不再有效(如果 GC 尚未运行,它可能恰好有效)。
执行此类操作的正确方法是引用通过 C# 代码访问的非托管内存中的byte[]
,或者将托管数组复制到非托管内存中。