C++ 调试断言失败!表达式:_pFirstBlock == pHead

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18882760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:18:00  来源:igfitidea点击:

Debug Assertion Failed! Expression: _pFirstBlock == pHead

c++visual-studio-2012

提问by Contango

I am calling into a statically linked .dll, and I see this error:

我正在调用一个静态链接的 .dll,我看到这个错误:

enter image description here

在此处输入图片说明

I wrote both the .dll and the calling code. This error should not be occurring. I am wondering if anyone else has encountered it before? The .dll only contains about 10 lines of code, its just a test .dll to see how dlls work in general. It blows up when I pass a std::string back out of the .dll.

我编写了 .dll 和调用代码。不应发生此错误。我想知道是否有其他人遇到过它?.dll 只包含大约 10 行代码,它只是一个测试 .dll,用于查看 dll 的一般工作方式。当我从 .dll 中传回 std::string 时,它会爆炸。

I am using Visual Studio 2012 and C++.

我正在使用 Visual Studio 2012 和 C++。

What I will try next

我接下来要尝试什么

From Debug assertion... _pFirstBlock == pHead:

调试断言... _pFirstBlock == pHead

This problem can occur if one uses the single-threading libraries in a multithreaded module.

如果在多线程模块中使用单线程库,则会出现此问题。

Tomorrow, I'll try recompiling the Boost static libraries in multi-threaded mode (my .dll is set to multi-threaded static mode).

明天,我将尝试在多线程模式下重新编译 Boost 静态库(我的 .dll 设置为多线程静态模式)。

What I will try next

我接下来要尝试什么

See Using strings in an object exported from a DLL causes runtime error:

请参阅在从 DLL 导出的对象中使用字符串会导致运行时错误

You need to do one of two things

  1. Make both the DLL and the client that use it both link to the DLLversion of the CRT (e.g. not statically).
  2. OR You need to make sure you don't pass dynamically allocated memory (such as is contained in string objects) across DLL boundaries. In other words, don't have DLL-exported functions that return string objects.

Joe

你需要做两件事之一

  1. 使 DLL 和使用它的客户端都链接到 CRT的DLL版本(例如,非静态链接)。
  2. 或者您需要确保不会跨 DLL 边界传递动态分配的内存(例如包含在字符串对象中)。换句话说,不要有返回字符串对象的 DLL 导出函数。

This seems to match whats going on, it blows up at the precise point where I pass a string back across a .dll boundary. The problem only occurs when everything is linked in static mode. Now that's fixable.

这似乎与正在发生的事情相匹配,它在我将字符串传回 .dll 边界的精确点爆炸。只有当一切都以静态模式链接时才会出现问题。现在可以解决了。

See Passing reference to STL vector over dll boundary.

请参阅通过 dll 边界传递对 STL 向量的引用

What I will try next

我接下来要尝试什么

See Unable to pass std::wstring across DLL.

请参阅无法通过 DLL 传递 std::wstring

Solution

解决方案

I have a nice solution, see the answer below.

我有一个很好的解决方案,请参阅下面的答案。

回答by Contango

In this case, the problem is that I was passing a std::stringback across a .dll boundary.

在这种情况下,问题是我std::string在 .dll 边界上传递了一个返回值。

Runtime Library config

运行时库配置

  • If the MSVC Runtime libraryis set to Multi-threaded Debug DLL (/MDd), then this is no problem (it works fine).

  • If the MSVC Runtime libraryis set to Multi-threaded Debug (/MTd), then it will throw this error, which can be fixed with the following instructions.

  • 如果 MSVCRuntime library设置为Multi-threaded Debug DLL (/MDd),那么这没问题(它工作正常)。

  • 如果 MSVCRuntime library设置为Multi-threaded Debug (/MTd),则它会抛出此错误,可以使用以下说明进行修复。

Memory allocated in Memory Manager A and freed in Memory Manager B ...

在内存管理器 A 中分配的内存和在内存管理器 B 中释放的内存...

The problem is that memory is allocated on the .dll side, then that same memory is freed on the application side. This means that memory manager A is allocating memory, and memory manager B is releasing that same memory, which generates errors.

问题是内存在 .dll 端分配,然后在应用程序端释放相同的内存。这意味着内存管理器 A 正在分配内存,而内存管理器 B 正在释放相同的内存,这会产生错误。

The solution is to make sure that all memory passed back is notallocated in the DLL. In other words, the memory is always allocated on the application side, and freed on the application side.

解决方案是确保所有传回的内存都没有在 DLL 中分配。换句话说,内存总是在应用程序端分配,在应用程序端释放。

Of course, the DLL can allocate/free memory internally - but it can't allocate memory that is later freed by the application.

当然,DLL 可以在内部分配/释放内存 - 但它不能分配稍后由应用程序释放的内存。

Examples

例子

This will notwork:

这将工作:

// Memory is allocated on the .dll side, and freed on the app side, which throws error.
DLL std::string GetString(); 

This will work:

这将起作用:

// Memory is allocated/freed on the application side, and never allocated in the .dll.
DLL int GetString(std::string& text); 

However, this is not quite enough.

然而,这还不够。

On the application side, the string has to be pre-allocated:

在应用程序方面,必须预先分配字符串:

std::string text("");
text.reserve(1024);     // Reserves 1024 bytes in the string "text".

On the .dll side, the text must be copied into the original buffer (rather than overwritten with memory that is allocated on the .dll side):

在 .dll 端,文本必须复制到原始缓冲区中(而不是用在 .dll 端分配的内存覆盖):

