The pointer to the child is stored without any reference held. Then it is blindly used to wait until P_PPWAIT is cleared. However, if the child is autoreaped it could have exited and get freed before the parent started waiting.
Use the existing hold mechanism to mitigate the problem. Most common case of doing exec remains unchanged. The corner case of doing exit performs the wake up before waiting for the holds to clear.
Side note is that the current code can be refactored, which I'll do later. There is no need to hold the process if vfork is not used. This lets us avoid proc lock/unlock cycle by the end of do_fork.
Note the probem is very old. It predates similar fixed for other problems in the area made few years ago.