problem deleting char* used in threads

A

Abubakar

Hi all,

My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both are
totally unmanaged. The gui app has a edit box, acting as a console, where I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{

extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);

}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
......
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to delete
it over here .
break;
.....
I get an error on the delete [] ptr line. It says:
-
Windows has triggered a breakpoint in OtengoGUI.exe.

This may be due to a corruption of the heap, and indicates a bug in
OtengoGUI.exe or any of the DLLs it has loaded.

The output window may have more diagnostic information
-
and the debugger stops at the following line with a green pointer arrow:
-

void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll =
FALSE, BOOL bCanUndo = FALSE)
{
SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll);
ReplaceSel(lpstrText, bCanUndo);
}<< ----------- this line

-
Why cant I delete a pointer that I got after casting from lParam parameter.
After all the allocation for this function was done on the heap and I should
be able to delete it anywhere else, thats what I was thinking.

Regards,

-ab.

Environment: visual studio 2k5, vc++ (unmanaged) WTL, windows 2000.
 
G

Guest

Abubakar said:
Hi all,

My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both are
totally unmanaged. The gui app has a edit box, acting as a console, where I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{

extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);

}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
......
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to delete
it over here .
break;
.....
I get an error on the delete [] ptr line. It says:
-
Windows has triggered a breakpoint in OtengoGUI.exe.

This may be due to a corruption of the heap, and indicates a bug in
OtengoGUI.exe or any of the DLLs it has loaded.

The output window may have more diagnostic information
-
and the debugger stops at the following line with a green pointer arrow:
-

void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll =
FALSE, BOOL bCanUndo = FALSE)
{
SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll);
ReplaceSel(lpstrText, bCanUndo);
}<< ----------- this line

-
Why cant I delete a pointer that I got after casting from lParam parameter.
After all the allocation for this function was done on the heap and I should
be able to delete it anywhere else, thats what I was thinking.

Regards,

-ab.

Environment: visual studio 2k5, vc++ (unmanaged) WTL, windows 2000.

Is your app and dll built with the same version of the crt ?

Wim
 
A

Arnaud Debaene

Abubakar said:
Hi all,

My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:
-
Why cant I delete a pointer that I got after casting from lParam
parameter.
After all the allocation for this function was done on the heap and I
should
be able to delete it anywhere else, thats what I was thinking.

Both module (DLL and EXE) must be linked against the same DLL version of the
C-Runtime library : Compile both modules either with /MD, either with /MDd
(be sure it is the same for both modules!).
This is the sine qua non condition to pass dynamically allocated pointers
(as well as other CRT-state dependents variables, such as FILE*) across
modules boundaries.

Arnaud
MVP - VC
 
B

Bruno van Dooren [MVP VC++]

Why cant I delete a pointer that I got after casting from lParam
parameter.
After all the allocation for this function was done on the heap and I
should
be able to delete it anywhere else, thats what I was thinking.

In addition to the answers you already got, deleting memory that was
allocated in another module is often an indication of bad design because it
creates inter-module dependencies.
It will work if both the app and the dll link against the same version of
the dynamic crt, but it might save you a lot of troubles in the long run if
you change your design so that it is not necessary.

For example, I think you should be able to use SysAllocString to solve your
problems.
Those BSTRs are module independent, so they are not influenced by the crt.


--

Kind regards,
Bruno van Dooren
(e-mail address removed)
Remove only "_nos_pam"
 
A

Abubakar

Is your app and dll built with the same version of the crt ?

How do I know that they r using the same or different?

-Abubakar.

Wim said:
Abubakar said:
Hi all,

My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both are
totally unmanaged. The gui app has a edit box, acting as a console, where I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{

extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);

}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
......
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to delete
it over here .
break;
.....
I get an error on the delete [] ptr line. It says:
-
Windows has triggered a breakpoint in OtengoGUI.exe.

This may be due to a corruption of the heap, and indicates a bug in
OtengoGUI.exe or any of the DLLs it has loaded.

The output window may have more diagnostic information
-
and the debugger stops at the following line with a green pointer arrow:
-

