Answers to questions in your head: Yes, this is for school. No, I can't use threads for this. And yes, I looked for an answer and some people said "yes" and others said "no." I'm also fact-checking my professor because I don't want to unfairly lose points if someone else were to grade it and they require this to be "fixed."
With that being said... consider this simple program for c on the Linux system. I malloc something and then fork. I boiled down my project to the exact problem:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main( void )
{
char * args [] = { "someinvalidcommand", NULL };
// malloc before the fork (happens in parent process)
char * something = (char *)malloc(sizeof(char));
pid_t child_pid = fork();
// are there now two things that need to be freed:
// one for each process?
if(child_pid == 0) // child process
{
//free(something); // is this needed?
// execvp (it won't return if succeeded)
if(execvp(args[0], args) < 0)
{
// or do I only need to free it here?
printf("%s: No such file or directory\n", args[0]);
/*
* EDIT: Calling it here seems to fix the issue. It turns out
* that the system calls were the ones with the "still reachable"
* errors, so I guess it's not all that important that the
* memory be freed.
*
* free(something)
*/
_exit(1);
}
}
else // parent process
{
int status;
while(wait(&status) != child_pid);
if(status != 0)
{
printf("command status: %i\n", WEXITSTATUS(status));
}
}
free(something);
return 0;
}
Now this is where it's slightly confusing. To my knowledge, fork creates an exact copy of the parent process at that particular state (including text, data, etc.). I read somewhere that this includes anything malloc'd (so, the heap). However, I read somewhere else that it doesn't because of something called "copy-on-write," but then I read somewhere else that "copy-on-write" is simply an optimization that's transparent and irrelevant. But then what I read that made the most sense was that since it's a COPY, it has its own, well... everything.
But then I recall that when fork() is used, whatever was malloc'd will contain the same memory address, so are the parent and child pointing to the same thing? Do I need to free resources in the child, as well? Are only the pointers copied, or are the data that the pointers are pointing to also copied?
I used valgrind and when the child process exits, it simply complains that all the memory is still reachable. How exactly is it "still reachable?" Does the fact that it's "still reachable" answer my question and say that the parent and child are pointing to the same thing and the parent's the only one responsible for freeing the memory?
In the absence of the calls to the exec
family, you have to free()
it. Parent and child do not point to the same thing, because they are separate processes and do not share the same address space. Imagine what would happen under the alternative if the parent free()
d it, for instance, and then the child tried to access it.
If you do call something like execvp()
, then as tmyklebu mentions, your process just gets wiped, and you don't have to do anything.
"Still reachable" means you still have a reference to it, but you haven't free()
d it yet. Since all your memory gets free()
d on termination anyway, this sometimes isn't so much of a problem, compared to getting an actual memory leak where you permanently lose track of allocated memory. Valgrind's FAQ itself says that "your program is probably ok -- it didn't free some memory it could have. This is quite common and often reasonable." Opinions on the subject differ - some folks say it's good form to explicitly free() everything, others say it's a pointless waste of resources to do what program termination is going to do for you all by itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With