vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit 2cb012c7135e71b528273571b699c41f56c97c02
parent c44bc99119076713a766d71d57f731148af1a6a9
Author: Florian Fischer <florian.fischer@muhq.space>
Date:   Sat, 18 Nov 2023 11:26:24 +0100

destroy the correct subprocess

When a new subprocess is created during an EXIT event of
another subprocess new_process_in_pool will update the
process_pool pointer. Since we use a pointer to a pointer
for iterating all processes during vis_process_tick its
value will be different before executing the event and after
creating the new subprocess. This causes the updated pointer
to be erroneously destroyed and leaves the Process of the
reaped child behind which causes consecutive waitpid calls
to fail with ECHILD.

This is fixed by destroying the proper current subprocess
and updating the iteration pointer accordingly.

Fixes: 13cf3b3a2c239d40f921eca08743e7d44d06b16b

Diffstat:
Mvis-subprocess.c | 14++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/vis-subprocess.c b/vis-subprocess.c @@ -29,11 +29,10 @@ static Process *new_process_in_pool(void) { /** * Removes the subprocess information from the pool, sets invalidator to NULL * and frees resources. - * @param a reference to a reference to the process to be removed + * @param a reference to the process to be removed * @return the next process in the pool */ -static void destroy_process(Process **pointer) { - Process *target = *pointer; +static Process *destroy_process(Process *target) { if (target->outfd != -1) { close(target->outfd); } @@ -47,9 +46,11 @@ static void destroy_process(Process **pointer) { if (target->invalidator) { *(target->invalidator) = NULL; } - *pointer = target->next; + Process *next = target->next; free(target->name); free(target); + + return next; } /** @@ -104,7 +105,7 @@ Process *vis_process_communicate(Vis *vis, const char *name, if (!new->name) { vis_info_show(vis, "Cannot copy process name: %s", strerror(errno)); /* pop top element (which is `new`) from the pool */ - destroy_process(&process_pool); + process_pool = destroy_process(process_pool); goto closeall; } new->outfd = pout[0]; @@ -211,6 +212,7 @@ just_destroy: } else { vis_lua_process_response(vis, current->name, NULL, WEXITSTATUS(status), EXIT); } - destroy_process(pointer); + /* update our iteration pointer */ + *pointer = destroy_process(current); } }