Package: zsh
Version: 5.0.8-3
Severity: normal

Hi,

zsh 5.0.8 segfaults on the

while [[ -n "$1" ]]; do

line in the attached script; zsh 5.0.7 (and before) was fine.

gdb backtrace:

#0  __strlen_sse2_bsf () at ../sysdeps/i386/i686/multiarch/strlen-sse2-bsf.S:50
#1  0x080bc801 in taddstr (s=0x1f09d4a3 <error: Cannot access memory at address 
0x1f09d4a3>) at ../../Src/text.c:115
#2  0x080bc952 in taddlist (state=state@entry=0xffffcbf0, num=30, num@entry=57) 
at ../../Src/text.c:141
#3  0x080bdc58 in taddlist (num=57, state=0xffffcbf0) at ../../Src/text.c:637
#4  gettext2 (state=state@entry=0xffffcbf0) at ../../Src/text.c:472
#5  0x080bdfdf in getjobtext (prog=0xf7fd6b98, c=0xf7fd6cb8) at 
../../Src/text.c:230
#6  0x0806bdcd in execpline2 (state=state@entry=0xffffce70, 
pcode=pcode@entry=1411, how=how@entry=18, input=0, output=0, last1=0) at 
../../Src/exec.c:1710
#7  0x0806c0f6 in execpline (state=state@entry=0xffffce70, slcode=<optimized 
out>, how=how@entry=18, last1=0) at ../../Src/exec.c:1500
#8  0x0806d23d in execlist (state=0xffffce70, dont_change_job=0, exiting=0) at 
../../Src/exec.c:1276
#9  0x0806d4d4 in execode (p=0xf7fd6b98, dont_change_job=0, exiting=0, 
context=0x80cca55 "toplevel") at ../../Src/exec.c:1074
#10 0x0807ee41 in loop (toplevel=1, justonce=0) at ../../Src/init.c:207
#11 0x08081dbe in zsh_main (argc=2, argv=0xffffd024) at ../../Src/init.c:1674
#12 0x0805497b in main (argc=2, argv=0xffffd024) at ../../Src/main.c:93

Andras

Versions of packages zsh depends on:
ii  dpkg        1.18.0
ii  libc6       2.19-18
ii  libcap2     1:2.24-8
ii  libtinfo5   5.9+20150516-1
ii  zsh-common  5.0.7-6

Versions of packages zsh recommends:
ii  libncursesw5  5.9+20150516-1
ii  libpcre3      2:8.35-3.3

Versions of packages zsh suggests:
pn  zsh-doc  <none>

-- no debconf information
#!/bin/zsh
#
# This script is intended to wrap start-stop-daemon. It will call the
# original start-stop-daemon with the supplied arguments unless the daemon
# to be started appears to exist as a runit service, in which case it will
# map the start-stop-daemon call to an sv(8) call.
#

# If called by non-root user, fall back to original start-stop-daemon
# unconditionally
[[ $UID -gt 0 ]] && exec /sbin/start-stop-daemon.real $@

set -A args $@

SVDIR=${SVDIR:-/etc/service}

unset mode signal exec timeout startas testmode oknodo quiet verbose command 
svstat
oknodo=0
quiet=0

while [[ -n "$1" ]]; do
        case "$1" in
                -S|--start)
                        mode=start
                        ;;
                -K|--stop)
                        mode=stop
                        ;;
                -T|--status)
                        mode=status
                        ;;
                -H|--help|-V|--version)
                        exec /sbin/start-stop-daemon.real $args
                        ;;
                -x|--exec)
                        shift
                        exec="$1"
                        ;;
                -s|--signal)
                        shift
                        signal=$1
                        ;;
                --signal=*)
                        signal="${1/--signal=/}"
                        ;;
                -R|--retry)
                        shift
                        timeout="$1"
                        ;;
                --retry=*)
                        timeout="${1/--retry=/}"
                        ;;
                -a|--startas)
                        shift
                        startas="$1"
                        ;;
                -t|--test)
                        testmode=1
                        ;;
                -o|--oknodo)
                        oknodo=1
                        ;;
                -q|--quiet)
                        quiet=1
                        exec >/dev/null
                        ;;
                -v|--verbose)
                        verbose=1
                        ;;
                
-p|--pidfile|-n|--name|-u|--user|-g|--group|-r|--chroot|-d|--chdir|-N|--nicelevel|-P|--procsched|-I|--iosched|-k|--umask|-m|--make-pidfile)
                        # ignored
                        shift
                        ;;
                
--pidfile=*|-b|--background|--nicelevel=*|--procsched=*|--iosched=*|--umask=*)
                        ;;
                --)
                        # What follows is args to the daemon. Avoid parsing
                        # those accidentally.
                        break
                        ;;
                *)
                        # Assume the previous was the last option; the rest
                        # is the name of the daemon plus args, of which we
                        # only care about the daemon.
                        command=$1
                        break
                        ;;
        esac
        shift
done

