Hi all

I've got a problem with the use of two classes I made.
I made a thread class similar to the 'Thread' class in Java.
I have a class for handling the thread (called CMMThread)
and another one (called CMMThreadObject) as an interface
(like the 'Runnable' interface in Java).
I put both classes in a dll and try to use them from
a normal .exe .
When I derive a class from CMMThread everything works as
expected, but when I derive a class from CMMThreadObject,
create a CMMThread object with the object derived from
CMMThreadObject passed in the constructor, I get an
assertion failure when trying to destroy the object
derived from CMMThreadObject, I get the assertion
failure

Here's the code of my classes (only relevant part):

<code>
CMMThreadObject::~CMMThreadObject()
{
if ( thread )
{
delete thread; // --> call destructor of CMMThread
thread = 0;
}
}

CMMThread::CMMThread(CMMThreadObject * object)
{
this->object = object;
id = 0;
handle = 0;
running = 0;
exitcode = 0;
}

CMMThread::~CMMThread()
{
if ( object )
{
object->thread = 0;
object = 0;
}
if ( handle )
{
int sts = CloseHandle(handle);
handle = 0;
}
} // <-- error occurs when returning from here

void
CMMThread::Start(void)
{
if ( object )
{
object->thread = this;
handle = CreateThread(0,0,CMMThreadRunObject,object,0,&id);
// handle = _beginthread(CMMThreadRunObject,0,object);
}
else
{
handle = CreateThread(0,0,CMMThreadRunThread,this,0,&id);
// handle = _beginthread(CMMThreadRunThread,0,this);
}
}

// BounceProc to start the thread with an associated object
MMTHREADRESULT __stdcall
CMMThreadRunObject(void * arg)
{
CMMThreadObject * object = (CMMThreadObject *)arg;
MMTHREADRESULT result;

object->thread->running = 1;
result = object->Run();
object->thread->running = 0;
// _endthread();
ExitThread(result);
return result;
}

// BounceProc to start the thread (using a class derived from CMMThread)
MMTHREADRESULT __stdcall
CMMThreadRunThread(void * arg)
{
CMMThread * thread = (CMMThread *)arg;
MMTHREADRESULT result;

thread->running = 1;
result = thread->Run();
thread->running = 0;
// _endthread();
ExitThread(result);
return result;
}
</code>


And here's the code of my app using my classes:

<code>
class TestObject : public CMMThreadObject
{
public :
MMTHREADRESULT Run(void);
};

class TestThread : public CMMThread
{
public :
MMTHREADRESULT Run(void);
};

...

TestObject * object[5];
CMMThread * thread[5];
// Here I create 5 threads
for ( i = 0; i < c; i++ )
{
sprintf(threadname,"Thread #%d",i);
object[i] = new TestObject();
thread[i] = new CMMThread(object[i]);
thread[i]->Start();
printf("thread %d started\n",i);
}
// Here I wait for the threads to complete
for ( i = 0; i < c; i++ )
{
object[i]->Thread()->Wait();
}
// Here I try to destroy all objects
for ( i = 0; i < c; i++ )
{
delete object[i]; // <-- Failure occurs here (indirectly)
// 1st, the destructor of CMMThreadObject is called
// which then destroys the thread object (see above)
}
</code>


