用户DLL/EXE中的堆分配失败 [英] Heap allocation failing in user 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
时,运行访问NewFailMfc1
的Www
功能的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?
(我曾尝试在在MyApp1
和MyApp2
中编译时,全局函数::operator new
失败.在询问过程中,我发现问题的发生范围比
(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.)
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.cpp
,MyClsModule2.cpp
等.在这些文件中,我显式实例化该模块的类.我还为每个包含extern
的模块添加了.h
文件,例如MyClsModule1.h
,MyClsModule2.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 extern
s 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屋!