为外部 dll 上的缓冲区分配内存并在主应用程序上使用它是不是安全?

Posted

技术标签:

【中文标题】为外部 dll 上的缓冲区分配内存并在主应用程序上使用它是不是安全?【英文标题】:Is it safe to allocate memory for buffers on external dll and use it on main application?为外部 dll 上的缓冲区分配内存并在主应用程序上使用它是否安全? 【发布时间】:2010-01-28 13:54:36 【问题描述】:

如主题.. 我在一个应用程序中发现了类似的内容。在主 C 应用程序中,我们有声明:

void* buff = NULL;

后来有一个电话:

ReadData(&buff);
SaveToFile(buff);

SaveToFile() 是来自 main 函数的 C 函数。

ReadData(void* * ) 是来自外部 dll 的 C++ 函数。在这个函数中,缓冲区的内存由malloc函数分配并存入数据。

所以这是我的问题:它正确吗?

【问题讨论】:

请不要使用 html 格式化您的 *** 问题。使用文本输入区域上方的格式按钮。 【参考方案1】:

正在运行的进程中的所有模块共享相同的地址空间(不管你是 Windows 还是 Linux 或其他什么,这是一个共同的原则)。但是,请注意:从模块 A 读取或写入模块 B 拥有的缓冲区是可以的 - 但释放缓冲区可能很糟糕。

在 Windows 上,它取决于应用程序所链接的运行时库。如果不是 DLL 运行时('多线程 dll'),每个模块都维护自己的堆管理器副本。因此,分配内存区域的模块也必须负责销毁它,因为只有它自己的堆管理器知道它。如果您遵循此指南,您将不会遇到问题(链接到 DLL 运行时可以避免该问题,因为所有模块都处理驻留在 msvXXXnnn.dll 某处的同一个堆管理器,但会引发其他问题)。

编辑:

ReadData(void* * ) 是来自外部 dll 的 C++ 函数。在这个函数中,缓冲区的内存由 malloc 函数分配并存入数据。

这可能会遇到上述分配器问题。要么向该 DLL (FreeData) 添加另一个函数,该函数明确负责释放缓冲区(由 Neil Butterworth 提议),然后调用它自己的 free()。或者您添加一个 DLL 函数来查询缓冲区的大小,预先分配它并将其传递给 ReadData(这是 imo 最干净的选择)。

【讨论】:

在回答自己或编辑现有答案之前阅读其他答案总是一个好主意。【参考方案2】:

如果 DLL 和主可执行文件都链接到同一个 C 运行时,这没问题,您可以在指针上调用 free() 来释放它。然而,更好的想法是在 DLL 中提供一个释放数据的函数 FreeData( void * )。这样,所有内存管理都在 DLL 的上下文中完成。

【讨论】:

【参考方案3】:

很安全。但是,您应该始终检查:

如果相同的分配器用于分配和解除分配 负责释放(所以没有意外) 注意任何类型的自动内存管理(如果是纯 C/C++ 则没问题)。

【讨论】:

【参考方案4】:

这取决于设计的意图和图书馆所针对的用户。更好的方法是获取一个固定大小的缓冲区并填充它并返回。但是,释放缓冲区时应该小心。最好调用第三方 DLL 本身提供的 free 函数(如果有的话),而不是从 main 中调用 free。

在 Windows 的情况下,如果您的第三方 DLL 使用不同的堆并且如果您的应用程序使用不同的堆,则可能会导致未定义的行为。例如:如果您的第三方 DLL 是使用 VC8 构建的,而您的应用程序是使用 VC6 构建的,那么如果您释放外部 DLL 分配的内存,则会导致问题。

【讨论】:

【参考方案5】:

是的,这是正确的。进程中的内存同样可以被该进程中的所有模块(EXE 和 DLL)访问。

【讨论】:

【参考方案6】:

是的,这个没有问题。

【讨论】:

以上是关于为外部 dll 上的缓冲区分配内存并在主应用程序上使用它是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

在堆栈上分配大缓冲区

DLL函数上的Haskell外部导入stdcall

Netty源码分析--内存模型(上)

浅谈java内存分配和回收策略

指针做参数的动态内存分配与二重指针(上)

深入理解Java虚拟机之读书笔记三 内存分配策略