micsza micsza - 7 months ago 19
C Question

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
A
s (basically copying them in some way into
B
) and also takes care of freeing some deeply recursed elements inside original
A
s 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
A
s 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.

Answer Source

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.