Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
147 views
in Technique[技术] by (71.8m points)

c++ - Debug Assertion Failed! Expression: _pFirstBlock == pHead

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

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.

I am using Visual Studio 2012 and C++.

What I will try next

From Debug assertion... _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).

What I will try next

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

You need to do one of two things

  1. Make both the DLL and the client that use it both link to the DLL version 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

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.

See Passing reference to STL vector over dll boundary.

What I will try next

See Unable to pass std::wstring across DLL.

Solution

I have a nice solution, see the answer below.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

Runtime Library config

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

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

Memory allocated in Memory Manager A and freed in Memory Manager 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.

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

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

Examples

This will not work:

// 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):

text.assign("hello");

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

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).

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...