strange leak in DLL


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 11 of 11

Thread: strange leak in DLL

  1. #1
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604

    strange leak in DLL

    Hi,

    I have a problem writing a DLL and I suspect some of the warnings I ignored during compilation might have something to do with it (wouldn't be very surprising...).

    So here are the warnings which occur amongst other similar ones:
    c:\sfb_development\sfb_dll\util.h(54) : warning C4251: 'startOle' : class 'CUtil::CStartOle' needs to have dll-interface to be used by clients of class 'CUtil'
    c:\sfb_development\sfb_dll\util.h(42) : see declaration of 'CStartOle'
    c:\sfb_development\sfb_dll\util.h(57) : warning C4251: 'LOGEXTENSION' : class 'CString' needs to have dll-interface to be used by clients of class 'CUtil'
    c:\program files\microsoft visual studio\vc98\mfc\include\afx.h(368) : see declaration of 'CString'

    CUtil is my class which has a subclass CStartOle and and a member startOle.
    Similarly I have some CString - members in CUtil. I ignored these, partly because I do not believe (can it really be?!?!), that one cannot use members of the Microsoft "CString" type as member in a DLL and partly because I previously ignored this warning when I used STL members without serious problems. That might have been sheer luck, though.

    The problem I get is a heap error telling me that I am trying to access an invalid heap pointer (The message box says something like _Crtl(IsValidHeapPointer(pUserData) raised an exception).
    I am not using ANY pointers to CString or so. Is it possible, that trying to access a CString member of a class in a DLL can cause this trouble?

    Thanks for your input!

    Cheers,

    D

  2. #2
    Join Date
    Nov 2003
    Posts
    4,118
    Generally speaking, trying to delete memory that was allocated inside a DLL in the main program is an error. A DLL's heap is distinct from that of the main process so deleting memory allocated in the DLL -- must be done in the DLL itself. What seems to have happened is that you using a CString object that allocated its buffer from the DLL's heap. The string's destructor is called inside the main program. The destructor tries to delete this memory so this might be the cause of this.
    Danny Kalev

  3. #3
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Thanks Danny for clarifying this. I think however I've been quite careful in not deleting anything inside the DLL. I pass parameters as "const CString&" and create local copies inside the DLL where needed.
    This is the method where I get the error:

    (typedef map<CString,_variant_t> PARAMETER_LIST;)
    bool CStoredProcedure::addParameter(const CString& name, long value, long maxval)
    {
    ASSERT(!(name.IsEmpty()));

    bool reval = true;
    if(!valid(name))
    {
    Log(this,ERR|LOG,IDS_ERR_ILLEGAL_STOREDPROCEDURE_PARAMETER_NAME,name);
    reval = false;
    }
    if(value>maxval)
    {
    Log(this,ERR|LOG,IDS_ERR_STOREDPROCEDURE_PARAMETER_VALUE_TOO_BIG,name,value,maxval);
    reval = false;
    }
    if(reval != false)
    {
    CString fullName = CString("@") + name;
    PARAMETER_LIST::iterator found = m_listParameters.find(fullName);
    if(found != m_listParameters.end())
    {
    Log(this,ERR|LOG,IDS_ERR_STOREDPROCEDURE_PARAMETER_ALREADY_ADDED,fullName);
    reval = false;
    }
    m_listParameters.insert(pair<CString,_variant_t>(fullName,_variant_t((long)value)));
    }

    return reval;
    }


    The error as, you are right to identify, occurs on exit of method. Am I missing anything heer?!?

    Cheers for your thoughts.

    Dieter

  4. #4
    Join Date
    Nov 2003
    Posts
    4,118
    You need to isolate the problem so try to shave off a few blocks of code and see whether the problem persists. Particularly, check whether the error remains after removing the insert() call at the bottom of this function. Another thing to look at: what does m_listParameters contain when the function is called? It may weel be the case the previously inserted pairs may be the culprit. Finally, I'm very suspcicious about _variant_t. You're casting long to _variant_t at the end of the function but isn't _variant_t larger than long? That means that the rest of the bytes contain garbage. Finally, try to see if removing the local auto CString object eliminates this bug. I know that CString contains a lot of junk aimed to make it compatible with bstr_t but this junk gets in the way when CString' operator < or == are called (these operators are implicitly called in map to keep it sorted). So, it might well be a good idea to see whether you can replace CString with std::string.
    Danny Kalev

  5. #5
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Thanks Danny,
    that gives me at least a couple of things to check out.
    I would really like to not use CString at all, but string doesn't work with DDX and rather than having string and CString alongside each other I decided to go with CString. And Ado/ole/com-components require the use of variants which is a right pain and can not easily be done without...
    But back to my original question: If I have a function say
    CString fct()
    {
    CString reval("Something");
    return reval;
    }
    inside my DLL, will this cause me problems, as when the function returns a copy of reval is created inside the DLl (and the destructor of this copy called in the calling exe)? Is there ANY way around this problem? The warning I get (warning C4251) seems to be at least related to this...

    Thanks,

    Dieter

  6. #6
    Join Date
    Dec 2003
    Posts
    3,366
    does a reference do the trick (on the left hand side)?

  7. #7
    Join Date
    Nov 2003
    Posts
    4,118
    Quote Originally Posted by jonnin
    does a reference do the trick (on the left hand side)?
    Do you mean:

    CString& fct()
    {
    CString reval("Something");
    return reval;
    }

    That's a Bad Thing because the reference is bound to a local auto object. You can work around this like this:

    CString& fct()
    {
    static CString reval("Something");
    return reval;
    }

    But it's probalmatic in multithreaded code.

    A slightly better version is:
    CString& fct()
    {
    return * new CString reval("Something");
    }

    But you still need to delete the allocated object, and that should be done inside the DLL. So my advice is to stick to:

    void fct(CString & s)
    {
    s= "Something";
    }
    Danny Kalev

  8. #8
    Join Date
    Nov 2003
    Posts
    4,118
    Quote Originally Posted by drkybelk
    Code:
    CString fct()
    {
    CString reval("Something");
    return reval;
    }
    To answer it, you have to poke into the constructor and destructor of CString. I don't know what exactly they are doing, but I suspect that this class uses reference counting and a few other memory related hacks that could cause problems. If this class for instance uses optimizations such as assigning a few local pointers instead of actually copying memory buffers, this is really a problem because eventually, memory allocated inside the DLL is released inside the main process.

    Try to define a simple class such as:

    struct S
    {
    int n[5];

    };

    S fct() //inside a DLL
    {
    S s
    return s;
    }

    If this code doesn't cause crashes.
    Danny Kalev

  9. #9
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Thanks Danni and jonnin, that confirms my worst fears! I really think that it is quite a limitation to the usefulness of DLLs, as one can't really exploit features of C++. Is there any workaround to force a DLL to create objects on the executables heap?
    Any suggestions are very much appreciated.

    Thanks in advance.
    Ciao,

    D

  10. #10
    Join Date
    Nov 2003
    Posts
    4,118
    You can use placement new: the operator new is called inside the DLL but it constructs an object on a buffer previously allocated inside the address space of the .exe
    You can read more about placement new here:
    http://www.devx.com/DevX/LegacyLink/9485
    See also a similar discussion about shared_ptr
    http://www.devx.com/cplus/10MinuteSolution/28347
    Danny Kalev

  11. #11
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Thanks for that. I will have a look at those links.

    D

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center