From 324a1f80a8a90cb4d087c8056241cf5649dde5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 12 Jan 2021 09:30:27 +0100 Subject: [PATCH] reaper: remove child from list *before* calling the user provided callback The user provided callback may call reaper_del(), in which case we will crash when we also try to remove the child from the list. Remove it from the list before the callback means reaper_del() (if called by the callback) will just loop through the entire list without finding the pid and thus do nothing. --- reaper.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/reaper.c b/reaper.c index 15e08539..9d98854e 100644 --- a/reaper.c +++ b/reaper.c @@ -138,23 +138,27 @@ fdm_reap(struct fdm *fdm, int fd, int events, void *data) } tll_foreach(reaper->children, it) { - struct child *child = &it->item; - pid_t pid = child->pid; + struct child *_child = &it->item; - if (pid != (pid_t)info.ssi_pid) + if (_child->pid != (pid_t)info.ssi_pid) continue; + /* Make sure we remove it *before* the callback, since it too + * may remove it */ + struct child child = it->item; + tll_remove(reaper->children, it); + bool reap_ourselves = true; - if (child->cb != NULL) - reap_ourselves = !child->cb(reaper, pid, child->cb_data); + if (child.cb != NULL) + reap_ourselves = !child.cb(reaper, child.pid, child.cb_data); if (reap_ourselves) { int result; - int res = waitpid(pid, &result, WNOHANG); + int res = waitpid(child.pid, &result, WNOHANG); if (res <= 0) { if (res < 0) - LOG_ERRNO("waitpid failed for pid=%d", pid); + LOG_ERRNO("waitpid failed for pid=%d", child.pid); continue; } @@ -165,8 +169,6 @@ fdm_reap(struct fdm *fdm, int fd, int events, void *data) else LOG_DBG("pid=%d: died of unknown resason", pid); } - - tll_remove(reaper->children, it); } if (hup)