The following code never ends. Why is that?
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#define SIZE 5
int nums[SIZE] = {0, 1, 2, 3, 4};
int main()
{
int i;
pid_t pid;
pid = vfork();
if(pid == 0){ /* Child process */
for(i = 0; i < SIZE; i++){
nums[i] *= -i;
printf(”CHILD: %d “, nums[i]); /* LINE X */
}
}
else if (pid > 0){ /* Parent process */
wait(NULL);
for(i = 0; i < SIZE; i++)
printf(”PARENT: %d “, nums[i]); /* LINE Y */
}
return 0;
}
Update:
This code is just to illustrate some of the confusions I have regarding to vfork()
. It seems like when I use vfork()
, the child process doesn't copy the address space of the parent. Instead, it shares the address space. In that case, I would expect the nums array get updated by both of the processes, my question is in what order? How the OS synchronizes between the two?
As for why the code never ends, it is probably because I don't have any _exit()
or exec()
statement explicitly for exit. Am I right?
UPDATE2:
I just read: 56. Difference between the fork() and vfork() system call?
and I think this article helps me with my first confusion.
The child process from vfork() system call executes in the parent’s address space (this can overwrite the parent’s data and stack ) which suspends the parent process until the child process exits.
Don't use
vfork
. That's the simplest advice you can get. The only thing thatvfork
gives you is suspending the parent until the child either callsexec*
or_exit
. The part about sharing the address space is incorrect, some operating systems do it, other choose not to because it's very unsafe and has caused serious bugs.Last time I looked at how applications use
vfork
in reality the absolute majority did it wrong. It was so bad that I threw away the 6 character change that enabled address space sharing on the operating system I was working on at that time. Almost everyone who usesvfork
at least leaks memory if not worse.If you really want to use
vfork
, don't do anything other than immediately call_exit
orexecve
after it returns in the child process. Anything else and you're entering undefined territory. And I really mean "anything". You start parsing your strings to make arguments for your exec call and you're pretty much guaranteed that something will touch something it's not supposed to touch. And I also meanexecve
, not some other function from the exec family. Many libc out there do things inexecvp
,execl
,execle
, etc. that are unsafe in avfork
context.What is specifically happening in your example:
From the official specification:
In your program you modify data other than the
pid
variable, meaning the behavior is undefined.You also have to call
_exit
to end the process, or call one of theexec
family of functions.The child must
_exit
rather than returning frommain
. If the child returns frommain
, then the stack frame does not exist for the parent when it returns fromvfork
.just call the _exit instead of calling return or insert _exit(0) to the last line in "child process". return 0 calls exit(0) while close the stdout, so when another printf follows, the program crashes.
To quote from the
vfork(2)
man page:You're doing a whole bunch of those things, so you shouldn't expect it to work. I think the real question here is: why you're using
vfork()
rather thanfork()
?