bug-bash
[Top][All Lists]
Advanced

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

Re: declare a="$b" if $a previously set as array


From: Stephane Chazelas
Subject: Re: declare a="$b" if $a previously set as array
Date: Sun, 7 Dec 2014 10:36:48 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

2014-12-06 20:19:21 -0500, Chet Ramey:
> On 12/6/14 6:24 PM, Stephane Chazelas wrote:
> > Hiya,
> > 
> > this is potentially dangerous:
> > 
> > If $a was previously used as an array (or hash), then:
> > 
> > declare a=$external_input
> 
> So what you're saying is that blindly using external input can sometimes
> have negative consequences?

In this case, it's not about sanitizing external input, at least
as far as the $external_input variable is concerned.

When a script writer writes:

   declare -l a="$external_input"

he's entitled to expect $a to contain the lower case version of
$external_input whatever $external_input contain.

If $external_input happens to contain "($(echo FOO))", I'd
expect $a to contain "($(echo foo))", not "foo" just because
$external_input happens to follow a specific pattern.

Where the script writer may be to blame is for running "declare"
when that "a" variable was previous declared as an array (though
that could have been done by code he invoked from 3rd party
libraries), or not anticipating that his code would be invoked
in contexts where that "a" variable may have been declared as an
array.

But even then, he can be excused not to imagine that

   declare -l a="$external_input"

could ever run an arbitrary commands.

And even if he intended to declare "a" as an array beforehand,
he could reasonably expect

   declare -l a="$external_input"

to do the same as

   declare -l a; a="$external_input"

That is, the same as a[0]="$external_input".

I'd say we have at least a documentation issue.

[...]
> At some point, you have to put some burden of responsibility onto the
> script writer.

Yes, definitely.

It's up to everyone to try and make this digital world a
safer place. In this case though, bash can easily do its bit by
changing this behaviour (I can't imagine anyone relying on the
behaviour as it is now).

> > 
> > If not changed, that behaviour may be worth documented.
> 
> declare's behavior is already documented:
> 
> "Arrays   are  assigned  to  using  compound  assignments  of  the  form
> name=(value1 ... valuen),  where  each  value  is  of  the  form
> [subscript]=string." ... "This  syntax is also accepted by the declare
> builtin."

a=$external_input

is not of the form name=(value ... valuen), it's of the form
var=$other_var.

And when doing it without "declare", it works as expected.

The problem is when using "declare"

Similarly,

a="(foo)"

Assigns "(foo)" to the element of indice 0 in the array "a" and
one could expect:

   declare a="(foo)"

to do the same.

> 
> 
> > ksh behaviour that only accepts "(" when litteral and unquoted
> > (or zsh that doesn't accept it at all) is a bit saner IMO.
> 
> declare is a builtin, not a reserved word.  At the point when it is
> invoked, its arguments have already been expanded.  The question is
> how much argument-mangling you want to do, and how much is worth it.

It's already parsed differently from other builtins.

declare a=(foo bar)

works

echo a=(foo bar)

doesn't (and declare a=$b doesn't do word splitting on $b for
instance)

$ b='[0]=foo' bash -c 'declare a=($b); echo $a'
[0]=foo

does already the right thing (remember you fixed that after I
reported the bug a few years ago). I argue it's a similar issue
here.


[...]
> > $ b='($(uname))' bash -c 'declare -a a; declare a="$b"; printf "<%s>\n" 
> > "$a" "${a[0]}"'
> > <>
> > <Linux>
> > $ b='($(uname))' bash -c 'a=(); declare a=$b; printf "<%s>\n" "$a" 
> > "${a[0]}"'
> > <Linux>
> > <Linux>
> > 
> > (I'd expect the same result for both).
> 
> You don't say what version of bash you're using, but I get the same results
> for both commands back to bash-4.0 (when I quit testing).

~$ bash --version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
~$ b='($(uname))' bash --norc -c 'declare -a a; declare a="$b"; printf "<%s>\n" 
"$a" "${a[0]}"'
<>
<Linux>

(on Linux Mint amd64).

> > It may be worth recommending people do a "unset var" before
> > doing a "declare [-<option>] var" unless they do intend to retain the
> > previous value and/or type 
> 
> Sure, that's good programming practice.  It should be recommended in a
> bash programming guide -- and there are several excellent ones.
[...]

At least the bash doc could document what happens when using
"declare" on a variable that was already assigned or declared
(in the current context and not).

-- 
Stephane



reply via email to

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