NDEBUG vs _DEBUG

Hi,

I have a problem wiht NDEBUG and _DEBUG settings from VC6. Usualy i'm delivering my DLLs compiled with NDEBUG, but the problem appears when the clients are using this dlls in their applications compiled with _DEBUG. The problem is that the application is crashing if one std object created in my DLL (NDEBUG) is distroyed in the client application (_DEBUG).

Workarounds i know for now are:
1)Always pasing objects from my dll by using referinces and never by value or smart pointers
2)delevering to the client a dll compiled with _DEBUG
3)asking the client to compile his app with NDEBUG

But i'm looking for understanding what is happening and trying to find a better solution. It's very confusing for me that a macro that was design only to enable and disable Assert functions is actually making the application to crash. Is anybody able to tell me more about this subject?

Ty
calisovAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AxterCommented:
>>It's very confusing for me that a macro that was design only to enable and disable Assert functions is actually making the application to crash.

That macro does much more then that.
When you compile your code in debug, you're also using a different set of libraries.

For VC++, according to MS, you're not allowed to distribute the DEBUG compile version of your executable.

I recommend that you add logging features to your code, so you can better determine what's going on.
You can make it so that logging gets turned off and on, depending on a registry or INI setting.


It's hard to give you detailed advise, without knowing more about the object that is causing problems.

Can you post the class and/or implementation for this object?
0
calisovAuthor Commented:
There is no specific object...any object from std library(vector,string,list etc) is causing this.
Here is a short example:
dll compiled with NDEBUG:
hpp:
#ifdef      MY_EXPORTS
#define            MY_API __declspec(dllexport)
#else
#define            MY_API __declspec(dllimport)
//##########################################################################
#include <vector>
//##########################################################################
class MY_API tNdebug
{
public:
//##########################################################################
      //! Constructor
      tNdebug();
      const std::vector <double> GetVector() const;
private:
};
cpp:
#include "tNdebug.h"
//##########################################################################
tNdebug::tNdebug()
{
}
//##########################################################################
const std::vector <double> tNdebug::GetGigi() const
{
      std::vector <double>  rtrn;
      rtrn.push_back(1.0);
      rtrn.push_back(2.0);
      return rtrn;
}
client application compiled with _DEBUG:
#include "stdafx.h"
#include "tNdebug.h"
//##########################################################################
int main(int argc, char* argv[])
{
      tNdebug a;
      {
            std::vector <double> b=a.GetVector();
      }//here when the vector destructor is called i get in VC the crash
      return 0;
}



0
calisovAuthor Commented:
oops
Sorry for that "const std::vector <double> tNdebug::GetGigi() const" from cpp :)

It's const std::vector <double> tNdebug::GetVector() const :)...any way this is the example
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

waysideCommented:
In general is it a good idea to have the module that created the object also be responsible for deleting it.

So I think the best solution is to add functions to your dll for the client to call to delete your objects, rather than having them use delete .

I could think of a couple of reasons why your scenario crashes:

1) The debug versions of new and delete allocate memory differently - the debug version of new allocates extra memory before and after the object and fills them will special values, the debug version of delete checks these guard bytes to make sure the values haven't changed. It's a mechanism to help detect overwrites and other memory corruptions.

If an object gets created with non-debug new (and doesn't have this extra space allocated with it) and then gets destroyed by the debug delete (which assumes this extra space has been allocated),  the bookkeeping gets messed up.

2) Since the debug and non-debug version are in different libraries, all of the memory allocation bookkeeping is done in two places. The debug delete is trying to free a chunk of memory it knows nothing about, which leads to a crash. It's equivalent to passing in a random value to delete.
0
calisovAuthor Commented:
Ok,...here are some updates....

Once i built both projects from the upper example (my dll and client app) with the same seting for "Use run-time library" ....the seting is MultiThreadedDLL...was the only one that worked .....i did not get the crash even if the dll had the NDEBUG and the client app had _DEBUG....but...as soon as i switched from vector to string i got the error back.
0
AxterCommented:
>>There is no specific object...any object from std library(vector,string,list etc) is causing this.

Make sure your client is using the same STL library as you.
You should both  be using standard headers that are part of the C++ standard.
#include <vector>
#include <string>
#include <iostream>

If you're using the above headers, and your client is using the following none standard headers, that could be causing the problem:
#include <vector.h>
#include <string.h>
#include <iostream.h>
0
AxterCommented:
>>Use run-time library" ....the seting is MultiThreadedDLL

If both projects are not using the same run-time library, then that will cause a crash because they're not using the same allocator/heap.

You need both to use the same run-time library.
0
calisovAuthor Commented:
Yes now i know that both projects must use the same run-time library...but as i told you this is ok ONLY for vector....as soon as i switched to string the error is back.


