operator delete question ?

L

lothar.behrens

Hi,

I have problems to delare a delete operator in a class and use it to
check
for valid pointer. Using release() with an additional validation
routine
from a separate malloc library avoids the double deletion.

The first delete will call the destructor and after it the delete
operator
will be called. It works.

At the second try, the assembler code seems to call an address at
0xBDBDBDBD.
My malloc library fills the freed buffer with 0xBD bytes.

Why does this not work ?

The same is when I define release as virtual.

Is this a compiler specific behaviour ?

I use Open Watcom 1.3.

Thanks, Lothar

class CTest {
public:
CTest() {}
virtual ~CTest() {}
void release();
static void* operator new(size_t size);
static void operator delete(void* p, size_t size);

char buf[100];
};

void CTest::release() { if (TRMemValidate(this)) delete this; }
void* CTest::eek:perator new(size_t size) { return malloc(size); }
void CTest::eek:perator delete(void* p, size_t size) { free(p); }

int main() {
printf("Hello world.\n");

CTest *ct = new CTest();
CTest *ct1 = ct;

ct->release();
ct1->release(); // Check works, if not virtual

ct = new CTest();
ct1 = ct;

delete ct;
delete ct1; // Crash

return 0;
}
 
V

Victor Bazarov

I have problems to delare a delete operator in a class and use it to
check
for valid pointer. Using release() with an additional validation
routine
from a separate malloc library avoids the double deletion.

The first delete will call the destructor and after it the delete
operator
will be called. It works.

At the second try, the assembler code seems to call an address at
0xBDBDBDBD.
My malloc library fills the freed buffer with 0xBD bytes.

Why does this not work ?

Because you're using a debug build, probably...
The same is when I define release as virtual.

Is this a compiler specific behaviour ?

Could be. Nothing specific is said about the contents of memory after
it's been released. You are not supposed to be looking at it.
I use Open Watcom 1.3.

Thanks, Lothar

class CTest {
public:
CTest() {}
virtual ~CTest() {}
void release();
static void* operator new(size_t size);
static void operator delete(void* p, size_t size);

IIRC, in both cases, the keyword 'static' must be omitted. But if your
compiler doesn't complain, you could leave them in. Until some other
compiler complains, that is.
char buf[100];
};

void CTest::release() { if (TRMemValidate(this)) delete this; }
void* CTest::eek:perator new(size_t size) { return malloc(size); }
void CTest::eek:perator delete(void* p, size_t size) { free(p); }

int main() {
printf("Hello world.\n");

CTest *ct = new CTest();
CTest *ct1 = ct;

ct->release();
ct1->release(); // Check works, if not virtual

ct = new CTest();
ct1 = ct;

delete ct;
delete ct1; // Crash

Of course. You're deleting the same object twice. Undefined behaviour
is what you're getting. A crash is just a form of undefined behaviour.
It does not matter whether your class has overloaded operator delete or
not. Before your 'delete' is called, a destructor is executed and you
are not supposed letting the destructor to execute twice for the same
object.
return 0;
}

V
 
L

lothar.behrens

What then are the usual ways to detect a double delete ?

In my version of a base class not to use delete on it is this:

class lb_I_Unknown {
public:
virtual void release() = 0;
virtual void queryInterface(char* name, void** unknown, char*
file, int line)
};

It is a pure abstract class (interface). This works, even the reference
count goes to -1.
I have printed out a warning, the line number and file name where i
have got the
reference (with the queryInterface function). This let me found a
possible double delete
and I have corrected it. But it doesn't crash with a call to release.

So I may ask the compiler vendor about that and the failing sample.

Thanks, Lothar
 
V

Victor Bazarov

What then are the usual ways to detect a double delete ?

Use a memory debugging tool like valgrind or Purify.

The cause for double delete are dangling pointers. You need to make
sure that there is one easily identifiable _owner_ for every dynamically
allocated object. The owner is the only one who is allowed to delete
the object. If you do that, you can let the owner to set the pointer
it keeps to null right after deletion. Even if other objects hold onto
a pointer to that dynamic object, they shouldn't attempt deleting it.
In my version of a base class not to use delete on it is this:

class lb_I_Unknown {
public:
virtual void release() = 0;
virtual void queryInterface(char* name, void** unknown, char*
file, int line)
};

It is a pure abstract class (interface).

There is no such thing as "a pure abstract class", only "an abstract
class" or "a pure function".
> This works, even the reference
count goes to -1.

What reference count?
I have printed out a warning, the line number and file name where i
have got the
reference (with the queryInterface function). This let me found a
possible double delete
and I have corrected it. But it doesn't crash with a call to release.

I am not sure I understand the last statement.
So I may ask the compiler vendor about that and the failing sample.

Not a bad idea, but it will probably get you a non-portable solution,
although many compiler vendors/creators are quite knowledgeable about
C++ Standard. It never hurts to ask if the solution they're offering
is portable.

V
 
L

lothar.behrens

I have no money for a debug malloc tool. I don't know, if your
mentioned tools are for free.

Currently I use the debug malloc tool from my compiler vendor. It
detects leaks, and
double deletes as unknown adresses. But it may reuse a prior deleted
pointer and this may end up in undefined behaviour if an old pointer to
a type is used where the type
currently allocated is not the same (different vtable).

My reference count mechanism is used to detect when the class has to
delete it self.
I cannot delete the pointer to an object directly. It is part of my
design.

I know about the 'owner' of an object pointer. In my implementation the
class it self
takes care about this with the help of my release function. Using
queryInterface
increases the reference count of an object and returns a pointer to be
used.

This pointer then is stored in a macro based smart pointer which is
released when
out of scope. If the reference goes to zero (while the call to release)
it deletes it self.

This works very well, if I ever use the macro to hold pointers to
objects.

About the statement, you don't understand, is exactly the problem I do
not understand
why the application works. A call to virtual release() with a prior
deleted object would
end up in an exeption near 0xBDBDBDBD.

My simple test application I have posted, the call to release crashes.
This is why a
warning inside that function would not work. But I got these warning
???

My application does not crash near 0xBDBDBDBD. But in _nmalloc_.
So it seems, the malloc structure it self is corrupted and also I
cannot trace back
to valid code from my DLL - possible stack corruption.

The code is as portable as I can do. I use it on Windows with Open
Watcom,
On Linux with GCC and Mac OS X with GCC.

On Windows and OW, I have an opportunity to change the debug mallog
library
to not really delete the memory. Then it should not crash and let me
detect deleted
objects. Much more memory usage but may be a way.

So I am a little struggled :-(

My last public version (0.5.1) works without any problems, but now I
try to fix memory
leaks. So all the difficult stuff happens on cleanup time and program
ending.

Lothar
 

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

Members online

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top