I am current reading OSTEP and come across this piece of code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
// fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); // program: "wc" (word count)
myargs[1] = strdup("p3.c"); // argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
printf("this shouldn't print out");
} else {
// parent goes down this path (original process)
int wc = wait(NULL);
//WHY IS THIS LINE PRINTED OUT??? Call to exec() already
//overwrites the original code segment
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
rc, wc, (int) getpid());
}
return 0;
}
And here is the output:
hello world (pid:22206)
hello, I am child (pid:22207)
32 123 966 p3.c
hello, I am parent of 22207 (wc:22207) (pid:22206)
$
The author says: "What it does: given the name of an executable (e.g.,wc), and some arguments (e.g.,p3.c), it loads code (and static data) from that executable and over-writes its current code segment (and current static data) with it; the heap and stack and other parts of the memory space of the program are re-initialized. Then the OS simply runs that program, passing in any arguments as the argv of that process. Thus, it does not create a new process; rather, it transforms the currently running program (formerly p3) into a different running program (wc). After the exec()in the child, it is almost as if p3.c never ran; a successful call to exec()never returns."
The bolded part is where I feel so confused. From my understanding, the parent process stops at line int wc = wait(NULL);
, and the child process starts from int rc = fork();
until it reaches execvp(myargs[0], myargs);
. After that, the codes from that called executable are loaded and overwrites the current code segment, and the stack and heap is re-initialized, transforming the original program to a different running program, but why hello, I am parent of 22207 (wc:22207) (pid:22206)
still got printed out after the original code segment has been overwritten and call to exec() never returns?
CodePudding user response:
When the authors say:
"(...) Thus, it does not create a new process; rather, it transforms the currently running program (formerly p3) into a different running program (wc). After the exec()in the child, it is almost as if p3.c never ran; a successful call to exec()never returns."
They mean that the child process, not the parent process, will be overwritten by the exec() command. That's why the reaming code in the child process after the exec is not executed. Remember that the child process code is only those lines inside the else if (rc == 0) clause:
else if (rc == 0) {
// child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); // program: "wc" (word count)
myargs[1] = strdup("p3.c"); // argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
printf("this shouldn't print out");
}
Remember also that the child process is itself a new process, with its own memory segments. Therefore an exec() command will not affect its parent (or even have access to its parent) not even other child processes from the same parent.