Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have some trouble figuring out why the following crashes (MSVC9):

//// the following compiles to A.dll with release runtime linked dynamically
//A.h
class A {
  __declspec(dllexport) std::string getString();
};
//A.cpp
#include "A.h"
std::string A::getString() {
   return "I am a string.";
}

//// the following compiles to main.exe with debug runtime linked dynamically
#include "A.h"
int main() {
   A a;
   std::string s = a.getString();
   return 0;
} // crash on exit

Obviously (?) this is due to the different memory models for the executable and DLL. Could it be that the string A::getString() returns is being allocated in A.dll and freed 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 wrappers like shared_ptr with a custom deleter.

See Question&Answers more detail:os

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

1 Answer

This isn't actually being caused by differing heap implementations - the MSVC std::string implementation doesn't use dynamically allocated memory for strings that small (it uses the small string optimization). The CRTs do need to match, but that isn't what bit you this time.

What's happening is that you're invoking undefined behaviour by violating the One Definition Rule.

The release and debug builds will have different preprocessor flags set, and you'll find that std::string has a different definition in each case. Ask your compiler what sizeof(std::string) is - MSVC10 tells me that it's 32 in a debug build and 28 in a release build (this isn't padding - 28 and 32 are both 4 bytes` boundaries).

So what's happening? Variable s is initialized using the debug version of the copy constructor to copy a release version of std::string. The offsets of the member variables are different between the versions, so you copy garbage. The MSVC implementation effectively stores begin and end pointers - you've copied garbage into them; because they're no longer null, the destructor tries to free them and you get an access violation.

Even if the heap implementations were the same it would crash, as you're freeing garbage pointers to memory that was never allocated in the first place.


In summary: the CRT versions need to match but so do the definitions - including the definitions in the standard library.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...