CString and char* memory issues

A minor mem leak is bugging me. Does anyone see anything wrong with this small function (I get a memory leak at the 2nd line).
Context: AppDir is a CString member variable in my class.

{
char szAppPath[MAX_PATH] = "";
::GetModuleFileName(0, szAppPath, sizeof(szAppPath) - 1);

strcpy (AppDir.GetBuffer(MAX_PATH-1), szAppPath);

//appdir now stores the application's path
AppDir = AppDir.Left(AppDir.ReverseFind('\\'));
}

Debugging points the memory leak to the strcpy function itself.
I have also tried (in place of strcpy) AppDir = szAppPath, and I have also tried putting AppDir.GetBuffer(MAX_PATH-1) in the getmodulefilename function itself.

Any thoughts?

oh - something I should add - if I take out the strcpy line - no mem leaks.
[832 byte] By [JeanChretien] at [2007-11-18 8:42:15]
# 1 Re: CString and char* memory issues
After the strcpy insert a

AppDir.Release() which copies the altered buffer back into
the CString object and deallocates the temporary buffer.
akraus1 at 2007-11-11 2:47:21 >
# 2 Re: CString and char* memory issues
exactly!
Indian_Techie at 2007-11-11 2:48:25 >
# 3 Re: CString and char* memory issues
I was wondering why it wouldn't work whenever I used GetBuffer. I wonder why I get mem leaks when I just use = rather than strcpy.

Thanks guys!
JeanChretien at 2007-11-11 2:49:23 >
# 4 Re: CString and char* memory issues
Are you calling _CrtDumpMemoryLeaks yourself or letting _AFX_DEBUG_STATE do it for you?
Mick at 2007-11-11 2:50:32 >
# 5 Re: CString and char* memory issues
Hmmm - still giving me problems, this time with calling "Left". It appears either way SHOULD work, because in a smaller scale test app I had no memory leaks. However, as soon as I moved the CString that gets the path name to a member variable, I get memory leaks.

The only thing I can think of is whatever deallocation that occurs at the end of a function doesn't happen for member variables, and I can't exactly delete them.


edit:

I'm using this approach - with the 2 checkpoints at the start and end of my app.

newMem.Checkpoint();
if( diff.Difference( old, newMem) )
{
TRACE( "Memory leaked!\n" );
TRACE("\n\n\n");

diff.DumpAllObjectsSince();
TRACE("\n\n\n");
diff.DumpStatistics();
}
JeanChretien at 2007-11-11 2:51:32 >
# 6 Re: CString and char* memory issues
Originally posted by JeanChretien However, as soon as I moved the CString that gets the path name to a member variable, I get memory leaks.

The only thing I can think of is whatever deallocation that occurs at the end of a function doesn't happen for member variables, and I can't exactly delete them.
A member variable of what? What is the lifetime of the object which holds the CString member veriable? Of course member objects are deleted too - as soon as the enclosing object is deleted. Maybe your object is static, so you are just calling newMem.Checkpoint() too early.
gstercken at 2007-11-11 2:52:29 >
# 7 Re: CString and char* memory issues
Originally posted by JeanChretien
Hmmm - still giving me problems, this time with calling "Left". It appears either way SHOULD work, because in a smaller scale test app I had no memory leaks. However, as soon as I moved the CString that gets the path name to a member variable, I get memory leaks.

The only thing I can think of is whatever deallocation that occurs at the end of a function doesn't happen for member variables, and I can't exactly delete them.


edit:

I'm using this approach - with the 2 checkpoints at the start and end of my app.

newMem.Checkpoint();
if( diff.Difference( old, newMem) )
{
TRACE( "Memory leaked!\n" );
TRACE("\n\n\n");

diff.DumpAllObjectsSince();
TRACE("\n\n\n");
diff.DumpStatistics();
}

Err I would guess the destructor of the CString hasn't been called yet (which will free the mem). Breakpoint on ~CString() in strcore.cpp (MFC\SRC). If your checkpointing before it cleans up then...well..

it would be the same if I called _CrtDumpMemoryLeaks(); but the CRT hasn't cleaned up the strings yet, which occurs after the function returns, destructor is called.

This happens with the STL and MFC all the time as an example, since the AFX debug state calls crtdumpmem but cleanup is still pending.

If this is the case, and I believe it to be so, get rid of the strcpy because your asking for trouble, and just use operator =.
Mick at 2007-11-11 2:53:26 >
# 8 Re: CString and char* memory issues
here is a simple example of what I mean...there is no memory leak...but it will report it, because cleanup hasn't occured.

