C#通过PInvoke释放C++分配的二维double数组时程序崩溃如何解决
崩溃核心原因
- 首要原因:传递给释放函数的指针已经是非法的偏移后地址
你编写的FromNative方法使用了ref IntPtr data作为参数,循环中每次执行data = (IntPtr)(data.ToInt64() + IntPtr.Size)直接修改了外部传入的jointAreaPointer原始值。读取完全部数据后,jointAreaPointer已经不再指向C分配的double**数组起始地址,而是偏移了numberOfPairs * IntPtr.Size的野指针。将野指针传入C释放函数后,访问arr[i]直接触发非法内存访问,导致崩溃。 - 次要潜在问题:P/Invoke的bool类型封送不匹配
C#默认将bool类型封送为4字节的Win32 BOOL,而C++端的bool是1字节类型,参数传递时会出现栈偏移,也可能触发崩溃。
修复方案
1. 修正FromNative方法,不要修改原始指针
两种修改方式二选一:
- 去掉多余的
ref关键字,你不需要修改外部的原始指针,完全没必要用ref:
// 去掉参数的ref修饰 public static double[][] FromNative(IntPtr data, int m, int[] n) { var matrix = new double[m][]; IntPtr currentPtr = data; // 用临时变量做偏移,不修改原始指针 for (int i = 0; i < m; i++) { int c = n[i] * 3; matrix[i] = new double[c]; Marshal.Copy(Marshal.ReadIntPtr(currentPtr), matrix[i], 0, c); currentPtr = (IntPtr)(currentPtr.ToInt64() + IntPtr.Size); } return matrix; } // 调用时也不需要加ref double[][] polylinePoints = FromNative(jointAreaPointer, numberOfPairs, jointAreaCountPointerFlatArray);
- 如果你一定要保留
ref修饰,就用临时变量做偏移,不要修改入参的data。
2. 修正P/Invoke的bool类型封送
给C#端的bool参数加封送标记,匹配C++的1字节bool:
[DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] internal static extern void ReleaseNestedDouble(IntPtr arr, int count, [MarshalAs(UnmanagedType.I1)] bool isArray = true);
3. 额外校验项
确保C++端分配内存时,外层double**数组和内层每个double*数组都是用new[]分配的,和delete[]对应,不能混用malloc/free或者new/delete。
内容的提问来源于stack exchange,提问作者Petras
相关产品推荐
相关产品推荐