When returning from the destructor of CMMThread, I see the
following assembler code (from where the error occurs):
10001265 mov eax,dword ptr [ebp+8]
10001268 and eax,1
1000126B test eax,eax
1000126D je CMMThread::`scalar deleting destructor'+3Bh
(1000127b)
1000126F mov ecx,dword ptr [ebp-4]
10001272 push ecx
10001273 call operator delete (100022d6)
10001278 add esp,4

Inside the call of the 'operator delete', '_free_dbg' is called,
which then calls '_free_dbg_lk' from dbgheap.c which then fails
in the statement '_ASSERTE(_CrtIsValidHeapPointer(pUserData));'

I can't see a reason for that. Both objects are created by my
test application and I also try to destroy them from there.
I tried many other combinations, like destroying the thread
object inside a 'Destroy' method (delete this) or destroying
the two objects inside the the test application (delete object[i]
and delete thread[i]) but nothing helped.
I also tried to use the _beginthread and _endthread functions
from C++ (according to MSDN, this is the way to go for C++ programs).

Can someone please help me to find a solution (maybe need to
create my own 'operator new' and 'operator delete' methods?).

Alexander Kienzle

Re: Assertion failure in dbgheap.c by Alexander

Alexander
Mon Apr 26 06:31:18 CDT 2004

"Alexander Kienzle" <madmax@pop.agri.ch> wrote in message
news:OHAmHA4KEHA.240@TK2MSFTNGP10.phx.gbl...
> Hi all
>
> I've got a problem with the use of two classes I made.
> I made a thread class similar to the 'Thread' class in Java.
> I have a class for handling the thread (called CMMThread)
> and another one (called CMMThreadObject) as an interface
> (like the 'Runnable' interface in Java).
> I put both classes in a dll and try to use them from
> a normal .exe .
> When I derive a class from CMMThread everything works as
> expected, but when I derive a class from CMMThreadObject,
> create a CMMThread object with the object derived from
> CMMThreadObject passed in the constructor, I get an
> assertion failure when trying to destroy the object
> derived from CMMThreadObject, I get the assertion
> failure
>
> Here's the code of my classes (only relevant part):
>
> <code>
> CMMThreadObject::~CMMThreadObject()
> {
> if ( thread )
> {
> delete thread; // --> call destructor of CMMThread
> thread = 0;
> }
> }
>
> CMMThread::CMMThread(CMMThreadObject * object)
> {
> this->object = object;
> id = 0;
> handle = 0;
> running = 0;
> exitcode = 0;
> }
>
> CMMThread::~CMMThread()
> {
> if ( object )
> {
> object->thread = 0;
> object = 0;
> }
> if ( handle )
> {
> int sts = CloseHandle(handle);
> handle = 0;
> }
> } // <-- error occurs when returning from here
>
> void
> CMMThread::Start(void)
> {
> if ( object )
> {
> object->thread = this;
> handle = CreateThread(0,0,CMMThreadRunObject,object,0,&id);
> // handle = _beginthread(CMMThreadRunObject,0,object);
> }
> else
> {
> handle = CreateThread(0,0,CMMThreadRunThread,this,0,&id);
> // handle = _beginthread(CMMThreadRunThread,0,this);
> }
> }
>
> // BounceProc to start the thread with an associated object
> MMTHREADRESULT __stdcall
> CMMThreadRunObject(void * arg)
> {
> CMMThreadObject * object = (CMMThreadObject *)arg;
> MMTHREADRESULT result;
>
> object->thread->running = 1;
> result = object->Run();
> object->thread->running = 0;
> // _endthread();
> ExitThread(result);
> return result;
> }
>
> // BounceProc to start the thread (using a class derived from CMMThread)
> MMTHREADRESULT __stdcall
> CMMThreadRunThread(void * arg)
> {
> CMMThread * thread = (CMMThread *)arg;
> MMTHREADRESULT result;
>
> thread->running = 1;
> result = thread->Run();
> thread->running = 0;
> // _endthread();
> ExitThread(result);
> return result;
> }
> </code>
>
>
> And here's the code of my app using my classes:
>
> <code>
> class TestObject : public CMMThreadObject
> {
> public :
> MMTHREADRESULT Run(void);
> };
>
> class TestThread : public CMMThread
> {
> public :
> MMTHREADRESULT Run(void);
> };
>
> ...
>
> TestObject * object[5];
> CMMThread * thread[5];
> // Here I create 5 threads
> for ( i = 0; i < c; i++ )
> {
> sprintf(threadname,"Thread #%d",i);
> object[i] = new TestObject();
> thread[i] = new CMMThread(object[i]);
> thread[i]->Start();
> printf("thread %d started\n",i);
> }
> // Here I wait for the threads to complete
> for ( i = 0; i < c; i++ )
> {
> object[i]->Thread()->Wait();
> }
> // Here I try to destroy all objects
> for ( i = 0; i < c; i++ )
> {
> delete object[i]; // <-- Failure occurs here (indirectly)
> // 1st, the destructor of CMMThreadObject is called
> // which then destroys the thread object (see above)
> }
> </code>
>
>
> When returning from the destructor of CMMThread, I see the
> following assembler code (from where the error occurs):
> 10001265 mov eax,dword ptr [ebp+8]
> 10001268 and eax,1
> 1000126B test eax,eax
> 1000126D je CMMThread::`scalar deleting destructor'+3Bh
> (1000127b)
> 1000126F mov ecx,dword ptr [ebp-4]
> 10001272 push ecx
> 10001273 call operator delete (100022d6)
> 10001278 add esp,4
>
> Inside the call of the 'operator delete', '_free_dbg' is called,
> which then calls '_free_dbg_lk' from dbgheap.c which then fails
> in the statement '_ASSERTE(_CrtIsValidHeapPointer(pUserData));'
>
> I can't see a reason for that. Both objects are created by my
> test application and I also try to destroy them from there.
> I tried many other combinations, like destroying the thread
> object inside a 'Destroy' method (delete this) or destroying
> the two objects inside the the test application (delete object[i]
> and delete thread[i]) but nothing helped.
> I also tried to use the _beginthread and _endthread functions
> from C++ (according to MSDN, this is the way to go for C++ programs).
>
> Can someone please help me to find a solution (maybe need to
> create my own 'operator new' and 'operator delete' methods?).
>
> Alexander Kienzle
>
>

