[git commit] ash: optimize tryexec(): avoid one allocation

Denys Vlasenko vda.linux at googlemail.com
Wed Oct 26 20:29:11 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=65a8b859a9a3f2bb4a62c15ca1f4d01288593734
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

There was a bug in tryexec which bbox had fixed in 2003.
dash had a smaller fix in 2007. Copy it. It is smaller,
although it is also more quirky (requires argv[-1] to exist).

Upstream commit 1:

    Date: Mon, 15 Oct 2007 20:24:28 +0800
    [EXEC] Fixed execing of scripts with no hash-bang

    The function tryexec used the original name instead of the path found through
    PATH search.  This patch fixes that.

    Test case:

        trap 'rm -f $TMP' EXIT
        TMP=$(tempfile -s nosuchthing)

        cat <<- EOF > $TMP
                echo OK
        EOF
        chmod u+x $TMP

        cd /
        PATH=${TMP%/*} ${TMP##*/}

    Old result:

        /bin/sh: Can't open filelgY4Fanosuchthing

    New result:

        OK

Upstream commit 2:

    Date: Sun, 23 Dec 2007 11:02:26 +0800
    [EVAL] Fix bad pointer arithmetic in evalcommand

    dash dies on sparc with a SIGBUS due to an arithmetic error introduced
    with commit 03b4958, this patch fixes it.

    Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>

function                                             old     new   delta
evalcommand                                         1261    1264      +3
dotcmd                                               321     319      -2
tryexec                                              115      64     -51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 3/-53)             Total: -50 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c | 31 +++++++++++--------------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 8bf02e6..133b2d4 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7467,13 +7467,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
 #else
 	execve(cmd, argv, envp);
 #endif
-	if (cmd == (char*) bb_busybox_exec_path) {
-		/* We already visited ENOEXEC branch below, don't do it again */
-//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
-		free(argv);
-		return;
-	}
-	if (errno == ENOEXEC) {
+	if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
 		/* Run "cmd" as a shell script:
 		 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
 		 * "If the execve() function fails with ENOEXEC, the shell
@@ -7490,19 +7484,13 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
 		 * message and exit code 126. For one, this prevents attempts
 		 * to interpret foreign ELF binaries as shell scripts.
 		 */
-		char **ap;
-		char **new;
-
-		for (ap = argv; *ap; ap++)
-			continue;
-		new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
-		new[0] = (char*) "ash";
-		new[1] = cmd;
-		ap = new + 2;
-		while ((*ap++ = *++argv) != NULL)
-			continue;
+		argv[0] = cmd;
 		cmd = (char*) bb_busybox_exec_path;
-		argv = new;
+		/* NB: this is only possible because all callers of shellexec()
+		 * ensure that the argv[-1] slot exists!
+		 */
+		argv--;
+		argv[0] = (char*) "ash";
 		goto repeat;
 	}
 }
@@ -7510,6 +7498,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
 /*
  * Exec a program.  Never returns.  If you change this routine, you may
  * have to change the find_command routine as well.
+ * argv[-1] must exist and be writable! See tryexec() for why.
  */
 static void shellexec(char **, const char *, int) NORETURN;
 static void
@@ -9415,7 +9404,9 @@ evalcommand(union node *cmd, int flags)
 			argc++;
 	}
 
-	argv = nargv = stalloc(sizeof(char *) * (argc + 1));
+	/* Reserve one extra spot at the front for shellexec. */
+	nargv = stalloc(sizeof(char *) * (argc + 2));
+	argv = ++nargv;
 	for (sp = arglist.list; sp; sp = sp->next) {
 		TRACE(("evalcommand arg: %s\n", sp->text));
 		*nargv++ = sp->text;


More information about the busybox-cvs mailing list