svn commit: r216826 - in head: bin/sh tools/regression/bin/sh/expansion

Jilles Tjoelker jilles at FreeBSD.org
Thu Dec 30 22:33:55 UTC 2010


Author: jilles
Date: Thu Dec 30 22:33:55 2010
New Revision: 216826
URL: http://svn.freebsd.org/changeset/base/216826

Log:
  sh: Avoid side effects from builtins in optimized command substitution.
  
  Change the criterion for builtins to be safe to execute in the same process
  in optimized command substitution from a blacklist of only cd, . and eval to
  a whitelist.
  
  This avoids clobbering the main shell environment such as by $(exit 4) and
  $(set -x).
  
  The builtins jobid, jobs, times and trap can still show information not
  available in a child process; this is deliberately permitted. (Changing
  traps is not.)
  
  For some builtins, whether they are safe depends on the arguments passed to
  them. Some of these are always considered unsafe to keep things simple; this
  only harms efficiency a little in the rare case they are used alone in a
  command substitution.

Added:
  head/tools/regression/bin/sh/expansion/cmdsubst10.0   (contents, props changed)
Modified:
  head/bin/sh/eval.c

Modified: head/bin/sh/eval.c
==============================================================================
--- head/bin/sh/eval.c	Thu Dec 30 21:32:35 2010	(r216825)
+++ head/bin/sh/eval.c	Thu Dec 30 22:33:55 2010	(r216826)
@@ -643,7 +643,31 @@ out:
 		result->fd, result->buf, result->nleft, result->jp));
 }
 
-
+/*
+ * Check if a builtin can safely be executed in the same process,
+ * even though it should be in a subshell (command substitution).
+ * Note that jobid, jobs, times and trap can show information not
+ * available in a child process; this is deliberate.
+ * The arguments should already have been expanded.
+ */
+static int
+safe_builtin(int idx, int argc, char **argv)
+{
+	if (idx == BLTINCMD || idx == COMMANDCMD || idx == ECHOCMD ||
+	    idx == FALSECMD || idx == JOBIDCMD || idx == JOBSCMD ||
+	    idx == KILLCMD || idx == PRINTFCMD || idx == PWDCMD ||
+	    idx == TESTCMD || idx == TIMESCMD || idx == TRUECMD ||
+	    idx == TYPECMD)
+		return (1);
+	if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
+	    idx == UMASKCMD)
+		return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
+	if (idx == SETCMD)
+		return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
+		    argv[1][0] == '+') && argv[1][1] == 'o' &&
+		    argv[1][2] == '\0'));
+	return (0);
+}
 
 /*
  * Execute a simple command.
@@ -861,10 +885,8 @@ evalcommand(union node *cmd, int flags, 
 	 || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
 	    && ((flags & EV_EXIT) == 0 || have_traps()))
 	 || ((flags & EV_BACKCMD) != 0
-	    && (cmdentry.cmdtype != CMDBUILTIN
-		 || cmdentry.u.index == CDCMD
-		 || cmdentry.u.index == DOTCMD
-		 || cmdentry.u.index == EVALCMD))) {
+	    && (cmdentry.cmdtype != CMDBUILTIN ||
+		 !safe_builtin(cmdentry.u.index, argc, argv)))) {
 		jp = makejob(cmd, 1);
 		mode = cmd->ncmd.backgnd;
 		if (flags & EV_BACKCMD) {

Added: head/tools/regression/bin/sh/expansion/cmdsubst10.0
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/bin/sh/expansion/cmdsubst10.0	Thu Dec 30 22:33:55 2010	(r216826)
@@ -0,0 +1,51 @@
+# $FreeBSD$
+
+a1=$(alias)
+: $(alias testalias=abcd)
+a2=$(alias)
+[ "$a1" = "$a2" ] || echo Error at line $LINENO
+
+alias testalias2=abcd
+a1=$(alias)
+: $(unalias testalias2)
+a2=$(alias)
+[ "$a1" = "$a2" ] || echo Error at line $LINENO
+
+[ "$(command -V pwd)" = "$(command -V pwd; exit $?)" ] || echo Error at line $LINENO
+
+v=1
+: $(export v=2)
+[ "$v" = 1 ] || echo Error at line $LINENO
+
+rotest=1
+: $(readonly rotest=2)
+[ "$rotest" = 1 ] || echo Error at line $LINENO
+
+set +u
+: $(set -u)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+set +u
+: $(set -o nounset)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+set +u
+: $(command set -u)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+umask 77
+u1=$(umask)
+: $(umask 022)
+u2=$(umask)
+[ "$u1" = "$u2" ] || echo Error at line $LINENO
+
+dummy=$(exit 3); [ $? -eq 3 ] || echo Error at line $LINENO


More information about the svn-src-all mailing list