Somewhat unusual use case. A comment is needed to explain why we are doing it.
Applied, thank you. On Sat, May 31, 2025 at 5:53 AM Valentin Lab <valentin.lab_busy...@kalysto.org> wrote: > > This patch fixes a long-standing zombie-process leak in crond that > appears whenever crond itself is PID 1 (typical in minimal BusyBox > containers). > > Reproducer > ========== > > mkdir /tmp/test-root-crontabs -p > echo "* * * * * sh -c 'sleep 1 &'" > "/tmp/test-root-crontabs/root" > sudo chown root:root -R /tmp/test-root-crontabs > > ## Run busybox crond PID 1 > docker run -d --rm --name busybox \ > -v /tmp/test-root-crontabs/root:/var/spool/cron/crontabs/root:ro \ > busybox:1.37.0-uclibc \ > crond -f -d 0 > /dev/null > > watch -n 1 ' > echo "Expecting more zombies in $((60 - 10#$(date +%S)))s (Ctrl-C to > quit):" > ps -ax -o pid,ppid,stat,comm | egrep "\s+Z\s+" > ' > echo "Cleaning busybox container" > docker stop busybox > > > You should see one new "sleep" zombie each minute. > > If crond is *not* PID 1 (e.g. started via a wrapper shell), the leak > does not appear because the wrapper—now PID 1—reaps the orphans. > > > Root cause > ========== > > crond only calls `waitpid()` for PIDs it tracks. Background tasks > (`sleep 5 &`) become orphans; the kernel re-parents them to PID 1. > When crond *is* PID 1, it inherits these orphans but never waits for > them, so they persist as zombies. > > > Fix > === > > Add a tiny reaper loop: > > while (waitpid(-1, NULL, WNOHANG) > 0); > > Placed at the end of `check_completions()`, it collects any remaining > children. On systems where crond is **not** PID 1 the loop returns > `-ECHILD` immediately, so behaviour and overhead are unchanged. > > > Testing > ======= > > * Reproduced the leak on `busybox:1.37.0-uclibc` and current git master. > * Applied the patch, rebuilt BusyBox statically (with only crond), > bind-mounted the binary into a fresh container; zombie count stays at > 0 after X min. > > Suggested docker commmand for testing with compiled (static) binary in CWD: > > docker run --rm --name busybox \ > -v /tmp/test-root-crontabs/root:/var/spool/cron/crontabs/root:ro \ > -v $PWD/busybox:/bin/crond \ > busybox:1.37.0-uclibc \ > crond -f -d 0 > > * Verified crond still exits cleanly and runs scheduled jobs normally. > > Binary size impact (gcc 13.3.0, x86-64, `-Os`, static): +17 bytes. > > Thanks for your time and for maintaining BusyBox! > > Regards, > Valentin Lab > _______________________________________________ > busybox mailing list > busybox@busybox.net > https://lists.busybox.net/mailman/listinfo/busybox _______________________________________________ busybox mailing list busybox@busybox.net https://lists.busybox.net/mailman/listinfo/busybox