void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll =
FALSE, BOOL bCanUndo = FALSE)
{
SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll);
ReplaceSel(lpstrText, bCanUndo);
}<< ----------- this line

-
Why cant I delete a pointer that I got after casting from lParam parameter.
After all the allocation for this function was done on the heap and I should
be able to delete it anywhere else, thats what I was thinking.

Regards,

-ab.

Environment: visual studio 2k5, vc++ (unmanaged) WTL, windows 2000.

Is your app and dll built with the same version of the crt ?

Wim
 
A

Abubakar

In this project I just agreed upon a pattern that all threads that want to
send messages to the gui console will use this method "cglobal::sendmessage"
by allocating char * with *new* and upon receiving the pointers the gui
thread will be responsible to delete them. Now the display part happens just
fine but the deleting gives problem as I stated earlier. I would try the
sysallocstring that u mentioned.

Thanks,

-ab.
 
T

Tom Widmer [VC++ MVP]

Abubakar said:
In this project I just agreed upon a pattern that all threads that want to
send messages to the gui console will use this method "cglobal::sendmessage"
by allocating char * with *new* and upon receiving the pointers the gui
thread will be responsible to delete them. Now the display part happens just
fine but the deleting gives problem as I stated earlier. I would try the
sysallocstring that u mentioned.

SendMessage is synchronous (it doesn't return until the message has been
processed, in contrast to PostMessage, which returns immediately), so
you can safely delete the pointer in the calling method straight after
the call to SendMessage. That way the calling method can allocate the
memory any way it likes, or pass a string literal, etc. Passing around
ownership of raw pointers is a bad idea in general, but if you need to
do it, you need to precisely specify the allocation/deallocation
semantics (e.g. document that sysallocstring must be used).

Tom
 
A

Abubakar

It would be wonderful if it can be done that way. But what I'm thinking is
that the UI thread would be executing its code asynchronously right ? What
if the pointer is used by the ui thread after the deletion has been done?

I'll try that.

Ab.
 
A

Abubakar

As ::SendMessage returns after it's already dispatched, so you can freely
delete the memory after that call.

do u mean that the sender thread (which is using the sendmessage) will going
to wait for the receiving thread to process the message and resume after the
receiving thread's message has been processed ?

-ab.

Vladimir Nesterovsky said:
My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{

extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);

}

As ::SendMessage returns after it's already dispatched, so you can freely
delete the memory after that call.
 
B

Bruno van Dooren [MVP VC++]

It would be wonderful if it can be done that way. But what I'm thinking is
that the UI thread would be executing its code asynchronously right ?

SendMessage waits until the message has been handled before it returns.
This means that you can allocate before SendMessage, and deallocate after
SendMessage.
As long as the pointer is only used in the message handler that receives the
message, you will have no
problems at all.
What
if the pointer is used by the ui thread after the deletion has been done?

BOOM. Your program will crash.

Now if you implement it like I explained above, you should at least document
the reasoning behind your implementation.
It might be safe now, but if your design changes (for example, you start
using PostMessage), you will get all sorts of problems.

The solution with SysAllocString has the advantage that it will always work,
regardless of the way you send and process messages.

--

Kind regards,
Bruno van Dooren
(e-mail address removed)
Remove only "_nos_pam"
 
V

Vladimir Nesterovsky

My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{

extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);

}

As ::SendMessage returns after it's already dispatched, so you can freely
delete the memory after that call.
 
A

Abubakar

oh , got it, its been answered.

Thanks.
-ab.

Abubakar said:
As ::SendMessage returns after it's already dispatched, so you can freely
delete the memory after that call.

do u mean that the sender thread (which is using the sendmessage) will going
to wait for the receiving thread to process the message and resume after the
receiving thread's message has been processed ?

-ab.

Vladimir Nesterovsky said:
My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{

extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);

}

As ::SendMessage returns after it's already dispatched, so you can freely
delete the memory after that call.
 
A

Abubakar

Cool. I'll make a note that no one should change the sendmessage to
postmessage and to read these posts!

Thanks to all who replied.

-ab.
 
