5

I'm writing a debug versions of global delete/new operator to detect memory leaks, double deletes and delete on unallocated memory.

As far as "new" operator is concerned, I overrode the global new operator and using macros I passed file name and line number information. The overridden "new" operator stores the memory address, file name, size and line number information in map keyed on address.

I overrode "delete" operator too, which removes the deleted address' entry from the map. Now i want to store the deleted memory information in another map which stores the file name and line number information from where the "delete" was called.

But the delete operator takes only argument (memory address of the object to be deleted). Can someone tell how to detect double deletes in the code?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
nikhil kohli
  • 71
  • 2
  • 6
  • 1
    I think there are tools for this. –  Jun 13 '11 at 05:59
  • 2
    Why cannot behave similar like "new", i.e., when deleting, check the passed in address, if it's already in the "deleted" map, it's a double-delete. Where is the problem? – Eric Z Jun 13 '11 at 06:08
  • 1
    You might also want to consider writing allocated/deallocated memory with a pattern (like 0xbaadf00d) to see if deallocated or un-initialized memory is accessed. The Visual Studio Debug Heap does this, and more. See http://stackoverflow.com/questions/127386/in-visual-studio-c-what-are-the-memory-allocation-representations – Macke Jun 13 '11 at 07:28
  • possible duplicate of [Critique my non-intrusive heap debugger](http://stackoverflow.com/questions/2835416/critique-my-non-intrusive-heap-debugger) – fredoverflow Jun 13 '11 at 08:58
  • @FredOverflow: Thanks for pointing me there, but even there the program is detecting double delete (when that could even be a delete on unallocated memory). I'm interested to know from where was first delete called on the doubly deleted memory. In large codebases, that is a useful information. – nikhil kohli Jun 15 '11 at 06:12
  • ◎nikhil, you can add a flag to each entry in the map. When deallocating a buffer, check the flag. If it's MEM_ALLOCATED, it's a valid deletion. Release the buffer, record file and line information, and mark the entry as MEM_DEALLOCATED without deleting the entry from the map. If it's already MEM_DEALLOCATED, it's a double-delete. – Eric Z Jun 15 '11 at 06:56

3 Answers3

7

You are already creating a map of allocated memory addresses(key) and filename, line number(value fields) inside your overloaded new.

While in your overloaded delete just check if the address being passed exists in the map you created.

If Yes, You consider the call to delete as valid and remove that address entry from your map.

If No, then consider the call to delete as faulty, delete called on a pointer not allocated through your new or trying to call delete multiple times.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
2

If what you need is to differentiate a double delete from a delete from a never allocated memory, just map addresses to state of the allocated memory, instead of removing the element from the map, just update the state to mark it as already released. The test in each delete would verify if the address is present (if not the error is deleting a never allocated address), and if so, whether the memory has already been released (if it has, then the error is a double free).

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • nice idea, updating 1 map is better than maintaining two. But how to check from where was the first delete called? – nikhil kohli Jun 15 '11 at 06:32
  • @nikhil kohli: You should really use a prepacked solution (consider `valgrind` in linux). But basically, the map has to store more information. The key will still be the address, but the contents will have to store the additional information you need (where the memory was allocated from --in case it leaks--, where it was released --to detect double deletes...) – David Rodríguez - dribeas Jun 15 '11 at 07:56
1

There are two separate issues: detecting the double delete (as opposed to a delete of memory that was never allocated, and determining where in the program it occurred. For the first, my debugging operator new allocates guard zones before and after the block it returns (also used for detecting writes past the end on deallocation); I set them to a different pattern in operator delete, and check for this pattern. There's always the chance that never allocated memory might contain this pattern, but the chance is very, very small. Determining where in the code the error occurred is more difficult. I've written code which does a stack walkback, but it's very system dependent. (I have versions for Solaris on Sparc, Linux on Intel, and Windows.) And all it reports is the return addresses in hex; it's up to the programmer to analyse those, using other tools. The GNU binutils package has a program addr2line, which works well under Linux, but it's not that difficult to do manually, given a sorted map.

James Kanze
  • 150,581
  • 18
  • 184
  • 329