c++ - 用户 DLL/EXE 中的堆分配失败

标签 c++ dll exe new-operator heap-memory

正确链接的 DLL 和 EXE 应该有一个自由存储区,它们都可以从中分配基于堆的对象。这是 Chis Becke 在 Who allocates heap to a DLL? 中的回答:

… it is the C++ runtime that is responsible for creating its freestore and deciding how to allocate it. Specifically, if you use the Dll runtime option, then a single dll - msvcrtxx.dll - manages a single freestore that is shared between all dll's, and the exe, that are linked against that dll

既然这是真的,那么我应该能够在其他 DLL/EXE 中定义 DLL/EXE 中的 new 对象。根据 Chris 的说法,msvcrtxx.dll 和编译时/运行时链接器负责在何处获取所有 DLL/EXE 的 union 自由存储区。

这对我不起作用。

为了对此进行测试,我生成了两个 MFC 对话框程序:NewFailMfc1NewFailMfc2。执行 NewFailMfc2 时,运行访问 NewFailMfc1Www 函数的 new 失败。

// Code in NewFailMfc1.
void Www()
{
  char* ch { nullptr };
  ch = new char[ 100 ]; // error: attempts to allocate memory somewhere else than in the prescribed joint DLL/EXE freestore
  ch[ 0 ] = '\0';
}

// Calling code in NewFailMfc2.
Www();

比我更了解 DLL/EXE freestore 工作原理的人知道问题出在哪里吗?

(我曾在“在 ::operator newMyApp1 中编译时全局函数 MyApp2 失败。在询问过程中,我发现该问题比 <random> 标准库中发生的问题更普遍。)

编辑1:

在 MSDN 中,一个不错的虚拟代理为我找到了 Potential Errors Passing CRT Objects Across DLL Boundaries。不幸的是,它推荐的唯一解决方案是使用 /MD 编译器选项编译所有程序,而不是使用多个 CRT 拷贝的 /MT,这会自动导致越界和内存访问冲突。

这对像我这样的应用开发者来说可不是什么好消息。我需要的是最佳实践,这样我就可以应用它并按时完成交付,而不必处理神秘的低级内存问题。我怎么知道 ::operator new 类型中有对全局 std:random_device 的隐藏调用?我不会,直到它访问被侵犯。直到现在,在所有这些研究之后,我才意识到通过调用全局 new,它越界了,这使我的 DLL/EXE 发生了访问冲突。非常晦涩。

编辑2:

我已经在 Visual Studio 中提交了一份关于 std::random_device 实现的错误报告。请参阅“std::random_device 实例化在某些情况下会导致访问冲突”。

最佳答案

无论这意味着什么,都有可能跨越边界 :) 首先,您需要了解发生了什么。

当你分配内存时,实际上 CRT 可以分配比你要求的多一点。例如。流行的做法(至少在过去)是多分配 4 个字节(用您的系统位数代替),在开头写入分配的内存大小,然后返回 ptr + 4 给您。因此,当您释放内存时,系统知道它应该释放多少。

这是一个有点简化的图片。不同的编译器、相同编译器的不同版本和相同编译器相同版本的不同配置可以不同地执行此操作。例如。调试配置可以使用一些填充来检测缓冲区溢出和其他技巧。因此,当您在一个二进制文件中分配内存并在另一个二进制文件中解除分配时,如果使用不同的编译器,这可能会导致内存损坏(在最好的情况下会立即崩溃)。

这个和许多其他原因导致了一个常见的建议:释放分配内存的二进制文件中的内存。这通常通过提供 API 类的 Release 成员函数并将析构函数设为私有(private),或者通过使用自定义删除器的 unique_ptr(或 shared_ptr)来实现,或其他技术。

现在关于/MD 建议。 /MD 表示动态 CRT(= 在 dll 中),并且由于不可能在同一进程中两次加载相同的 dll,这意味着相同的 CRT 将用于分配和释放。这仍然不是针对不同版本或不同编译器的解决方案。例如。许多应用程序使用插件系统,在这种情况下,要求所有插件都由特定的编译器/版本/配置编译不是一个好主意

关于c++ - 用户 DLL/EXE 中的堆分配失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45804799/

相关文章:

c++ - 使用 mutator 更新头部的下一个时,链表 C++ 不保存

c++ - 解析来自 dll 的 C++ undefined reference (so's)

c++ - C++ 中的 DLL 导出和继承

c# - 在 Visual C# 中创建头文件 (.h) 和 .lib 文件

node.js - 如何使用 Electron 生成器将 v8 快照打包到 exe 中?

python - Windows 10/11 上的 .exe 文件附带的文件存储在哪里?

python - 致命的 Python 错误 : Py_Initialize: unable to load the file system codec. 导入错误:没有名为 'encodings' 的模块

c++ - 为什么我不能在下面的代码中使用 `pos_type` 返回类型?

C++,如何将多个输入除以空格?

c++ - 为什么 valgrind 报告 libstdc++ 的 std::locale 错误?