S

SvenC

Hi Abubakar,
My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{
extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);
}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
.....
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to
delete
it over here .
break;
....
I get an error on the delete [] ptr line.

Why cant I delete a pointer that I got after casting from lParam
parameter.
After all the allocation for this function was done on the heap and I
should
be able to delete it anywhere else, thats what I was thinking.

To answer that question: you have two distinct heaps. One from the crt
of your dll and one from the crt of your exe. So your exe's heap doesn't
contain the given pointer and cannot delete it. If you link both modules to
use the same crt instance they share the same heap.
But as a clean separation of modules cannot always ensure this
implementation detail (you might ship a new dll version which was
compiled with a new compiler thus using a new crt) you should not
rely on this.

In addition to Brunos suggestion to use SysAllocString you might also
consider to give your CGlobal class a member for freeing memory.
Assuming that CGlobal is exported from that dll and not only shared
in code, so that the implementation lives only in your dll you are
save to delete any memory in that function that was allocated in
another function of that dll:

void CGlobal::DeleteMessageString(char* p)
{
delete [] p;
}

Now you can savely call CGlobal::DeleteMessageString(ptr) in your exe
as the call is executing in your dll so that it is using the dlls crt heap.

Regards,
SvenC
 
A

Abubakar

Hi SvenC,

Thanks for the nice explanation. My process having 2 separate heaps really
sounds interesting :) and make things bit more clear to me. Can you give me
a link of some article that could explain this in detail ?

Regards,

-ab.

SvenC said:
Hi Abubakar,
My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{
extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);
}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
.....
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to
delete
it over here .
break;
....
I get an error on the delete [] ptr line.

Why cant I delete a pointer that I got after casting from lParam
parameter.
After all the allocation for this function was done on the heap and I
should
be able to delete it anywhere else, thats what I was thinking.

To answer that question: you have two distinct heaps. One from the crt
of your dll and one from the crt of your exe. So your exe's heap doesn't
contain the given pointer and cannot delete it. If you link both modules to
use the same crt instance they share the same heap.
But as a clean separation of modules cannot always ensure this
implementation detail (you might ship a new dll version which was
compiled with a new compiler thus using a new crt) you should not
rely on this.

In addition to Brunos suggestion to use SysAllocString you might also
consider to give your CGlobal class a member for freeing memory.
Assuming that CGlobal is exported from that dll and not only shared
in code, so that the implementation lives only in your dll you are
save to delete any memory in that function that was allocated in
another function of that dll:

void CGlobal::DeleteMessageString(char* p)
{
delete [] p;
}

Now you can savely call CGlobal::DeleteMessageString(ptr) in your exe
as the call is executing in your dll so that it is using the dlls crt heap.

Regards,
SvenC
 
S

SvenC

Hi Abubakar,

Abubakar said:
Hi SvenC,

Thanks for the nice explanation. My process having 2 separate heaps really
sounds interesting :) and make things bit more clear to me. Can you give
me
a link of some article that could explain this in detail ?

I did a quick search but didn't found too specific articles. You might want
to take a look at this:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dngenlib/html/heap3.asp
Here you can see multiple heaps with the CRT heap as a private heap. If you
statically link to a CRT it will have a private heap of its own and another
module with a statically linked CRT will have another private heap. The
dynamically linked CRT has also a private heap but all of your modules which
use the dynamic CRT will use that private heap throughout process life time.

Here is a short discussion:
http://groups.google.de/group/micro...13513452239/f5772c989b002616#f5772c989b002616

At least that gives you some key words for googling around.

Regards,
SvenC
Regards,

-ab.

SvenC said:
Hi Abubakar,
My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{
extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);
}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy
and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
.....
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to
delete
it over here .
break;
....
I get an error on the delete [] ptr line.

Why cant I delete a pointer that I got after casting from lParam
parameter.
After all the allocation for this function was done on the heap and I
should
be able to delete it anywhere else, thats what I was thinking.

