On Sat, Feb 24, 2024 at 02:11:25PM +0900, Koichi Murase wrote: > I have a question. Maybe it's not technically a bug as fd > 9 is > involved, but the resulting behavior appears to be strange. I > received some reports from users in my project and tried to find out > what is happening. This is a reduced case:
Thank you for bringing this up; I have also noticed weird behaviour with redirections of cloexec file descriptors a couple months ago. Bash seems to check for the CLOEXEC flag in the source file descriptor, and preserves it in the destination file descriptor when performing a n<&m redirection. $ bash -c 'enable fdflags; exec 6</dev/null; fdflags -s+cloexec,nonblock 6; exec 7<&6; fdflags 6 7' 6:cloexec 7:cloexec That is very surprising; I would expect 7 to not be cloexec since CLOEXEC is a file descriptor flag; that is the behaviour you normally get when you if you duplicate 7 before applying CLOEXEC to 7: $ bash -c 'enable fdflags; exec 6</dev/null 7<&6; fdflags -s+cloexec 6; fdflags 6 7' 6:cloexec 7: With strace you can see bash checking if 6 has the CLOEXEC flag, and applying it to 7 manually after duping it: $ strace -qqefd=6,7 bash -c 'enable fdflags; exec 6</dev/null; fdflags -s+cloexec 6; exec 7<&6' fcntl(6, F_GETFD) = -1 EBADF (Bad file descriptor) dup2(3, 6) = 6 fcntl(6, F_GETFD) = 0 fcntl(6, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE) fcntl(6, F_SETFD, FD_CLOEXEC) = 0 fcntl(7, F_GETFD) = -1 EBADF (Bad file descriptor) dup2(6, 7) = 7 fcntl(6, F_GETFD) = 0x1 (flags FD_CLOEXEC) fcntl(7, F_SETFD, FD_CLOEXEC) = 0 This is very confusing/annoying because I would expect to be able to do something like this: #!/bin/bash -- enable fdflags exec {fifofd}< fifo fdflags -s +cloexec "$fifofd" # ... cmd /dev/fd/3 3<&"$fifofd" # ... To only make cmd inherit $fifofd, but I cannot do that because bash will copy CLOEXEC from $fifofd, and fd 3 will be closed for cmd: $ bash -c 'enable fdflags; exec 6</dev/null; fdflags -s+cloexec 6; ls -ld /proc/self/fd/3 3<&6' ls: cannot access '/proc/self/fd/3': No such file or directory So I have to use something like: ( fdflag -s-cloexec "$fifofd" cmd /dev/fd/3 3<&"$fifofd" ) This only happens whe redirecting to an fd >= 3. I don't know why bash wants/needs to copy the CLOEXEC flag when the user duplicates a file descriptor. o/ emanuele6