Forget to mention that I don't want to use AFX or MFC!



Re: Assertion failure in dbgheap.c by Oleg

Oleg
Mon Apr 26 06:52:48 CDT 2004

Make sure that both the executable and the DLL are linked to the DLL version of CRT library,
so that they share the same CRT heap (see /MD and /MDd compiler options).

If they aren't, they will end up allocating blocks in one heap and deallocating them
in another, causing that assertion and other problems.

Regards,
Oleg





Re: Assertion failure in dbgheap.c by Alexander

Alexander
Mon Apr 26 08:30:12 CDT 2004

"Oleg Starodumov" <oleg_staro@hotmail.com> wrote in message
news:O3v6%23T4KEHA.2624@TK2MSFTNGP09.phx.gbl...
> Make sure that both the executable and the DLL are linked to the DLL
version of CRT library,
> so that they share the same CRT heap (see /MD and /MDd compiler options).
>
> If they aren't, they will end up allocating blocks in one heap and
deallocating them
> in another, causing that assertion and other problems.
>
> Regards,
> Oleg
>
>
>
>

I was using the Multithreaded DLL library (/MDd) for my dll file
and the Multithread library (/MTd) for my test application, which
seamed logical to me, but ..., I did as you suggested and using
/MDd in both projects solved my problem.
So this means that in C++ the objects are not allocated in the
heap of the module which creates the objects, does it?

Thanks a lot

Alex



Re: Assertion failure in dbgheap.c by Oleg

Oleg
Mon Apr 26 09:05:07 CDT 2004


> I was using the Multithreaded DLL library (/MDd) for my dll file
> and the Multithread library (/MTd) for my test application, which
> seamed logical to me, but ..., I did as you suggested and using
> /MDd in both projects solved my problem.
> So this means that in C++ the objects are not allocated in the
> heap of the module which creates the objects, does it?
>

In general, it depends on which CRT library implements the memory allocation function
you are calling to allocate the memory.

In your original configuration, if the executable calls a CRT memory allocation function
(new, malloc, etc.), the memory is allocated on the heap created by the CRT linked
with the executable. If the DLL calls a CRT memory allocation function, the memory
is allocated on the heap created by the CRT linked with the DLL.

When freeing the memory, it is necessary to free it from the correct heap (the one
it was allocated from). If the interface between the executable and the DLL
can ensure that, there is no problem. But usually it is difficult to share objects between
several modules without allocating them from the same place.

Regards,
Oleg