If you really want to catch those, a better idea might be to do something like:
Code: Select all
#include <stdio.h>
/* This symbol is inserted at the end of .bss section by gcc
* default linker script. For obvious reasons, relying on such
* a symbol is NOT PORTABLE AT ALL.
*
* Type doesn't matter since we only take the address anyway.
*/
extern int _end;
void myfree(void * p) {
int foo;
if(p > &foo||p < &_end) {
fprintf(stderr, "myfree: pointer not in heap.\n");
abort();
}
free(p);
}
Like said in the comment, it's not portable to assume that there's an _end symbol in there. On
my x86 linux with gcc though (and probably other gcc targets), this is the case. To verify that this is indeed the case, you can look at the default linker scripts.
But that's not the only problem. We also rely on the fact that heap is after the mapped image, that is, any address in the heap is necessarily after _end.
Finally, we check that it's not a stack allocated pointer. We do this by comparing the address with the address of a local variable. This relies on the fact that stack grows down (towards address zero) on x86. Since the local variable is (almost) on top of the stack, any
valid address within the stack is necessarily after it.
Ofcourse if you take the address of a local in some function, then return from that function (so that the stack address is no longer valid) we won't necessarily catch that. Doing so is a bug anyway, and since catching it would require us to know where the heap ends, I didn't bother.
Finding the end of heap isn't necessarily hard though. Just write another function mymalloc(), which calls malloc, and if we get a block which extends after the known end of heap (add the address and the blocksize), write it down as the new known heap end. The ugly thing is that then you need to make sure malloc() is never called directly, so I think doing this is even worse idea than using the current stack-top.