Why this program crashes: passing std :: string between DLLs

I have some problems figuring out the causes of the following crashes (MSVC9):

//// the following compiles to A.dll with release runtime linked dynamically //Ah class A { __declspec(dllexport) std::string getString(); }; //A.cpp #include "Ah" std::string A::getString() { return "I am a string."; } //// the following compiles to main.exe with debug runtime linked dynamically #include "Ah" int main() { A a; std::string s = a.getString(); return 0; } // crash on exit 

Obviously (?) This is due to different memory models for the executable and the DLL. Could it be that the line A::getString() returned, allocated in A.dll and freed up in main.exe?

If so, why - and what would be a safe way to pass strings between DLLs (or executables, for that matter)? Without using covers like shared_ptr, with user deletion.

+20
c ++ memory-management dll visual-c ++
Feb 23 2018-10-23T00
source share
5 answers

In fact, this is not caused by various heap implementations - the MSVC std :: string implementation does not use dynamically allocated memory for small strings (it uses small string optimizations). CRT needs to be matched, but this time is not what you need.

What happens is that you invoke undefined behavior, breaking the rule of one definition.

In releases and debug builds, different preprocessor flags will be set, and you will find that std::string has a different definition in each case. Ask your compiler that sizeof(std::string) - MSVC10 tells me that it is 32 in the debug build and 28 in the release build (this is not an addition - 28 and 32 are 4 byte boundaries).

So what is going on? The variable s initialized using the debug version of the copy constructor to copy the release version of std::string . Member variable offsets vary between versions, so you are copying garbage. The MSVC implementation effectively saves start and end pointers - you have copied garbage into them; because they are no longer zero, the destructor tries to free them, and you get an access violation.

Even if the heap implementations were the same, it would crash because you are freeing garbage pointers into memory that was never allocated in the first place.




In short: CRT versions should be consistent, but , so definitions - including definitions in the standard library .

+45
Feb 23 2018-10-23T00
source share

Maybe the line Return A :: getString () is highlighted in A.dll and freed in main.exe?

Yes.

If so, why - and what would be a safe way to transfer strings between DLLs (or executables, for that matter)? Without using wrappers such as shared_ptr, using custom deter.

Using shared_ptr sounds like a reasonable thing to me. Remember that, as a rule, distributions and releases must be performed by the same module in order to avoid such failures.

Exporting STL objects via dll is a complex pony at best. I suggest you check this out first in the MSDN KB article and this post.

+3
Feb 23 2018-10-23T00
source share

In addition to what was said above, make sure that the Platform Toolset (in the "Properties-> General" section) is identical in both projects. Otherwise, the contents of the string on the arriving side may be fictitious.

This happened to me when a library installed on v90 was used in a console application project with the v100 toolkit.

+2
Feb 05 '15 at 16:03
source share

Perhaps this is due to the fact that the DLL and EXE are compiled with different CRT settings. Therefore, when you pass a string, there is some conflict of resources. Check the project settings for both the DLL and the executable.

+1
Feb 23 '10 at 22:05
source share

You need to link the same runtime library (DLL), either debug or release, for each DLL in your application, where memory is allocated in one and freed up in the other. (The reason for using a dynamically linked runtime library is because then there will be one heap for the whole process, and not one for the dll / exe that references the static.)

This includes returning std :: string and stl containers by value since you are doing this.

The reasons are twofold (updated section) :

  • classes have different layouts / sizes, so otherwise compiled code assumes that the data is in different places. The one who created it first gets the right, but the other can cause a crash sooner or later.
  • the implementation of the msvc heap is different in each runtime, which means that if you try to free the pointer on the heap that did not allocate it, it will go to breakers. (This happens if the layouts are similar, i.e. where you are experiencing the first case.)

So, get your executables directly or stop freeing / highlighting in different dlls (i.e. stop transmitting data by value).

+1
Feb 23 2018-10-23T00
source share



All Articles