bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Leak in BASH "named" file descriptors?


From: Mathieu Patenaude
Subject: Re: Leak in BASH "named" file descriptors?
Date: Thu, 28 Jan 2016 12:40:57 -0500

Yes, using ":" also illustrate the same (or similar) behavior that I'm experiencing with my script.  Using the "here" string creates the additional weirdness of showing that the temporary file content is actually "deleted", but the bash process keep the FD open.  Which is quite strange since it appears to have done half the job...

Below is another difference with the "here" string construct -  of course this is a very inefficient way to assign a string to a variable!!! ;-)   but just used as a simple example here.

# Start a new shell to make sure there is no old FD left from previous tests
bash

unset -v TESTVAR
9<<<"test data" read -r -u 9 TESTVAR
printf "OUTPUT: $TESTVAR\n"
OUTPUT: test data

FD #9 is not left open or "deleted" here:

lsof -a -d '0-20' -p $$
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash    12084 mathp    0u   CHR  136,4      0t0    7 /dev/pts/4
bash    12084 mathp    1u   CHR  136,4      0t0    7 /dev/pts/4
bash    12084 mathp    2u   CHR  136,4      0t0    7 /dev/pts/4

Now testing with the "named" (if that's a good name to call this) FD:

unset -v TEST_FD TESTVAR
{TEST_FD}<<<"test data" read -r -u $TEST_FD TESTVAR
bash: read: TESTVAR: invalid file descriptor specification

But strangely, the TEST_FD exists and is left in the "deleted" mode:

lsof -a -d '0-20' -p $$
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
bash    12084 mathp    0u   CHR  136,4      0t0       7 /dev/pts/4
bash    12084 mathp    1u   CHR  136,4      0t0       7 /dev/pts/4
bash    12084 mathp    2u   CHR  136,4      0t0       7 /dev/pts/4
bash    12084 mathp   10r   REG    8,1       10 1049150 /tmp/sh-thd-512950288 (deleted)

Looks like the process of dynamically assigning a FD to the FD "variable" breaks the redirection.  But the FD is created and it's value did get assigned to TEST_FD:

echo $TEST_FD
10

and temporary file content deleted, but the FD not un-linked....

Doing the same thing but using 2 steps works, but you're still left with a "deleted" FD:

unset -v TEST_FD TESTVAR
: {TEST_FD}<<<"test data" 
read -r -u $TEST_FD TESTVAR
printf "OUTPUT: $TESTVAR   FD: $TEST_FD\n"
OUTPUT: test data   FD: 11

lsof -a -d '0-20' -p $$
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
bash    12084 mathp    0u   CHR  136,4      0t0       7 /dev/pts/4
bash    12084 mathp    1u   CHR  136,4      0t0       7 /dev/pts/4
bash    12084 mathp    2u   CHR  136,4      0t0       7 /dev/pts/4
bash    12084 mathp   10r   REG    8,1       10 1049150 /tmp/sh-thd-512950288 (deleted)
bash    12084 mathp   11r   REG    8,1       10 1049151 /tmp/sh-thd-263257624 (deleted)


I think that having a common behavior for "named" vs "numbered" FD in bash would be great since obviously using dynamically assigned FD (numbers) offers some advantages when coding more complex scripts.

Also related, assigning the output of the process substitution construct to a "named" FD has the same behavior, i.e. you're left with an un-linked pipe:

unset -v TESTVAR
9< <(ls ~/t) read -r -u 9 TESTVAR
printf "OUTPUT: $TESTVAR\n"
OUTPUT: 0095.out

lsof -a -d '0-20' -p $$
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash    16098 mathp    0u   CHR  136,4      0t0    7 /dev/pts/4
bash    16098 mathp    1u   CHR  136,4      0t0    7 /dev/pts/4
bash    16098 mathp    2u   CHR  136,4      0t0    7 /dev/pts/4

unset -v TEST_FD TESTVAR
: {TEST_FD}< <(ls ~/t)
read -r -u $TEST_FD TESTVAR
printf "OUTPUT: $TESTVAR   FD: $TEST_FD\n"
OUTPUT: 0095.out   FD: 10

lsof -a -d '0-20' -p $$
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
bash    16098 mathp    0u   CHR  136,4      0t0        7 /dev/pts/4
bash    16098 mathp    1u   CHR  136,4      0t0        7 /dev/pts/4
bash    16098 mathp    2u   CHR  136,4      0t0        7 /dev/pts/4
bash    16098 mathp   10r  FIFO    0,8      0t0 96683179 pipe


Thanks!

Math.

On Thu, Jan 28, 2016 at 8:58 AM, Andreas Schwab <schwab@suse.de> wrote:
Greg Wooledge <wooledg@eeg.ccf.org> writes:

> On Wed, Jan 27, 2016 at 01:18:11PM -0500, Mathieu Patenaude wrote:
>> When using "named" file descriptors inside a function, the file descriptors
>> are not automatically un-linked when the function returns, but when using
>> regular "numbered" file descriptors they are automatically "destroyed".
>
> Could not reproduce in an interactive shell, on bash 4.3.30 (Debian).
>
> $ f() { local fd; exec {fd}</dev/null; }
> $ f
> $ g() { exec 9</dev/null; }
> $ g
> $ lsof -p $$
> ...
> bash    931 wooledg    0u   CHR  136,0      0t0       3 /dev/pts/0
> bash    931 wooledg    1u   CHR  136,0      0t0       3 /dev/pts/0
> bash    931 wooledg    2u   CHR  136,0      0t0       3 /dev/pts/0
> bash    931 wooledg    9r   CHR    1,3      0t0    1028 /dev/null
> bash    931 wooledg   10r   CHR    1,3      0t0    1028 /dev/null
> bash    931 wooledg  255u   CHR  136,0      0t0       3 /dev/pts/0
>
> I actually ran the lsof multiple times, in between the calls to f and g.
> FD 10 was opened by f (and kept open), and FD 9 was of course opened by g
> (and kept open).

Try replacing exec with :.  Redirections established with exec are
always permanent.

Andreas.

--
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


reply via email to

[Prev in Thread] Current Thread [Next in Thread]