text.assign("hello");

Sometimes, C++ will insist on allocating memory anyway. Double check that the pre-allocation is still the same as it was:

有时,C++ 无论如何都会坚持分配内存。仔细检查预分配是否仍然与以前相同:

if (text.capacity < 1024)
{
   cout << "Memory was allocated on the .dll side. This will eventually throw an error.";
}

Another way that works is to use std::shared_ptr<std::string>, so even though memory is allocated in the .dll, it is released by the .dll (rather than the application side).

另一种有效的方法是使用std::shared_ptr<std::string>,因此即使在 .dll 中分配内存,它也会由 .dll(而不是应用程序端)释放。

Yet another way is to accept a char *and a length which indicates the amount of pre-allocated memory. If the text that we want to pass back is longer than the length of pre-allocated memory, return an error.

另一种方法是接受一个char *和一个长度,它表示预分配的内存量。如果我们要传回的文本长度超过预分配内存的长度,则返回错误。

回答by Hans Passant

This is what assert()looks like when its expressionargument evaluates to false. This assert exists in the Debug build of the C runtime library, designed to check for allocation problems. The free() function in your case. The Debug build add extra checks to make sure you are writing your code correctly. And tell you when it detects a problem. Like calling free() on an allocation that was already freed, the simple case. Or calling free() passing the wrong pointer value, the trickier case. Or calling free() when the heap was corrupted by earlier code, the much harder case.

assert()表达式参数计算为 false时,这就是它的样子。此断言存在于 C 运行时库的调试版本中,旨在检查分配问题。您的情况下的 free() 函数。调试构建添加额外的检查以确保您正确编写代码。并在检测到问题时告诉您。就像在已经释放的分配上调用 free() 一样,简单的情况。或者调用 free() 传递错误的指针值,更棘手的情况。或者在堆被早期代码损坏时调用 free() ,情况要困难得多。

This is only as far as they can take it, they don't actually know whyyour code got it wrong. There is not any way they can put a Big Red arrow on the code that corrupted the heap for example. The easy case is covered by the Debug + Windows + Call Stack debugger window, it takes you to the code in your program that called free(). Or std::operator deletefor a C++ program. The harder case is very, very hard indeed, heap corruption is often a Heisenbug. Getting the assert to be repeatable so you can set a data breakpoint on the reported address is the core strategy. Crossing fingers for the easy case, good luck with it!

这只是他们所能接受的,他们实际上并不知道为什么你的代码出错了。例如,他们无法在破坏堆的代码上放置大红色箭头。Debug + Windows + Call Stack 调试器窗口涵盖了简单的情况,它会将您带到程序中调用 free() 的代码。或者std::operator delete对于 C++ 程序。更困难的情况确实非常非常困难,堆损坏通常是一个 Heisenbug。使断言可重复,以便您可以在报告的地址上设置数据断点是核心策略。为简单的案例交叉手指,祝你好运!



After edit: yes, having cross-module problems with a C++ class like std::string is certainly one of the problems it can catch. Not a Heisenbug, good kind of problem to have. Two basic issues with that:

编辑后:是的,像 std::string 这样的 C++ 类的跨模块问题肯定是它可以捕获的问题之一。不是 Heisenbug,这是一个很好的问题。两个基本问题:

  • The modules might each have their own copy of the CRT, objects allocated by one copy of the CRT cannot be released by another copy of the CRT. They each have their own heap they allocate from. A problem that got addressed in VS2012, the CRT now allocates from a process-global heap.
  • The modules might not use the same implementation of std::string. With an object layout that does not match. Easily induced by having the modules compiled with different C++ library versions, particularly an issue with C++11 changes. Or different build settings, the _HAS_ITERATOR_DEBUGGING macro is quite notorious.
  • 每个模块可能都有自己的 CRT 副本,由 CRT 的一个副本分配的对象不能由 CRT 的另一个副本释放。他们每个人都有自己分配的堆。在 VS2012 中解决了一个问题,CRT 现在从进程全局堆分配。
  • 模块可能不使用 std::string 的相同实现。具有不匹配的对象布局。通过使用不同的 C++ 库版本编译模块很容易引起,特别是 C++11 更改的问题。或者不同的构建设置,_HAS_ITERATOR_DEBUGGING 宏是非常臭名昭著的。

The only cure for that problem is to make sure that you build allof the modules in your program with the exact same compiler version using the exact same build settings. Using /MD is mandatory, it ensures that the CRT is shared so there's only one in the program.

解决该问题的唯一方法是确保使用完全相同的构建设置使用完全相同的编译器版本构建程序中的所有模块。使用 /MD 是强制性的,它确保 CRT 是共享的,因此程序中只有一个。

回答by Pavel Radzivilovsky

The likely cause: binding to wrong version of the Qt DLLs, especially when moving a project from VS2010 to VS2012.

可能的原因:绑定到错误版本的 Qt DLL,尤其是在将项目从 VS2010 移动到 VS2012 时。

This is due to different versions of the standard library and associated dynamic allocation issues.

这是由于标准库的不同版本和相关的动态分配问题。

回答by user6118388

I had the same problem after a Windows reinstallation. My Runtime library build was Multi-threaded Debug DLL (/MDd).

重新安装 Windows 后,我遇到了同样的问题。我的运行时库构建是多线程调试 DLL ( /MDd)。

My solution was to remove *.userfile of the visual studio project, remove the debug folder and rebuild the project.

我的解决方案是删除*.userVisual Studio 项目的文件,删除调试文件夹并重建项目。