# returns success if $1 appears to be the name of a runit service
function issvname() {
        if [[ -d "$SVDIR/$1/supervise/." ]]; then
                return 0
        # 'supervise' could still be a symlink to a directory that doesn't 
exist yet
        elif [[ -L $SVDIR/$1/supervise ]] && ! [[ -e $SVDIR/$1/supervise ]]; 
then
                return 0
        else
                return 1
        fi
}

# TODO: decide what to do if the runit service we're supposed to manage
# doesn't exist in the current svdir but does in other "runlevels"

# Try to infer runit service name. If our parent is an initscript, use its
# basename
foundsvname=0
read -A cmdline </proc/$PPID/cmdline
while [[ -n "$cmdline[1]" ]]; do
        if [[ "${cmdline[1]:h}" = /etc/init.d ]]; then
                svname=${cmdline[1]:t}
                break
        fi
        shift cmdline
done
if [[ -z "$svname" ]] && [[ "${$(readlink -f /proc/$PPID/exe):h}" = /etc/init.d 
]]; then
        read svname < /proc/$PPID/comm
fi

issvname $svname && foundsvname=1

# if not, try other heuristics
if [[ $foundsvname = 0 ]]; then
        svnames=($startas $exec $command)
        while [[ -n "$svnames[1]" ]]; do
                if issvname ${svnames[1]:t}; then
                        svname=${svnames[1]:t}
                        foundsvname=1
                        break
                else
                        shift svnames
                fi
        done
fi

# if still not found, call real start-stop-daemon
if [[ "$foundsvname" = 0 ]]; then
        exec /sbin/start-stop-daemon.real $args
fi

# otherwise, do what we've been asked to
[[ "$quiet" = "0" ]] && [[ "$verbose" = "1" ]] && echo 
"start-stop-daemon.runit: will act on $svname service." >&2

function sendsig() {
        case "$signal" in
                HUP|1)
                        sv hup $svname
                        ;;
                INT|2)
                        sv interrupt $svname
                        ;;
                QUIT|3)
                        sv quit $svname
                        ;;
                KILL|9)
                        sv d $svname
                        sv kill $svname
                        ;;
                USR1|10)
                        sv 1 $svname
                        ;;
                USR2|12)
                        sv 2 $svname
                        ;;
                ALRM|14)
                        sv alarm $svname
                        ;;
                TERM|15)
                        sv down $svname
                        ;;
                CONT|18)
                        sv cont $svname
                        ;;
                STOP|19)
                        sv pause $svname
                        ;;
                *)
                        echo "$0: ERROR: don't know how to send $signal signal 
to $svname." >&2
                        exit 3
                        ;;
        esac
}

function wait_until_exited() {
        counter=0
        read svstat < $SVDIR/$svname/supervise/stat
        while ! [[ "$svstat" = down ]]; do
                ((counter++))
                [[ $counter -gt $timeout ]] && return 1
                sleep 1
                read svstat < $SVDIR/$svname/supervise/stat
        done
        return 0
}

function do_stop() {
        if [[ $timeout =~ / ]]; then
# handle complex schedule
                OLDIFS="$IFS"
                IFS=/
                echo $timeout | read -A schedule
                IFS="$OLDIFS"
                while [[ -n "$schedule[1]" ]]; do
                        signal=$schedule[1]
                        sendsig
                        shift schedule
                        timeout=$schedule[1]
                        wait_until_exited && exit 0
                        shift schedule
                done
                exit 2
        else
# simple timeout
                if [[ -z "$signal" ]]; then
                        if [[ $timeout =~ ^[0-9]+$ ]]; then
                                export SVWAIT=$timeout
                        fi
                        if sv stop $svname; then
                                exit 0
                        else
                                exit 1
                        fi
                else
                        sendsig
                        [[ -n "$timeout" ]] && if wait_until_exited; then
                                exit 0
                        else
                                exit 1
                        fi
                fi
        fi
}

if [[ -r $SVDIR/$svname/supervise/stat ]]; then
        read svstat < $SVDIR/$svname/supervise/stat
else
        # runsv is not yet up
        svstat=none
fi
case "$mode" in
        start)
                [[ "$svstat" = run ]] && [[ "$oknodo" = "0" ]] && exit 1 # 
Emulate start-stop-daemon semantics
                [[ -z "$testmode" ]] && ! [[ "$svstat" = "none" ]] && sv start 
$svname
                exit 0
                ;;
        stop)
                [[ "$svstat" = none ]] && exit 0
                [[ "$svstat" = down ]] && [[ "$oknodo" = "1" ]] && exit 1 # 
Emulate start-stop-daemon semantics
                [[ -z "$testmode" ]] && do_stop # handles --retry and --signal, 
therefore separate function
                
                ;;
        status)
                case "$svstat" in
# States are complex; we only handle the most basic cases here and bail on
# the rest (e.g. "finish" cannot be correctly reported as "running" or "not
# running")
                        run)
                                exit 0
                                ;;
                        down|none)
                                exit 3
                                ;;
                        *)
                                exit 4
                                ;;
                esac
                ;;
esac
exit 0

Reply via email to