用户DLL/EXE中的堆分配失败 [英] Heap allocation failing in user DLL/EXE

查看:195
本文介绍了用户DLL/EXE中的堆分配失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正确链接的DLL和EXE应该具有一个免费存储,它们都可以从中分配基于堆的对象.这是Chis Becke在谁将堆分配给DLL的答案?:

Properly linked DLLs and EXEs are supposed to have one freestore from which they all can allocate heap-based objects. Here is Chis Becke’s Answer in Who allocates heap to a DLL?:

…是C ++运行时,负责创建其免费存储并决定 如何分配它. 具体来说,如果使用Dll运行时选项,则单个dll-msvcrtxx.dll-管理单个 在与该dll链接的所有dll和exe之间共享的免费存储区

… 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

由于这是真的,所以我应该能够new在其他DLL/EXE中定义的DLL/EXE中的对象.克里斯认为,msvcrtxx.dll和编译时/运行时链接程序负责在何处可以获得所有DLL/EXE的联合免费存储.

Since this is true, then I should be able to new objects in DLL/EXEs defined in other DLL/EXEs. According to Chris, the msvcrtxx.dll and compile-time/runtime linker take care of where the joint freestore for all the DLL/EXEs can be obtained.

那对我不起作用.

要对此进行测试,我生成了两个MFC对话框程序: NewFailMfc1 NewFailMfc2 .执行new时,运行访问NewFailMfc1Www功能的NewFailMfc2失败.

To test this, I have generated two MFC dialog programs: NewFailMfc1 and NewFailMfc2. Running NewFailMfc2 which accesses NewFailMfc1’s Www function fails when doing the 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的工作原理?

Does someone with a better knowledge of how DLL/EXE freestore works than me know what the problem is?

(我曾尝试在在MyApp1MyApp2中编译时,全局函数::operator new失败.在询问过程中,我发现问题的发生范围比 std lib.)

(I attempted to ask this question once before in "Global function ::operator new fails when compiled in MyApp1 and MyApp2. During the asking process, I discovered that the problem was occurring more generally than in the <random> std lib.)

在MSDN中,找到了一个不错的虚拟代理

In MSDN a nice virtual agent found Potential Errors Passing CRT Objects Across DLL Boundaries for me. Unfortunately, the only solution it recommends is compiling all your programs with the /MD compiler option, and not /MT which uses multiple copies of the CRT which automatically leads to crossing boundaries and memory access violations.

对于像我这样的应用程序开发人员来说,这不是一个好消息.我需要的是一种最佳实践,因此我可以应用它并满足交付期限,而不必处理神秘的低级内存问题.我怎么能知道在std:random_device类型中是否存在对全局::operator new的隐藏调用?直到它违反了访问权限,我才会这样做.直到所有这些研究之后,我才意识到,通过调用全局new,它是越界,这使我的DLL/EXE发生了访问冲突.非常晦涩.

This is not good news for an app developer like me. What I need is a Best Practice so I can apply it and meet my delivery deadlines without having to deal with arcane low-level memory problems. How would I fx know there is a hidden call to the global ::operator new in the std:random_device type? I wouldn’t until it access-violated. Only now after all this research do I realize that by it calling the global new, it was crossing a boundary which gave my DLL/EXE an access violation. Very obscure.

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

I have submitted a bug report in Visual Studio regarding the std::random_device implementation. See "std::random_device instantiation causes an access-violation in certain cases".

推荐答案

显式实例化

显式实例化强制编译器为模板化类或函数的特定参数列表生成代码.没有该代码,我导入的DLL/EXE二进制文件将无法在运行时实例化(如ch = new char[ 100 ]std::random_device rd;)上执行,这些操作隐式地执行全局::operator new.我没有找到有用的解释来解释为什么会发生这种情况.遗憾的是,IPC讨论并未明确区分涉及多个运行进程的客户端-服务器运行时与导入已编译并导出到其他地方的二进制代码(DLL/EXE)的运行时代码.

Explicit Instantiation forces the compiler to generate code for a specific parameter list of a templated class or function. Without that code my imported DLL/EXE binaries were failing on runtime instantiations like ch = new char[ 100 ] and std::random_device rd; which implicitly does a global ::operator new. I have found no useful explanation for why this occurs. IPC discussions unfortunately don’t clearly distinguish between client-server runtime involving more than one running process, and runtime code that imports binary code (DLL/EXE) that was compiled and exported elsewhere.

解决方案是向失败的类添加模板参数,并将.cpp文件添加到显式实例化该类的每个模块,例如MyClsModule1.cppMyClsModule2.cpp等.在这些文件中,我显式实例化该模块的类.我还为每个包含extern的模块添加了.h文件,例如MyClsModule1.hMyClsModule2.h,因此在特定模块内不会发生重复的代码生成.使用这种方法,每个模块都会在编译时生成特定于模块的类代码,这会强制模块的线程允许访问该模块的进程堆的堆实例化.

The solution was to add a template parameter to the class that was failing and add a .cpp file to each module that explicitly instantiated the class, like MyClsModule1.cpp, MyClsModule2.cpp, etc. In these files I explicitly instantiate the class for that module. I also add the .h files, like MyClsModule1.h, MyClsModule2.h, for each module which contain externs so duplicate code generations don’t occur within a particular module. With this approach each module generates module-specific class code at compile time, which forces the module’s threads to allow heap instantiations which access that module’s process heap.

这个现代的C ++解决方案对我来说很优雅,因为它使我不必将复杂的IPC解决方案(例如COM)重新引入我的应用程序代码中.

This modern C++ solution is elegant for me in that it keeps me from having to re-introduce complex IPC solutions like COM into my app code.

从应用程序开发人员的角度来看,我认为我的原始代码应该已经起作用,或者至少已经产生了有关问题根源的错误,因此,我将在 EDIT2中提及我的错误报告效果强.

From an app developer’s perspective I think that my original code ought to have worked or at least have generated errors that were more informative as to what the problem was, so I am leaving my bug report mentioned in EDIT2 in effect.

这篇关于用户DLL/EXE中的堆分配失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