Does strdup allocate another memory zone and create another pointer every time?
For example: does the following code result in a memory leak?
void x(char** d, char* s){
*d = strdup(s);
}
int main(){
char* test = NULL;
x(&test, "abcd");
x(&test, "etc");
return 0;
}
Yes, the program leaks memory because it allocates objects and then loses references to them.
The first time this happens is in the line:
The variable
test
holds the one and only copy of a pointer that was allocated in a previous call tox
. The new call tox
overwrites that pointer. At that point, the pointer leaks.This is what it means to leak memory: to lose all references to an existing dynamically allocated piece of storage.*
The second leak occurs when the
main
function returns. At that point, thetest
variable is destroyed, and that variable holds the one and only copy of a pointer to a duplicate of the"etc"
string.Sometimes in C programs, we sometimes not care about leaks of this second type: memory that is not freed when the program terminates, but that is not allocated over and over again in a loop (so it doesn't cause a runaway memory growth problem).
If the program is ever integrated into another program (for instance as a shared library) where the original
main
function becomes a startup function that could be invoked repeatedly in the same program environment, both the leaks will turn into problems.The POSIX
strdup
function behaves similarly to this:Yes; it allocates new storage each time.
If you have a garbage collector (such as Boehm) in your C image, then it's possible that the leaked storage is recycled, and so
strdup
is able to re-use the same memory for the second allocation. (However, a garbage collector is not going to kick in after just one allocation, unless it is operated in a stress-test mode for flushing out bugs.)Now if you want to actually reuse the memory with realloc, then you can change your
x
function along these lines:(By the way, external names starting with
str
are in an ISO C reserved namespace, butstrealloc
is too nice a name to refuse.)Note that the interface is different. We do not pass in a pointer-to-pointer, but instead present a
realloc
-like interface. The caller can check the return value for null to detect an allocation error, without having the pointer inconveniently overwritten with null in that case.The
main
function now looks like:Like before, there is no error checking. If the first
strealloc
were to fail,test
is then null. That doesn't since it gets overwritten anyway, and the first argument ofstrealloc
may be null.Only one
free
is needed to plug the memory leak.* It's possible to have a semantic memory leak with objects that the program hasn't lost a reference to. For instance, suppose that a program keeps adding information to a list which is never used for any purpose and just keeps growing.