By "convention" (according to a comment in syscall/exec_linux.go), file descriptors inherited by a go program at startup won't be automatically marked close-on-exec, and therefore (for fd >= 3) will be passed on to children created by syscall.StartProcess, even when not listed in ProcAttr.Files.
On Plan 9, the mechanism for closing unwanted fds is different, but the current implementation takes some pains to replicate this behaviour. A comment in syscall_exec_plan9.go says:
Plan 9 does not allow clearing the OCEXEC flag from the underlying channel backing an open file descriptor, therefore we store a list of already opened file descriptors inside startupFds and skip them when manually closing descriptors not meant to be passed to a child exec.
Is this really necessary? The documentation for StartProcess doesn't seem to promise passing on any open fds except the ones in ProcAttr.Files; and in fact the code which manipulates the explicitly listed fds into the right order doesn't take into account any other inherited ones, which may therefore get closed accidentally anyway.
I ask because I'm looking at re-working StartProcess on Plan 9 along the lines of
https://codereview.appspot.com/57890043 (this abandoned CL was basically sound but went a bit too far). I think the fork/exec code can be simpler and more efficient if we don't need to keep track of extra fds.