From owner-svn-src-all@FreeBSD.ORG Sun Oct 26 17:50:35 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id A4A34301; Sun, 26 Oct 2014 17:50:35 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 902C9155; Sun, 26 Oct 2014 17:50:35 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s9QHoZV5024233; Sun, 26 Oct 2014 17:50:35 GMT (envelope-from jilles@FreeBSD.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s9QHoYag024224; Sun, 26 Oct 2014 17:50:34 GMT (envelope-from jilles@FreeBSD.org) Message-Id: <201410261750.s9QHoYag024224@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: jilles set sender to jilles@FreeBSD.org using -f From: Jilles Tjoelker Date: Sun, 26 Oct 2014 17:50:34 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r273700 - in head/bin/sh: . tests/builtins X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 26 Oct 2014 17:50:35 -0000 Author: jilles Date: Sun Oct 26 17:50:33 2014 New Revision: 273700 URL: https://svnweb.freebsd.org/changeset/base/273700 Log: sh: Make getopts memory-safe if with changing arguments. POSIX does not permit to continuing a getopts loop with different arguments. For parsing the positional parameters, we handle this case by resetting the getopts state when the positional parameters are changed in any way (and the getopts state is local to a function). However, in the syntax getopts , changes could lead to invalid memory access. In the syntax getopts , store a copy of the arguments and continue to use them until getopts is reset. Added: head/bin/sh/tests/builtins/getopts9.0 (contents, props changed) head/bin/sh/tests/builtins/getopts9.0.stdout (contents, props changed) Modified: head/bin/sh/eval.c head/bin/sh/options.c head/bin/sh/options.h Modified: head/bin/sh/eval.c ============================================================================== --- head/bin/sh/eval.c Sun Oct 26 17:17:08 2014 (r273699) +++ head/bin/sh/eval.c Sun Oct 26 17:50:33 2014 (r273700) @@ -1039,6 +1039,7 @@ evalcommand(union node *cmd, int flags, shellparam.reset = 1; shellparam.nparam = argc - 1; shellparam.p = argv + 1; + shellparam.optp = NULL; shellparam.optnext = NULL; INTOFF; savelocalvars = localvars; Modified: head/bin/sh/options.c ============================================================================== --- head/bin/sh/options.c Sun Oct 26 17:17:08 2014 (r273699) +++ head/bin/sh/options.c Sun Oct 26 17:50:33 2014 (r273700) @@ -325,6 +325,7 @@ setparam(char **argv) shellparam.malloc = 1; shellparam.nparam = nparam; shellparam.p = newparam; + shellparam.optp = NULL; shellparam.reset = 1; shellparam.optnext = NULL; } @@ -344,6 +345,11 @@ freeparam(struct shparam *param) ckfree(*ap); ckfree(param->p); } + if (param->optp) { + for (ap = param->optp ; *ap ; ap++) + ckfree(*ap); + ckfree(param->optp); + } } @@ -417,20 +423,33 @@ getoptsreset(const char *value) int getoptscmd(int argc, char **argv) { - char **optbase = NULL; + char **optbase = NULL, **ap; + int i; if (argc < 3) error("usage: getopts optstring var [arg]"); - else if (argc == 3) - optbase = shellparam.p; - else - optbase = &argv[3]; if (shellparam.reset == 1) { + INTOFF; + if (shellparam.optp) { + for (ap = shellparam.optp ; *ap ; ap++) + ckfree(*ap); + ckfree(shellparam.optp); + shellparam.optp = NULL; + } + if (argc > 3) { + shellparam.optp = ckmalloc((argc - 2) * sizeof *ap); + memset(shellparam.optp, '\0', (argc - 2) * sizeof *ap); + for (i = 0; i < argc - 3; i++) + shellparam.optp[i] = savestr(argv[i + 3]); + } + INTON; + optbase = argc == 3 ? shellparam.p : shellparam.optp; shellparam.optnext = optbase; shellparam.optptr = NULL; shellparam.reset = 0; - } + } else + optbase = shellparam.optp ? shellparam.optp : shellparam.p; return getopts(argv[1], argv[2], optbase, &shellparam.optnext, &shellparam.optptr); Modified: head/bin/sh/options.h ============================================================================== --- head/bin/sh/options.h Sun Oct 26 17:17:08 2014 (r273699) +++ head/bin/sh/options.h Sun Oct 26 17:50:33 2014 (r273700) @@ -38,6 +38,7 @@ struct shparam { unsigned char malloc; /* if parameter list dynamically allocated */ unsigned char reset; /* if getopts has been reset */ char **p; /* parameter list */ + char **optp; /* parameter list for getopts */ char **optnext; /* next parameter to be processed by getopts */ char *optptr; /* used by getopts */ }; Added: head/bin/sh/tests/builtins/getopts9.0 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/bin/sh/tests/builtins/getopts9.0 Sun Oct 26 17:50:33 2014 (r273700) @@ -0,0 +1,9 @@ +# $FreeBSD$ + +args='-ab' +getopts ab opt $args +echo $?:$opt:$OPTARG +for dummy in dummy1 dummy2; do + getopts ab opt $args + echo $?:$opt:$OPTARG +done Added: head/bin/sh/tests/builtins/getopts9.0.stdout ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/bin/sh/tests/builtins/getopts9.0.stdout Sun Oct 26 17:50:33 2014 (r273700) @@ -0,0 +1,3 @@ +0:a: +0:b: +1:?: