bug-bash
[Top][All Lists]
Advanced

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

Some issues with short-circuiting arithmetic operators


From: Dan Douglas
Subject: Some issues with short-circuiting arithmetic operators
Date: Wed, 05 Sep 2012 21:40:44 -0500
User-agent: KMail/4.8.3 (Linux/3.4.6-pf+; KDE/4.8.3; x86_64; ; )

This reorder function is meant to swap values of a two-element array if
unordered. Bash and ksh produce reversed results. mksh and zsh do as expected.

    #!/usr/bin/env bash

    [[ -n ${ZSH_VERSION+_} ]] && emulate ksh

    function reorder {
        (( x[1] < x && (x=x[1], x[1]=$x) ))
        echo "${x[@]}"
    }

    x=(123 456)
    reorder
    x=(456 123)
    reorder

    eval echo '${'{BA,K,Z}SH_VERSION\}
    # vim: ft=sh :

     $ bash ./reorder
    456 123
    123 456
    4.2.37(1)-release
     $ ksh ./reorder
    123 456
    456 123
    Version AJM 93u+ 2012-06-28
     $ mksh ./reorder
    123 456
    123 456
    @(#)MIRBSD KSH R40 2012/09/01
     $ zsh ./reorder
    123 456
    123 456
    5.0.0

The Ksh issue seems to be that an explicit x[0] is needed (it's a slightly
outdated dev build), but I can't figure out why Bash is doing this. No
parameter expansion in the arithmetic does the same:

    function reorder2 {
        _=$x let '(x[1] < x) && (x=x[1], x[1]=_)'
        echo "${x[@]}"
    }

Some variations crash:

    $ bash -c 'function reorder { (( x[1] < x[0] && (x=x[1], x[1]=$x) )); echo 
"${x[@]}"; }; x=(123 456); reorder; x=(456 123); reorder'
    Segmentation fault
    $ bash -c 'function reorder { (( (x > x[1]) && (x=${x[1]}, x[1]=$x) )); 
echo "${x[@]}"; }; x=(123 456); reorder; x=(456 123); reorder'
    123 456
    Segmentation fault

The second issue is that Bash tries to resolve arithmetic variables when
evaluation should never reach them. Some methods of short-circuiting do work,
e.g. to populate an array:

     $ n=0 a=a[n]=n=(n+1)%10,a; ((a)); echo "${a[@]}" # Bash
    0 1 2 3 4 5 6 7 8 9

However, In this case, `a' should be protected by `&&'. The same occurs with
`||' and `x?y:z'.

     $ zsh -c 'emulate ksh; typeset -a a; n=0 a="(a[n]=n++)<7&&a"; ((a)); echo 
"${a[@]:1}"' # max depth == 256
    0 1 2 3 4 5 6 7
     $ ksh -c 'n=0 a="(a[n]=++n)<7&&a[0]"; ((a[0])); echo "${a[@]:1}"'          
            # max depth == 8
    1 2 3 4 5 6 7
     $ bash -c 'n=0 a="(a[n]=++n)<7&&a[0]"; ((a[0])); echo "${a[@]:1}"'         
            # max depth == 1024
    bash: n: expression recursion level exceeded (error token is "n")
     $ bash -c 'n=0 a="(a[n]=n++)<7&&a"; ((a)); echo "${a[@]:1}"'
    bash: (a[n]=n++)<7&&a: expression recursion level exceeded (error token is 
"n++)<7&&a")
    0 1 2 3 4 5 6 7

The last one both gets the right answer and throws an error... weird.

It appears the mksh method is to keep track of which variables have been
visited and error if any are referenced twice, rather than counting the
arithmetic evaluator stack depth, so this isn't possible in that shell.
-- 
Dan Douglas

Attachment: signature.asc
Description: This is a digitally signed message part.


reply via email to

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