The upper example was compiled and test on my computer so, yes, for sure is the same STL.
Ok....i made more tests and here is a short report.The tests are made with the upper example as model and both projects using "MultiThreadedDLL"

For std::vector:
 - working fine even if the dll has NDEBUG and application has _DEBUG

For std::string:
- if the dll has NDEBUG and the application has _DEBUG then i get the crash
- If i keep this setings but insetad of returning by value: "const std::string GetString()" i'm using returning by ref. :
"const std::string& GetString()"  with keeping the app caling line:
int main(int argc, char* argv[])
{
     tNdebug a;
     {
          std::string b=a.GetString();
     }
     return 0;
}
then the crash is gone and evrything is working fine

For std::set or std::map
- if the dll has NDEBUG and the application has _DEBUG then i get the crash
- If i keep this setings but insetad of returning by value: "const std::set<int>  GetSet()" i'm using returning by ref. :
"const std::set<int>& GetSet()" with keeping the app caling line:
nt main(int argc, char* argv[])
{
     tNdebug a;
     {
          std::set <int> b=a.GetSet();
     }
     return 0;
}
 then i get the crash
- MORE THEN THIS..... even compiling both applications with NDEBUG and returnign by ref...i still get the crash.....

Ok....now i can realy say that THIS IS A BIG MESS FROM M.S.

PS: in .Net evrything is working fine even if i have the dll compiled with "MultiThreadedDLL" and the client app with
"MultiThreaded Debug DLL"....which is a normal behaivior.....but unfortunally for now is not an option to switch to .NET
0
AxterCommented:
For most off the above issues, the problem is that with the STL library you need to be using the same run-time library if any deallocation occurs accross both DLL/EXE.
The debug version uses a different runtime library then the release version.

You can minimize the damage by using methods that will insure deallocation occurs in your DLL, instead of the calling application.
0
AxterCommented:
>>Ok....now i can realy say that THIS IS A BIG MESS FROM M.S.

This is not a problem with M.S.
The debug version of the library has a lot of code that you would not want in a release version of the library.
That means to keep the release version efficient, they have to make the release version incompatible with the debug version.
0
calisovAuthor Commented:
i was talking about the set and map.....even with both projects using release version there is still a crash.....and this why i say that this is a MESS

And also i was not speaking about delevering to the client the debug version or about having debug code in my release......i was talking about:
1) Delivering to the client a release version of DLLs
2) Let the client debuging his application while he is using my dlls

But ofcourse...this is just a point of view.....

And it looks like the guys from MS are thinking like me also since this is no more happening in .NET.....or maybe what i'm thinking that it is a fix is actually a bug...should i report it :)?
0
AxterCommented:
>>i was talking about the set and map.....even with both projects using release version there is still a crash.....and this why i say that this is a MESS

I would consider that a bug.
Can you post the code for GetSet function?
0
AxterCommented:
>>or maybe what i'm thinking that it is a fix is actually a bug...should i report it :)?

If you're referring to the std::set and std::map issue, I would report it if you're sure that's what's causing the problem.
0
jkrCommented:
>>But i'm looking for understanding what is happening and trying to find a better solution

What is happening is the following: Release and Debug modules use different heaps. Do, if you allocate aon object on the Release heap and try to free it in a Debug module, that will crash. One of the easiest workarounds is to have the objecs free themselves (since they know the approprate heap) by adding a method to do that implicitly rather explicitly:

struct IExportable {

    virtual void Release () { delete this;}
};

Have the exported classes inherit from the above one and the problems should vanish.
0
AxterCommented:
>>Have the exported classes inherit from the above one and the problems should vanish.

You also have to worry about returning std::string by value, which causes the reference counter to be used.

I believe passing an std::string by value will also cause the same problem.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
calisovAuthor Commented:
>>What is happening is the following: Release and Debug modules use different heaps. Do, if you allocate aon object >>on the Release heap and try to free it in a Debug module, that will crash. One of the easiest workarounds is to have >>the objecs free themselves (since they know the approprate heap) by adding a method to do that implicitly rather >>explicitly:
>>
>>struct IExportable {
>>
>>    virtual void Release () { delete this;}
>>};

Does not make any sence...the object is not created with new and it is not destroyed with delete.....it is created natural
sdt::string myObject="any text";

and the destructor is automatically called by compiler when the object is geting out of its scope....
What you are sayng is "to have the objecs free themselves"....but they should  already do this since the compiler is calling their own destructor...virtual void Release () { delete this;} shoul be exactly what the implicit destructor is doing..... and this is my big question...if the object is not created with new ....since the object knows how to distroy itself.....why i'm geting problems?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.