In one of the special cases shown below, getpid()
for the grandchild created with vfork()
returns the PID of the parent process.
#include <stdio.h>
#include <stdlib.h>
int main() {
if(vfork()) { /* parent */
printf("parent pid = %d\n", getpid());
exit(0);
} else {
if(vfork()) { /* child */
printf("child pid = %d\n", getpid());
exit(0);
} else { /* grandchild */
printf("grandchild pid = %d\n", getpid());
exit(0);
}
}
}
Compiled as gcc main.c
, this works as expected:
grandchild pid = 12241
child pid = 12240
parent pid = 12239
Compiled as gcc main.c -lpthread
, the grandchild PID is incorrect:
grandchild pid = 12431
child pid = 12432
parent pid = 12431
Any clues why? Is this one of the undefined behavior cases?
With ps
and strace
, I can see the correct PID. BTW, the same example code works fine with fork()
, i.e. correct getpid()
with or without -lpthread
.
getpid
is not one of the two operations you're permitted to perform after vfork
in the child; the only two are execve
and _exit
. It happens that glibc caches the process's pid in userspace, and does not update this cache on vfork
(since it would modify the parent's cached value, and since it's not needed since valid code can't observe the result); that's the mechanism of the behavior you're seeing. The caching behavior differs slightly with -lpthread
linked. But the underlying reason is that your code is invalid.
Pretty much, don't use vfork
. There's basically nothing you can do with it.