Release mode Vs DEbug mode in MS Visual Studio Windows
I am using MSVS 9 (VS 2008). My application as well as shared library(dll)(I am using to link with my application) is also of c++ environment. Now observe the below cases:
when the shared library/dll is built in Debug mode and my application is also built in Debug mode Result: Application executed successfully
when the shared library/dll is built in Release mode and my application is also built in Release mode Result: Application executed successfully
when the shared library/dll is built in Release mode and my application is also built in Debug mode Result: Application is getting crashed without loading any symbols from call stack.
call stack:
ntdll.dll!76e94684()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!76e7d55f()
ntdll.dll!76e5fa18()
ntdll.dll!76e2b3c8()
This problem is seen when I am trying to use the following SetName() and GetName() definitions in my application.
using namespace std;
void main()
{
Schema * schemaExp = new Schema();
schemaExp -> SetName("ExpSchema");
string srctable;
srctable=schemaExp->GetName();
cout <<"nConnection EXPORT using the target table:" << srctable.c_str() << endl;
delete schemaExp;
}
Schema Class Definition:
using namespace std;
class Schema
{
public:
TELAPI_EXPORT void SetName(char *name);
TELAPI_EXPORT string GetName();
protected:
string tableName;
};
void Schema::SetName(char *name)
{
string str(name);
tableName = str;
}
string Schema::GetName()
{
return tableName;
}
Note: The above one is just a part from my application and my application is getting crash only in the #3 and working fine with #1 and #2 cases above
Please help me in fixing this problem. Any kind of help is greatly appreciated.
Thanks in advance.
when the shared library/dll is built in Release mode and my application is also built in Debug mode Result: Application is getting crashed without loading any symbols from call stack.
That's because this is not a supported configuration. By default, the Debug and Release targets link to different versions of the CRT, which (among other things) use different strategies for allocating memory and are not compatible with one another.
This is just an extension of the more general rule that you aren't supposed to mix libraries that link to different versions of the CRT. All of the projects need to match. And as you've already seen, when they do, everything works correctly.
There are workarounds for this, but they're a lot of work to get right. Essentially, you make sure that all memory allocation is isolated within the single DLL so that nothing crosses module boundaries. You'll need to export specific functions from the DLL to allocate and free memory in order to ensure that the heap manager that allocates the memory is the same one that destroys it. You can't rely on this being the case when you use the new
and delete
operators. Frankly, in this case, I don't see how all this effort buys you anything useful.
Do note that this is unrelated to whether or not optimizations are enabled (which they are by default for Release builds, and are not in Debug builds). That setting is orthogonal to the version of the CRT that is linked in. It just so happens that the "Debug" and "Release" targets imply multiple options. You could turn on optimizations for one project and turn them off for another and that should work, so long as you ensure that they both link to the same version of the CRT. But again, I can't really see the point in doing so…if you want optimizations enabled for one, why would you want them suppressed for the other?
Related: Mixing debug and release library/binary - bad practice?
This should not be a crash, just yet, normally you get a debug break inside the Windows memory manager to warn you that your program is destroying the heap. A feature of the debug heap in Windows, available on Vista and up. Look in the Output window for the message.
It is also important to enable the symbol server so the stack trace becomes readable and accurate. Do so with Tools + Options, Debugging, Symbols and tick the checkbox in front of the pre-defined msdl.microsoft.com server name. Pick a good scratch directory for the symbols storage. When you start your program again, it will trundle for a while before it starts running, downloading the symbol files. This only happens once. You should now get a highly readable stack trace that now also goes back to your main() method.
What you are in general discovering is that exposing C++ classes across module boundaries is tricky business. More than one thing can go wrong, one failure mode here is that Schema class object isn't the same size on both sides of the DLL boundary. That's because of a Debug build setting, the _HAS_ITERATOR_DEBUGGING #define matters. It is turned on by default in the Debug build, off in the Release build. Nice debugging feature, but the only way they could implement it was by adding fields to the standard C++ library classes. Which makes std::string bigger in the Debug build. Which makes your Scheme class bigger. You are skirting this problem right now, the failure mode is the Debug version of the DLL with the Release version of the EXE. The Scheme class constructor will then corrupt the heap when it initializes the string because the allocation for the object wasn't large enough.
Another failure mode is that you've got two versions of the CRT in your process, the debug version in your app and the release version in your DLL. They won't use the same heap to allocate from. Which will go wrong when you allocate in one and release in the other. The string returned by your GetName() method suffers from that problem, it was created in the GetName() method inside the DLL and will be destroyed after the method call in your EXE. By the wrong allocator. The heap corruption this causes isn't detected until you again do something with the heap, like deleting your Scheme object. You'll also invoke this failure mode if you don't build your code with /MD. This issue was addressed in VS2012 btw, all allocations are now made from the default process heap.
Using consistent build settings is essential to survive the module boundary. Setting up your VS solution so you always consistently use the right build for the DLL is not a problem, just make sure that the DLL project is in the same solution as the EXE project.
But do note that you may well have trouble in the future, a DLL has a knack of live a life of its own and may some day be used by an app that was built with another version of the compiler. Kaboom then. Designing your DLL interface so this can never happen is quite possible, but you will have to give up on exposing C++ objects. A C-style interface is the fallback, the way COM works to uplift this into an object model is also a good approach. That's pretty draconian of course, only contemplate this if you can't guarantee that the EXE and DLL are always built and deployed at the same time.
链接地址: http://www.djcxy.com/p/95392.html