【发布时间】:2017-04-17 22:06:12
【问题描述】:
我有一个 C++/CLI DLL 的 C++ 客户端,它初始化一系列 C# dll。
这曾经有效。失败的代码没有改变。在抛出异常之前不会调用已更改的代码。我的编译环境发生了变化,但是在与我的旧环境相似的机器上重新编译仍然失败。 (编辑:正如我们在答案中看到的,这并不完全正确,我只是在旧环境中重新编译库,而不是库和客户端一起重新编译。客户端项目已经升级,无法轻易返回。)
除了我之外的其他人重新编译了库,我们开始遇到内存管理问题。 The pointer passed in as a String must not be in the bottom 64K of the process's address space. 我重新编译了它,一切正常,没有代码更改。 (警报#1)最近它被重新编译,并且重新出现了字符串的内存管理问题,这次它们并没有消失。新的错误是Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
我很确定问题不在于我看到异常的地方,代码在成功和失败的构建之间没有变化,但我们应该检查它是否完整。忽略事物的名称,我对这些字符串所做的设计没有太多控制权。很抱歉造成混乱,但请注意 _bridge 和 bridge 是不同的东西。因为这个问题已经太长了,所以缺少很多代码行。
在库中定义:
struct Config
{
std::string aye;
std::string bee;
std::string sea;
};
extern "C" __declspec(dllexport) BridgeBase_I* __stdcall Bridge_GetConfiguredDefaultsImplementationPointer(
const std::vector<Config> & newConfigs, /**< new configurations to apply **/
std::string configFolderPath, /**< folder to write config files in **/
std::string defaultConfigFolderPath, /**< folder to find default config files in **/
std::string & status /**< output status of config parse **/
);
在客户端函数中:
GatewayWrapper::Config bridge;
std::string configPath("./config");
std::string defaultPath("./config/default");
GatewayWrapper::Config gwtransport;
bridge.aye = "bridged.dll";
bridge.bee = "1.0";
bridge.sea = "";
configs.push_back(bridge);
_bridge = GatewayWrapper::Bridge_GetConfiguredDefaultsImplementationPointer(configs, configPath, defaultPath, status);
请注意,对崩溃的库的调用与向量声明、结构声明、字符串赋值和向量回推在同一范围内 在这部分代码中没有线程调用,但是有其他线程在运行做其他事情。这里没有指针数学,除了标准库之外,该区域没有堆分配。
我可以在调试器中运行代码直到调用Bridge_GetConfiguredDefaultsImplementationPointer,并且configs 向量的内容在调试器中看起来是正确的。
回到库,在第一个子函数中,调试器不亮,我将失败的语句分解为几个控制台打印。
System::String^ temp
List<CConfig^>^ configs = gcnew List<CConfig ^>((INT32)newConfigs.size());
for( int i = 0; i< newConfigs.size(); i++)
{
std::cout << newConfigs[i].aye<< std::flush; // prints
std::cout << newConfigs[i].aye.c_str() << std::flush; // prints
temp = gcnew System::String(newConfigs[i].aye.c_str());
System::Console::WriteLine(temp); // prints
std::cout << "Testing string creation" << std::endl; // prints
std::cout << newConfigs[i].bee << std::flush; // crashes here
}
如果我将newConfigs[i].bee 移到temp 的分配之上或注释掉列表声明/分配,我会在访问bee 时遇到同样的异常。
仅作为参考,向量中的结构中的 std::string 应该已经到达它的目的地 ok
- Is std::vector copying the objects with a push_back?
- std::string in struct - Copy/assignment issues?
- http://www.cplusplus.com/reference/vector/vector/operator=/
- Assign one struct to another in C
为什么我的 try/catch 没有捕获到这个异常
https://stackoverflow.com/a/918891/2091951
Generic AccessViolationException 相关问题
- How to handle AccessViolationException
- Programs randomly getting System.AccessViolationException
- https://connect.microsoft.com/VisualStudio/feedback/details/819552/visual-studio-debugger-throws-accessviolationexception
- finding the cause of System.AccessViolationException
- https://msdn.microsoft.com/en-us/library/ms164911.aspx
- Catching access violation exceptions?
- AccessViolationException when using C++ DLL from C#
以上问题的建议
- 更改为 .net 3.5,更改目标平台 - 这些解决方案可能会在大型多项目解决方案中出现严重问题。
- HandleProcessCorruptedStateExceptions - 在 C++ 中不起作用,此装饰适用于 C#,无论如何捕获此错误可能是一个非常糟糕的主意
- 更改 legacyCorruptedStateExceptionsPolicy - 这是为了捕获错误,而不是阻止它
- 安装 .NET 4.5.2 - 不能,已经有 4.6.1。安装 4.6.2 没有帮助。在没有安装 4.5 或 4.6 的不同机器上重新编译没有帮助。 (尽管这曾经在安装 Visual Studio 2013 之前在我的机器上编译和运行,这强烈表明 .NET 库是一个问题?)
- VSDebug_DisableManagedReturnValue - 我只看到与调试器中的特定崩溃有关的提到这一点,微软的帮助说其他 AccessViolationException 问题可能不相关。 (http://connect.microsoft.com/VisualStudio/feedbackdetail/view/819552/visual-studio-debugger-throws-accessviolationexception)
- 更改 Comodo 防火墙设置 - 我不使用此软件
- 将所有代码更改为托管内存 - 不是一个选项。通过 C++/CLI 从 C++ 调用 C# 的整体设计是抗更改的。我被特别要求以这种方式设计它,以利用现有 C++ 代码中的现有 C# 代码。
- 确保已分配内存 - 应在 C++ 客户端的堆栈上分配内存。我试图使向量不是参考参数,以强制将向量复制到显式库控制的内存空间中,但没有帮助。
- “冒泡到托管代码的非托管代码中的访问冲突始终包含在 AccessViolationException 中。” - 事实,而不是解决方案。
【问题讨论】:
-
好主意,但事实并非如此。两个调试版本都使用 /MDd,两个发布版本都使用 /MD。
-
继续发布第二个链接作为答案。这是相关的。我们第一次遇到这个问题时,有人开始在 Visual Studio 2013 中编译库,而客户端仍在 2010 年编译。我一直认为 2013 是一个问题,所以当客户端在 2013 年开始编译时,我继续编译2010 年的库,但问题在于不匹配,而不是特定版本。在 2013 年编译,它工作正常。
-
如果它只是相关但不能解决你当前的问题,那么它就不是一个真正的答案(你说的是“第一次”所以我的理解是您当前的问题尚未解决)。此外,在没有答案的问题上,您将获得更多观看次数。
-
我认为它已经修复,直到有人决定在较新版本的 VS 中重新编译这两者之一。
标签: c++ .net memory-management c++-cli access-violation