Re: More fun with IFS

2013-02-24 Thread Thorsten Glaser
Dan Douglas dixit:

>Zsh and pdkshes produce:
>
>one:::two:three:::four
>
>For all of the above, which I think is wrong for the last 4. ksh93 produces:

Why is it incorrect?

The mksh manpage documents $@ behaving like $*:

 @   Same as $*, unless it is used inside double quotes, in which case
 a separate word is generated for each positional parameter. If
 there are no positional parameters, no word is generated. $@ can
 be used to access arguments, verbatim, without losing NULL argu-
 ments or splitting arguments with spaces.

And $* uses the first char of IFS:

 *   All positional parameters (except 0), i.e. $1, $2, $3, ...
 If used outside of double quotes, parameters are separate words
 (which are subjected to word splitting); if used within double
 quotes, parameters are separated by the first character of the
 IFS parameter (or the empty string if IFS is NULL).

POSIX is just as explicit on $* (with better wording for the
two distinguished cases of IFS being unset or empty which the
mksh code implements correctly, though):

   *
  Expands  to  the positional parameters, starting from one.
  When  the  expansion  occurs within a double-quoted string
  (see  [54]Double-Quotes  ),  it  shall  expand to a single
  field  with  the  value of each parameter separated by the
  first  character  of  the IFS variable, or by a  if
  IFS  is unset. If IFS is set to a null string, this is not
  equivalent  to  unsetting it; its first character does not
  exist, so the parameter values are concatenated.

And POSIX on $@ doesn’t specify anything different for when the
result of $@ is used where it isn’t multiple fields:

   @
  Expands  to  the positional parameters, starting from one.
  When  the expansion occurs within double-quotes, and where
  field  splitting  (see [53]Field Splitting ) is performed,
  each  positional  parameter  shall  expand  as  a separate
  field,  with the provision that the expansion of the first
  parameter shall still be joined with the beginning part of
  the  original  word  (assuming that the expanded parameter
  was embedded within a word), and the expansion of the last
  parameter  shall still be joined with the last part of the
  original  word. If there are no positional parameters, the
  expansion of '@' shall generate zero fields, even when '@'
  is double-quoted.

So I think mksh at least behaves as specified, and the standard
doesn’t contradict it. Inside the code, there’s even special-casing
for “ifs0”, so I believe this is no accident.

In other words, “don’t do that then” (rely on this behaviour).
I think eval is evil anyway ;-)

(Thanks to ormaaj for pointing out this posting.)

bye,
//mirabilos
-- 
“It is inappropriate to require that a time represented as
 seconds since the Epoch precisely represent the number of
 seconds between the referenced time and the Epoch.”
-- IEEE Std 1003.1b-1993 (POSIX) Section B.2.2.2




Re: Short list of issues with various expansions and IFS

2013-02-24 Thread Thorsten Glaser
Chet Ramey dixit:

>>  2. IFS side-effects don't take effect during expansion.
>
>Yeah, this is a tough one.  If you want side effects of assignments to IFS
>to affect subsequent expansions, you have to have a way to ensure that the

I think changing IFS during expansion is just asking for trouble.

>pd-ksh derivatives are wrong; the second expansion of ${*} needs to be
>split.

Yeah, sorry about that, we’re good now (CVS HEAD):

mksh:  

bye,
//mirabilos
-- 
„nein: BerliOS und Sourceforge sind Plattformen für Projekte, github ist
eine Plattform für Einzelkämpfer“
-- dieses Zitat ist ein Beweis dafür, daß auch ein blindes Huhn
   mal ein Korn findet, bzw. – in diesem Fall – Recht haben kann




bash crash processing b=b+1 after array read

2013-02-24 Thread phil colbourn
phil@rex:~$ unset a b X; declare -i a b=1; declare -ia X=(1 2 3);
phil@rex:~$ unset a b X; declare -i a b=1; declare -ia X=(1 2 3); (( a=X[b]
)); echo $a
2
phil@rex:~$ cd Development/pc-z80
phil@rex:~/Development/pc-z80$ chmod +x pc-crash-bash.bash
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash2
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
2
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
2
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
3
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
200
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
100
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100
This works: 200
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100
This works: 200
But a 'b=b+1' after an array read crashes bash.
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100
This works: 200
This works: 200
But a 'b=b+1' after an array read crashes bash.
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: 100
This works: 200
This works: 200
But a 'b=b+1' after an array read crashes bash.
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ declare -ia X=({0..1000}); echo ${X[3]}
3
phil@rex:~/Development/pc-z80$ declare -ia X=({0..1000..100}); echo ${X[3]}
300
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: a=-1  b=2
This works: a=-1  b=3
This works: a=300  b=3
This works: a=300  b=4
This works: a=400  b=5
This works: a=500  b=6
This works: a=500  b=8
This works: a=500  b=10
This works: a=0  b=11
This works: a=0  b=12
This works: a=0  b=13
This works: a=0  b=14
But a 'b=b+1' after an array read crashes bash.
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ ./pc-crash-bash.bash
Howto crash bash
This works: a=-1  b=2
This works: a=-1  b=3
This works: a=300  b=3
This works: a=300  b=4
This works: a=400  b=5
This works: a=500  b=6
This works: a=500  b=8
This works: a=500  b=10
This works: a=0  b=11
This works: a=0  b=12
This works: a=0  b=13
This works: a=0  b=14
But a 'b=b+1' after an array read crashes bash.
Segmentation fault (core dumped)
phil@rex:~/Development/pc-z80$ bashbug
Processing '/etc/jupp/editorrc'...done
Processing '/etc/jupp/editorrc'...done













Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64'
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu'
-DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL
-DHAVE_CONFIG_H   -I.  -I../bash -I../bash/include -I../bash/lib
 -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector --param=ssp-buffer-size=4
-Wformat -Werror=format-security -Wall
uname output: Linux rex 3.7.5-030705-generic #201301280206 SMP Mon Jan 28
07:07:29 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu

Bash Version: 4.2
Patch Level: 37
Release Status: release

Description:

Within (( )), 'b=b+1' will crash bash with a segment fault if it follows an
array read such as 'a=X[b]'.

Once, a test line entered into a bash prompt crashed my terminal window as
well.

Repeat-By:
#!/bin/bash printf "Howto crash bash\n" unset a b X declare -i a=-1 b=1
declare -ia X=( {0..1000..100} ) printf "But a 'b=b+1' after an array read
crashes bash.\n" (( a=X[b], b=b+1 )); printf "This crashes: a=%d b=%d\n" $a
$b

Fix:

Don't run a command after an array read

eg.

Do this instead

#!/bin/bash printf "Howto crash bash\n" unset a b X declare -i a=-1 b=1
declare -ia X=( {0..1000..100} ) printf "But a 'b=b+1' after an array read
crashes bash.\n" (( a=X[b] )); (( b=b+1 )); printf "This crashes: a=%d
b=%d\n" $a $b

More detailed script looking at what case crashes bash:

It seems that b+=1 is ok, but b=b+1 is not.


#!/bin/bash
printf "Howto crash bash\n"
unset a b X
declare -i a=-1 b=1
declare -ia X=( {0..1000..100} )
(( b+=1 )); printf "This works: a=%d  b=%d\n" $a $b
(( b=b+1)); printf "This works: a=%d  b=%d\n" $a $b
(( a=X[b]   )); pri