P/Invoke:内存损坏与指针
Posted
技术标签:
【中文标题】P/Invoke:内存损坏与指针【英文标题】:P/Invoke: Memory corruption with pointer 【发布时间】:2014-11-10 12:28:29 【问题描述】:我正在用 Mono(所以 COM、CLI 不是选项)和一堆 extern 封装 FBX SDK(已关闭,带有公共 API)的一部分,一切进展顺利,直到我不得不返回一个非指针实例。 See here
关键是我必须将它返回给 C++ 以进行另一个调用。因为我不知道如果没有指针你会怎么做,我就这样返回了它:
FBXAPI FbxProperty* Object_GetFirstProperty(FbxObject* obj)
return &obj->GetFirstProperty();
..直到我尝试类似下一个 sn-p 的操作,我才得到 “System.AccessViolationException : Attempted to read or write protected memory。这通常表明其他内存已损坏。” 消息。
FBXAPI const wchar_t* Property_GetName(FbxProperty* prop)
int c = prop->GetSrcPropertyCount();
return L"Test";
如果我在 C++ 中使用相同的调用使用几乎相同的代码,那很好。我以同样的方式又做了大约 20 个函数调用,但不必“指针”它,它们也都很好,所以我不认为我的 DllImport 应该受到责备。因此,如果应归咎于参考,我该怎么做呢?我肯定不会因为有人从 API 调用它而在某处存储全局静态引用吗?
感谢任何帮助,C/C++ 和它处理内存的显式方式对我来说是新的。
【问题讨论】:
en.wikipedia.org/wiki/Dangling_pointer 我发现您的问题令人困惑:标题表明问题是关于非指针返回值,然后您继续解释您需要如何返回指针。此外,问题是关于 P/Invoke 但您只提供 C++ 签名,而不是相应的 C# P/Invoke 签名。 我们不知道 FbxProperty 是什么。而且我们无法判断您返回的地址是否仍然有效。而且你没有显示任何 c#。 C++/CLI 是否适合您?如果是这样,这注定要在 Windows 上编写一个 C# 包装器;通过正确的 P/Invoke 为您省去所有麻烦。 感谢 cmets,我已经澄清了新的问题标题,并澄清这是为了跨平台(单声道)分发,所以 CLI 不是一个选项 - 我希望是这样!跨度> 【参考方案1】:我假设您的程序崩溃了,因为您获得指针的属性不再存在。让我澄清一下,并从剖析以下内容开始:
FBXAPI FbxProperty* Object_GetFirstProperty(FbxObject* obj)
return &obj->GetFirstProperty();
我查阅了 FBX 的文档,FbxObject::GetFirstProperty()
的返回类型为FbxProperty
。请注意,返回值不是任何指针或引用?这意味着你会得到一个所谓的“自动变量”,或者在这种情况下是一个“临时变量”。这种对象只会持续到您离开范围,在本例中是您的包装器的Object_GetFirstProperty()
。之后,该对象被清理并从内存堆栈中删除。 FbxObject::GetFirstProperty()
为您提供该属性的副本,而不是实际参考。在内部可能会有所不同,但您的包装器关注的是属性对象本身,而不是它的内容。
所以你正在做的是你得到一个指向一个地址的指针,当你将它传递给你的Property_GetName()
时,这个地址在以后不再有效。
在对象生命周期方面,C++ 的行为与 C# 不同。 C# 中称为MyObj
的对象可以被认为是像MyObject*
这样的C++ 指针类型——它就像一个引用值。在 C# 中,您还有 struct
等值类型,它们等价于 C++ 自动变量。所有自动变量在其生命周期结束时都将被销毁。
要解决问题,您必须做的是直接保存从FbxObject::GetFirstProperty()
获得的对象,而不是指向它的指针。您基本上必须将对象编组为适当的 .NET 类,以免其内容丢失。
或者,您可以分配动态内存并复制从FbxObject::GetFirstPoperty()
获得的对象,然后返回指向您自己内存的指针。当然,您以后必须手动删除此内存。这是一个简单的例子:
FBXAPI FbxProperty* Object_GetFirstProperty(FbxObject* obj)
// Allocate custom memory.
char* myMem = new char[sizeof(FbxProperty)];
// Copy the property's content there.
std::memcpy(myMem, &obj->GetFirstProperty(), sizeof(FbxProperty));
// Return custom memory address.
return reinterpret_cast<FbxProperty*>(myMem);
这应该可以解决您的内存损坏问题。但在 C++ 中,您必须在使用完该属性后手动释放此内存:
FBXAPI void Property_Free(FbxProperty* prop)
// Free previously allocated memory
delete[] prop;
但是这种尝试可能会导致其他问题,这取决于实际的FbxProperty
如何处理它内部的数据。当然,您正在创建对象的副本,但如果原始临时/自动变量在销毁时删除了重要内存,那么您将遇到与现在类似的问题。
如果你真的很机智,你可以为你需要的每个 FBX 类型编写真正的包装类,并编组整个类类型,而不是生成单独的 C 函数,每次你想获得一个值或一个属性时你都必须 P/Invoke .
【讨论】:
以上是关于P/Invoke:内存损坏与指针的主要内容,如果未能解决你的问题,请参考以下文章
char 指向字符串的指针,然后进入字符串数组。 *** `./a.out' 中的错误:malloc():内存损坏:0x0900c3b0 ***