[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bash leaks the old var when using =~ in a function with local BASH_REMAT
From: |
Emanuele Torre |
Subject: |
bash leaks the old var when using =~ in a function with local BASH_REMATCH |
Date: |
Sat, 28 May 2022 22:08:19 +0200 |
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=x86-64 -mtune=generic -O2 -pipe -fno-plt
-DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/bin'
-DSTANDARD_UTILS_PATH='/usr/bin' -DSYS_BASHRC='/etc/bash.bashrc'
-DSYS_BASH_LOGOUT='/etc/bash.bash_logout'
-DNON_INTERACTIVE_LOGIN_SHELLS
uname output: Linux t420 5.15.41-1-lts #1 SMP Wed, 18 May 2022
13:37:06 +0000 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu
Bash Version: 5.1
Patch Level: 16
Release Status: release
Description:
If `[[ $str =~ $re ]]' is executed from a function in which
`BASH_REMATCH' is local, bash will "leak" the old *global*
`BASH_REMATCH' variable.
This happens because in `sh_regmatch()', bash calls these two
functions:
unbind_variable_noref ("BASH_REMATCH");
rematch = make_new_array_variable ("BASH_REMATCH");
`unbind_variable_noref()' will unbind and `free()' the first
variable it can find named "BASH_REMATCH" (giving priority to
local variables).
While "BASH_REMATCH" will add a new variable named
"BASH_REMATCH" to the global variables.
Since the old BASH_REMATCH variable was not removed, the old
variable will not be readable until the new one is removed
(using `unset -v BASH_REMATCH').
Repeat-By:
bash-5.1$ x=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bash-5.1$ a () [[ $x =~ .* ]]
bash-5.1$ (ulimit -v 5000; for ((i=0;i<8000;++i)); do a; done)
bash-5.1$ a () { local BASH_REMATCH; [[ $x =~ .* ]] ;}
bash-5.1$ (ulimit -v 5000; for ((i=0;i<8000;++i)); do a; done)
bash: xmalloc: cannot allocate 32 bytes
bash-5.1$ a () { local BASH_REMATCH; [[ $1 =~ .* ]] ;}
bash-5.1$ declare -p BASH_REMATCH
bash: declare: BASH_REMATCH: not found
bash-5.1$ a abc; declare -p BASH_REMATCH
declare -a BASH_REMATCH=([0]="abc")
bash-5.1$ a xyz; declare -p BASH_REMATCH
declare -a BASH_REMATCH=([0]="xyz")
bash-5.1$ a hello; declare -p BASH_REMATCH
declare -a BASH_REMATCH=([0]="hello")
bash-5.1$ unset -v BASH_REMATCH; declare -p BASH_REMATCH
declare -a BASH_REMATCH=([0]="xyz")
bash-5.1$ unset -v BASH_REMATCH; declare -p BASH_REMATCH
declare -a BASH_REMATCH=([0]="abc")
bash-5.1$ unset -v BASH_REMATCH; declare -p BASH_REMATCH
bash: declare: BASH_REMATCH: not found
This also occurs on the devel branch.
Fix:
The obvious fix is to use, instead of `unbind_variable_noref()',
a similar function that uses `global_variables' instead of
`shell_variables'.
That will remove the "variable leak", but it is still not great:
declaring a local `BASH_REMATCH' makes it impossible to access
the matches of `[[ $str =~ $re ]]' because bash will set the
global `BASH_REMATCH' instead of the local one, and
`"${BASH_REMATCH[@]}"' will expand to local `BASH_REMATCH'.
I think allowing `BASH_REMATCH' to be local-ised should be
considered: it would be nice. (Also, it's a little confusing
that `MAPFILE', `REPLY', `COPROC', etc. can be localised, but
`BASH_REMATCH' cannot.)
bash will currently (once the unbind part is fixed) try to
remove the global `BASH_REMATCH' and replace it with a brand new
array variable that contains the matches.
It could instead replace the local `BASH_REMATCH' variable with
a new local array variable (if a local `BASH_REMATCH' variable
of any type was present.)
I am not sure if bash has any specific reason to use this
technique instead of just using `find_or_make_array_variable()'
like other features in bash that use arrays do.
I think bash could just make `[[ $str =~ $re ]]' use
`find_or_make_array_variable()' like other bash features that
use arrays do; If the variable that already exists has
incompatible attributes (i.e. -A and -r) it could just print an
error message (while still returning 0/1 depending on the result
of the match, BASH_REMATCH not being settable should not
influence the exit status of `[[ $str =~ $re ]]'), or simply not
set BASH_REMATCH silently.
This would also allow to use attributes like -l, -u with
BASH_REMATCH (`declare -l BASH_REMATCH') which may be useful.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- bash leaks the old var when using =~ in a function with local BASH_REMATCH,
Emanuele Torre <=