int main(int argc, char* argv[])
{

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
CString foo("hi");
_CrtDumpMemoryLeaks();
return 0;
}

Detected memory leaks!
Dumping objects ->
strcore.cpp(118) : {52} normal block at 0x002F43F8, 15 bytes long.
Data: < hi > 01 00 00 00 02 00 00 00 02 00 00 00 68 69 00
Mick at 2007-11-11 2:54:34 >
# 9 Re: CString and char* memory issues
That's what I did (got rid of strcpy when it didn't fix it).

I used a dialog base application and the functions in question are all contained in the dialog window.

My Memory state checkpoints are in the main application (the one that creates the dialog window itself) at the very beginning and very end of InitInstance (thus, before the main dialog is constructed and after it's DoModal call). Therefore, shouldn't all cleanup relating to that window be done by the time the control hits the debugging statements?

Note that I agree with you, but memory leaks really frighten me :)

I will try the deconstructor breakpoint now.
JeanChretien at 2007-11-11 2:55:30 >
# 10 Re: CString and char* memory issues
Originally posted by JeanChretien
That's what I did (got rid of strcpy when it didn't fix it).

I used a dialog base application and the functions in question are all contained in the dialog window.

My Memory state checkpoints are in the main application (the one that creates the dialog window itself) at the very beginning and very end of InitInstance (thus, before the main dialog is constructed and after it's DoModal call). Therefore, shouldn't all cleanup relating to that window be done by the time the control hits the debugging statements?

Note that I agree with you, but memory leaks really frighten me :)

I will try the deconstructor breakpoint now.

And that's a good fear to have :) Would that more people had it ;) But you'll come across instances where memory leaks are not memory leaks...when in doubt, just break in the objects destructor and watch it get called and the memory get wacked. Your going to run into this hmm fairly often, where it's not a memory leak, but you'll be able to tell fairly quickly...in time...

Also, you know of _CrtSetBreakAlloc() ? to find the allocation block in {}...very useful to see whom allocated the reported leak.
Mick at 2007-11-11 2:56:37 >
# 11 Re: CString and char* memory issues
I believe I have verified that it is being destroyed! After reporting "memory leaked", it called ~CString twice. w00t, I guess.

But just to get a second opinion, when I say

class member variable of type CString = locally scoped char array;

Apparently, what happens is the control passes back to the funciton that created the dialog (hitting up the debug mem leak statement) while the deconstructor is imploding the class concurrently. I guess I should've realized that earlier, but thanks!
JeanChretien at 2007-11-11 2:57:39 >
# 12 Re: CString and char* memory issues
There's nothing happening concurrently here. Just take the following code snippet:// CString m_txt is a member of CMyDialog

{
CMyDialog dlg; // m_txt is now created.
dlg.DoModal(); // While inside DoModal, the internal CString buffer is allocated

// OK, now DoModal is done, but dlg (and hence m_txt) still exists.
// Doing a memory check here will report a leak!

}
// Now dlg is out of scope, and m_txt is destroyed
gstercken at 2007-11-11 2:58:33 >
# 13 Re: CString and char* memory issues
Originally posted by JeanChretien
That's what I did (got rid of strcpy when it didn't fix it).


If all you did was get rid of the strcpy line, you would still have a problem, because your code then would be trying to do a Left() on a negative number.

AppDir = AppDir.Left(AppDir.ReverseFind('\\'));

If AppDir is empty, or it does not have a '\\' character, it will always return a negative number and fail.

After you use GetBuffer, make sure you always to a .Release before using the CString member functions.
Axter at 2007-11-11 2:59:41 >
# 14 Re: CString and char* memory issues
Thanks, I just stuck with the direct equality. It always worked. It's just that the deconstructor wasn't called until the app quit (as the person mentioning the scope of the dialog pointed out)

Thanks for your help everyone.
JeanChretien at 2007-11-11 3:00:36 >
# 15 Re: CString and char* memory issues
Originally posted by akraus1
After the strcpy insert a

AppDir.Release() which copies the altered buffer back into
the CString object and deallocates the temporary buffer.You probably meant ReleaseBuffer(), which (unless GetBuffer was not called) just sets the length; there is no deallocation, since the buffer is the CString data.

I don't see a way that GetBuffer without a ReleaseBuffer would cause a memory leak. There might be a way that I don't see but I think it is more likely that the leak was the result of the same problems encountered subsequently.
Sam Hobbs at 2007-11-11 3:01:41 >