gspawn.c may clobber target fds
When working on !1968 (merged), I noticed that gspawn.c's do_exec() and do_posix_spawn() functions have an unfortunate bug:
* If we're doing remapping fd assignments, we need to handle
* the case where the user has specified e.g.:
* 5 -> 4, 4 -> 6
*
* We do this by duping the source fds temporarily in a first pass.
But this isn't right. Consider this counterexample where we map source_fd 5 -> target_fd 7 and also map source_fd 4 -> target_fd 6. Then:
- dup(5) -> get unlucky, dup returns 6
- dup(4) -> dup returns 7
This means our final mapping is 6 -> 7, 7 -> 6. So we will call dup2(6, 7) first, and then we have clobbered fd 7. Then we dup2(7, 6) and lose. Drat. The result is we have remapped 5 -> 7 as expected, but then remapped 5 -> 6 instead of 4 -> 6.
We will need a quadratic loop to check that each value in duped_source_fds is not present in target_fds, and repeatedly dup if it is.
Edited by Michael Catanzaro