Search code examples
cmallocfree

How do I free an array in C inside a function that doesn't know if it is allocated on stack or heap?


Let's say in C I have implemented a function B foo(const A arr[]), where A and B are recursively dependent structs, potentially heavy dynamically allocated. Function foo creates B out of As (basically copying them in some way into B) and also takes care of freeing some deeply recursed elements inside original As in input array. I cannot change that functionality.

Now let's say I also have a function B bar(B *b1, B*b2) that does some work and statically allocates array of As out of b1 and b2 (of the length of |b1| * |b2| to be precise) and returns foo(A). So far it all has worked well: foo has been freeing dynamically allocated elements of A with no leaks and as arr was not malloc'ed I didn't have to free arr.

But then I've come across a stress test for bar that triggers a stack overflow due to excessive size of array it creates on stack (well, at least that's my guess as Valgrind reported some 10^6+ strange errors like "Invalid write of size 8/Address 0xffe8625d0 is on thread 1's stack" but zero leaks). So I changed the way I define an array of A inside bar from static to dynamic.

Valgrind's strange errors disappeared, but leaks have come out as I don't know how to free this intrinsic array of A inside bar as bar calls foo which needs that array and moreover it takes responsibility for it so the problem is there are calls to foo with arrays allocated either on stack or on heap and I cannot outsource free'ing outside foo. That is a homework 'good C style' project and hacky tricks (like some direct grabs of heap/stacks at low level) should be avoided.


Solution

  • You can't. Given just a pointer value, there is no portable/reliable way to determine if it was allocated by new, by malloc(), or if it even points to something on the heap (the pointer passed may actually point to an object on stack). It may even point to an element in an array. There's no way the function can tell.

    You have to manage your memory yourself. If you have declared A dynamically, then you will HAVE to change foo accordingly.