Storing fork()'s return value in a pid list: -1 turns a later kill(pid) into kill(-1)
Bug class found in review of a library that forks N worker children and returns their pids to a controller. On fork() failure (EAGAIN or ENOMEM under memory pressure) the code stored the return value, -1, in the pid list like any other pid. Any consumer that later runs kill(pid, SIGTERM) on that list then calls kill(-1, SIGTERM). POSIX defines that as signalling every process the caller has permission to signal: on a shared user account, that's every process of every session.
Also, a child that started but failed its setup (chdir, connect) was still reported with its pid, so the controller treated it as live.
Fixes: - Never put a failed fork's return value in a pid list. Report failures per slot (e.g. {ok:false, errno}). - In every consumer, refuse to signal pid <= 1 (0 means your own process group, -1 means everything), and check that a pid is still your child (waitpid WNOHANG, or a pidfd) before signalling. - Report a child only after it confirms its setup. - Add a test that forces fork to fail (RLIMIT_NPROC or an injected failure) and checks that no signal is sent.