[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: unset does not act as expected on namerefs
From: |
Greg Wooledge |
Subject: |
Re: unset does not act as expected on namerefs |
Date: |
Wed, 27 May 2015 08:25:36 -0400 |
User-agent: |
Mutt/1.4.2.3i |
On Tue, May 26, 2015 at 05:02:43PM -0400, Shawn Wilson wrote:
> If there's no good reason to keep this as is (some use case where
> this might be wanted and breaking backward compatibility - I can't
> see anyone actually *wanting* it this way) shouldn't it be changed?
> A behavior can be documented and still be bad.
Well, there are multiple aspects to this issue.
The first is that "declare -n" is very new (only since bash 4.2), so
most script writers either aren't aware of it yet, or haven't had
much chance to use it. It's hard to have a good understanding of
how to use something properly without some experience.
The second is that bash's "declare -n" is, in its current implementation,
not robust enough for general use. It has two major issues, which I've
documented on my wiki, which I'll summarize here:
1) It doesn't cross scopes. It's not like Tcl's upvar at all. It
only refers to a variable in the same scope (which, following the
standard bash rules, means it'll recursively search upward until
it finds a matching variable by name). What this means is that
while you might EXPECT this to work:
f() {
declare -n foo="$1"
foo=set_by_f
}
It won't work in the general case. Demonstration:
imadev:~$ f() { declare -n foo="$1"; }
imadev:~$ g() { declare -n foo="$1"; f foo; }
imadev:~$ foo=bar
imadev:~$ g foo
bash: warning: foo: circular name reference
So, you can't use it to pass variable names from a caller to
a function. You STILL have namespace collisions.
2) It allows arbitrary code execution, just like eval:
imadev:~$ f() { declare -n foo="$1"; echo "$foo"; }
imadev:~$ f 'x[i=0$(date >&2)]'
Wed May 27 08:07:35 EDT 2015
Though, one might argue that this is more of an issue with bash's
indexed arrays than with eval or declare -n. Even printf -v isn't
safe against this.
(See also http://mywiki.wooledge.org/BashFAQ/048)
The third aspect to consider about "unset nameref" is whether the script
writer's intent was to unset the nameref itself, or the variable pointed
to by the nameref.
foo=bar
unset foo
Given those two lines of code, with no context, we might expect that
the word "bar" is no longer held in memory anywhere (or is held in a
chunk of memory that's free to be overwritten at any time). If foo
is a regular variable, this is the case. If foo is a nameref to
another variable, then it's STILL true:
imadev:~$ declare -n foo=somevariable
imadev:~$ foo=bar
imadev:~$ unset foo
imadev:~$ declare -p foo somevariable
declare -n foo="somevariable"
bash: declare: somevariable: not found
This leaves the nameref intact, so you can assign a new "somevariable"
through it. Wiping and re-assigning the pointed-to variable might be
what someone wants.
Here's another surprise, that I didn't know until now. Given the above,
if we follow it up with another declaration of foo, it "hides" the
nameref. But the nameref declaration is still there, lurking, waiting.
imadev:~$ declare -A foo
imadev:~$ foo["jug"]="brown"
imadev:~$ declare -p foo somevariable
declare -A foo='([jug]="brown" )'
bash: declare: somevariable: not found
imadev:~$ unset foo
imadev:~$ declare -p foo somevariable
declare -n foo="somevariable"
bash: declare: somevariable: not found
Is that what Chet intended? I have no idea. (I was actually expecting
"declare -A foo" to create an associative array named somevariable,
with foo still pointing to it.)
- unset does not act as expected on namerefs, Shawn Wilson, 2015/05/26
- Re: unset does not act as expected on namerefs, Greg Wooledge, 2015/05/26
- Re: unset does not act as expected on namerefs, Shawn Wilson, 2015/05/26
- Re: unset does not act as expected on namerefs, Geir Hauge, 2015/05/26
- Re: unset does not act as expected on namerefs, Eduardo A . Bustamante López, 2015/05/26
- Re: unset does not act as expected on namerefs, Geir Hauge, 2015/05/26
- Re: unset does not act as expected on namerefs, Shawn Wilson, 2015/05/26
- Re: unset does not act as expected on namerefs,
Greg Wooledge <=
- Re: unset does not act as expected on namerefs, Chet Ramey, 2015/05/29
- Re: unset does not act as expected on namerefs, Chet Ramey, 2015/05/27
Re: unset does not act as expected on namerefs, Chet Ramey, 2015/05/27