To answer that question: you have two distinct heaps. One from the crt
of your dll and one from the crt of your exe. So your exe's heap doesn't
contain the given pointer and cannot delete it. If you link both modules to
use the same crt instance they share the same heap.
But as a clean separation of modules cannot always ensure this
implementation detail (you might ship a new dll version which was
compiled with a new compiler thus using a new crt) you should not
rely on this.

In addition to Brunos suggestion to use SysAllocString you might also
consider to give your CGlobal class a member for freeing memory.
Assuming that CGlobal is exported from that dll and not only shared
in code, so that the implementation lives only in your dll you are
save to delete any memory in that function that was allocated in
another function of that dll:

void CGlobal::DeleteMessageString(char* p)
{
delete [] p;
}

Now you can savely call CGlobal::DeleteMessageString(ptr) in your exe
as the call is executing in your dll so that it is using the dlls crt heap.

Regards,
SvenC
 
A

Abubakar

Thanks, cool.

=ab.

SvenC said:
Hi Abubakar,

Abubakar said:
Hi SvenC,

Thanks for the nice explanation. My process having 2 separate heaps really
sounds interesting :) and make things bit more clear to me. Can you give
me
a link of some article that could explain this in detail ?

I did a quick search but didn't found too specific articles. You might want
to take a look at this:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dngenlib/ht
ml/heap3.asp
Here you can see multiple heaps with the CRT heap as a private heap. If you
statically link to a CRT it will have a private heap of its own and another
module with a statically linked CRT will have another private heap. The
dynamically linked CRT has also a private heap but all of your modules which
use the dynamic CRT will use that private heap throughout process life time.

Here is a short discussion:
http://groups.google.de/group/microsoft.public.vc.ide_general/browse_thread/
thread/6ee1e13513452239/f5772c989b002616%23f5772c989b002616

At least that gives you some key words for googling around.

Regards,
SvenC
Regards,

-ab.

SvenC said:
Hi Abubakar,

My solution consists of 2 projects, 1 is a dll (contains sockets
functionality, multithreaded), and the other is a wtl gui project. Both
are
totally unmanaged. The gui app has a edit box, acting as a console, where
I
send messages from dll to be displayed. The way I am sending messages is:
for sending the message:

void CGlobal::SendMessage(char * chptr )
{
extern HWND c_main_window_handle;
char * tmp = new char [ strlen ( chptr) +1 ];
strcpy ( tmp, chptr );
::SendMessage( c_main_window_handle, WM_DISPLAY_MSG, 200, (LPARAM)tmp);
}
(this function is somewhere inside the dll) any thread can call this class
and pass it any character array, it will create its own buffer, copy
and
send its pointer to the gui thread.
The gui application has a file that has this function declared:

LRESULT proc_display_message(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam,
BOOL& /*bHandled*/)

proc_display_message receives the message and does something like this:
.....
case 200:
char * ptr = (char * )lParam ;

diagtext->AppendText (ptr);
diagtext->AppendText ("\r\n");

delete [] ptr ; // this was allocated somewhere else and I plan to
delete
it over here .
break;
....
I get an error on the delete [] ptr line.

Why cant I delete a pointer that I got after casting from lParam
parameter.
After all the allocation for this function was done on the heap and I
should
be able to delete it anywhere else, thats what I was thinking.

To answer that question: you have two distinct heaps. One from the crt
of your dll and one from the crt of your exe. So your exe's heap doesn't
contain the given pointer and cannot delete it. If you link both
modules
to
use the same crt instance they share the same heap.
But as a clean separation of modules cannot always ensure this
implementation detail (you might ship a new dll version which was
compiled with a new compiler thus using a new crt) you should not
rely on this.

In addition to Brunos suggestion to use SysAllocString you might also
consider to give your CGlobal class a member for freeing memory.
Assuming that CGlobal is exported from that dll and not only shared
in code, so that the implementation lives only in your dll you are
save to delete any memory in that function that was allocated in
another function of that dll:

void CGlobal::DeleteMessageString(char* p)
{
delete [] p;
}

Now you can savely call CGlobal::DeleteMessageString(ptr) in your exe
as the call is executing in your dll so that it is using the dlls crt heap.

Regards,
SvenC
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top