views:

483

answers:

10

I have a pointer to a given class. Lets say, for example, the pointer is:

0x24083094

That pointer points to:

0x03ac9184

Which is the virtual function table of my class. That makes sense to me. In windbg, everything looks correct.

I delete said pointer. Now at 0x24083094 is:

0x604751f8

But it isn't some random garbage, that address is put in there every time, it is consistently 0x604751f8! So much so that I can actually use that address to determine if that pointer was deleted, between executions of my application!

But Why? How does it determine that 0x604751f8 should be written there?

For the record, I am using windows, building under visual studio 2003.

EDIT: I know I can't rely on that value being set, even if it does appear to be consistent, but can I rely on it being different? ie, 0x03ac9184 will not be at 0x24083094 if the pointer is deleted, right? WHAT is put there could be anything, but 0x03ac9184 will definitely not be there (or else I could still call methods, since that is the virtual function table). Am I right?

Second EDIT: I feel like I have answer... can't rely on anything after it is deleted. Maybe some background will help people see where I am coming from. Essentially, I am trying to fix a bug where a pointer gets deleted out from under me. Its a long story, I won't go into the details. Basically, I am trying to detect that I am in this situation, so I can exit gracefully from my function. I suppose the easiest and best way is to just figure out who actually owns this pointer, and ask him if anything has changed. So I am going to implement a fix like that. It avoids any of this c++ delete hacker-y I was discussing.

HOWEVER, the interesting thing is that in our code we have a class called 'BogusObject' that essentially acts as a tray catching people that accidentally dereference freed objects. Basically, we hook our own delete functions and bash the BogusObject class into the vtable of any freed class. Then if someone calls something they get a nice message saying something to the effect of "hey, something is wrong dude.". This is happening in my case. ie 0x604751f8+(someoffset) is inside the BogusObject class. BUT WE NO LONGER USE BOGUSOBJECT!!!! It literally isn't setup anywhere (even links properly if I completely remove the BogusObject class), and yet I still end up getting the nice message saying something is wrong! But I am now of the opinion that it is a coincidence.

For some reason the runtime is putting that 0x604751f8 value in this pointer when it is deleted, and that just happens to correspond with the one class that has a purpose to catch situations like this! weird. But on to bigger and better bugs!

thanks for the help!

+16  A: 

Nothing in the standard determines what gets written there. Visual studio (at least in debug mode) will often write sentinal values all over the place to help in catching bugs early.

This value is not something you can rely on, but if you ever find that value popping up in your program mysteriously, you can assume that somewhere you are referencing deleted memory. See this answer for a list of values under one compiler.

It's also entirely possible that it's a free list pointer, pointing to the next piece of free memory. Most memory allocators keep their free memory in a linked list of sorts, using the free memory they are tracking to store the tracking data.

In any case, you MUST NOT use that pointer value for anything you want to keep working, unless you call up microsoft and get some documentation saying why that value is what it is, and get them to guarantee that it will not change. And even then, know that your code is now tied to one compiler's behaviour. In C++, accessing unallocated memory is undefined and evil.

Edit: You can't even rely on that value changing after a delete. There's nothing that says a compiler needs to modify the data on delete.

Eclipse
Yeah I know about the FEEEFEEE's and whatnot. But why the consistency in my case for it to ALWAYS put 0x604751f8 in that spot?
pj4533
0x604751f8 is likely to be a pointer to something (another free block maybe). But it could also be a bunch of bitflags or a signature
Michael Burr
Or garbage (there's nothing that says that garbage can't be consistent).
Michael Burr
+2  A: 

Just calling the delete operator for a pointer doesn't mean that the "deleted" memory will be cleared. It will only call the destructor of the deleted object(s) and marks the allocated heap memory as deallocated. (this is the default behavior of the delete operator).

If you need to clear the memory content when deleting, then you need to override the delete operator.

Cătălin Pitiș
Right, but SOMETHING else must be happening, because the memory changes. I understand it doesn't clear it....but it consistently makes it 0x604751f8. Why?
pj4533
Are you checking right after the delete statement? In that case, either the destructor alters the pointer or the pointer is changed from another thread.
Jonatan
It changes when compiled in Debug mode. AFAIK The deallocation functions behind delete change the content of the deallocated memory to "mark" the memory as free, for debug purposes. But not in Release target, for performance reasons...
Cătălin Pitiș
+5  A: 

One you delete an object the memory it was using gets put back into the free store (heap). Of course the free store will have its own data structures (and possibly debugging data) that it will apply to that memory.

What the particular value you're looking at means? Could be almost anything.

Michael Burr
Even more, it's probably misaligned access into the middle of a heap record structure.
Joshua
+2  A: 

As Josh said, there are a number of values that can be inserted, to make life easier for the debugger with debug builds. These are compiler specific and in no way can be relied on. In a release build, I believe the default behavior of most C++ compilers is to do nothing with the memory that is freed, so, until that address space is allocated again, the contents will basically be what ever was there before, of course, you should NEVER rely on this.

Serapth
+2  A: 

There is almost certainly a specific internal meaning to the value that appears every time you delete the object.

However, it may change with the next version of Visual C++, and will certainly be different on other vendors compilers.

The fact that it appears to be the same every time you delete an object does not signify anything useful. Nor can it even be potentially useful. Supposing you found some way to take advantage of it, it would be an appalling hack to do so, and you'd regret it eventually.

Try to put it out of your mind!

Daniel Earwicker
It might be useful as a debugging aid.
florin
@florin, unless you like statistical debugging that is a bad idea.
Joshua
+2  A: 

As Michael Burr said earlier, the memory goes back to the free store. Some free stores are implemented as linked lists, with the ->next pointer placed at the beginning of the free buffer. It is possible that the magic number that you are seeing (0x604751f8) to be the 'end of list' guard. You can check by performing the following experiment:

Foo* f = new Foo();
Bar* b = new Bar();

// make a note of the values of f and b _pointers_

delete b;  // check that b points now to 0x604751f8
delete f;  // check that f points now to 0x604751f8

// now check that does b point to;  it might point to f!

Let us know what you find!

florin
+2  A: 

Most likely this pointer value is the vtable of the base class. When a destructor for a derived class runs, after it completes its normal body, it 'recasts' the memory as the base type (basically, writing the base class vtable pointer into the object) and then calls the base class destructor.

Note that this behavior is an internal implementation detail of the compiler's runtime C++ support, so other compilers (or future versions of the same compiler) may do something completely different. But this 'convert vtable to base class and call the base class destructor' is fairly common and dates back to the original cfront implementation of C++

Chris Dodd
+2  A: 

The program is trying to tell you something. A date, a telephone number, who knows?

Now seriously, this is not specified, totally implementation-dependent, and of course trying to dereference that pointer after delete would lead to undefined behaviour. So, in short, who cares?

Daniel Daranas
+2  A: 

No, you cannot rely on it being set. You cannot even rely on it being different.

MS-DOS heap managers often allowed using freed memory until the next call to malloc. New and delete in that era called malloc and free.

These days, most heap managers are reasonable about returning memory to the OS, which means you cannot even rely on it being readable! Even one ones that still allow it (glibc has a bwd-compat mode that allows it) you are subject to thread-race conditions.

Also, delete is allowed to change the pointer to NULL if it is an lvalue.

Once you call delete, don't even think about dereferencing the pointer.

Joshua
A: 

You have access to the CRT source code in Visual Studio. You could take a look. I did once to better understand a bug I had.