svn commit: r273700 - in head/bin/sh: . tests/builtins

Jilles Tjoelker jilles at FreeBSD.org
Sun Oct 26 17:50:35 UTC 2014


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 <optstring> <var> <arg...>, changes could lead to invalid
  memory access.
  
  In the syntax getopts <optstring> <var> <arg...>, 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:?:


More information about the svn-src-all mailing list