ash: Expand here-documents in the current shell environment
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 22 Feb 2020 19:25:03 +0000 (20:25 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 22 Feb 2020 19:29:36 +0000 (20:29 +0100)
Upstream commit:

    Date: Sun, 11 Nov 2007 15:27:00 +0800
    Expand here-documents in the current shell environment

    Previously we always expanded here-documents in a subshell.  This is
    contrary to the POSIX specification and how other shells behave.  What's
    more this slows down many expansions due to the extra fork (however, it
    must be said that it is possible for it speed up certain expansions by
    running it simultaneously with the command on two CPUs).

    This patch move the expansion into the current shell environment.

    Test case:

            unset a
            cat <<- EOF > /dev/null
                    ${a=NOT}
            EOF
            echo ${a}BAD

    Old result:

            BAD

    New result:

            NOTBAD

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-heredoc/heredoc_side_effects.right [new file with mode: 0644]
shell/ash_test/ash-heredoc/heredoc_side_effects.tests [new file with mode: 0755]

index 5fb67c0fa18f316f23ec8643b24e328a05b9c3dc..01346108a49b0dcd6b35f996f950484b364ca2da 100644 (file)
@@ -5444,22 +5444,29 @@ stoppedjobs(void)
  * the pipe without forking.
  */
 /* openhere needs this forward reference */
-static void expandhere(union node *arg, int fd);
+static void expandhere(union node *arg);
 static int
 openhere(union node *redir)
 {
+       char *p;
        int pip[2];
        size_t len = 0;
 
        if (pipe(pip) < 0)
                ash_msg_and_raise_perror("can't create pipe");
-       if (redir->type == NHERE) {
-               len = strlen(redir->nhere.doc->narg.text);
-               if (len <= PIPE_BUF) {
-                       full_write(pip[1], redir->nhere.doc->narg.text, len);
-                       goto out;
-               }
+
+       p = redir->nhere.doc->narg.text;
+       if (redir->type == NXHERE) {
+               expandhere(redir->nhere.doc);
+               p = stackblock();
        }
+
+       len = strlen(p);
+       if (len <= PIPE_BUF) {
+               xwrite(pip[1], p, len);
+               goto out;
+       }
+
        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
                /* child */
                close(pip[0]);
@@ -5468,10 +5475,7 @@ openhere(union node *redir)
                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
                signal(SIGPIPE, SIG_DFL);
-               if (redir->type == NHERE)
-                       full_write(pip[1], redir->nhere.doc->narg.text, len);
-               else /* NXHERE */
-                       expandhere(redir->nhere.doc, pip[1]);
+               xwrite(pip[1], p, len);
                _exit(EXIT_SUCCESS);
        }
  out:
@@ -8016,10 +8020,9 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
  * Expand shell variables and backquotes inside a here document.
  */
 static void
-expandhere(union node *arg, int fd)
+expandhere(union node *arg)
 {
        expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
-       full_write(fd, stackblock(), expdest - (char *)stackblock());
 }
 
 /*
diff --git a/shell/ash_test/ash-heredoc/heredoc_side_effects.right b/shell/ash_test/ash-heredoc/heredoc_side_effects.right
new file mode 100644 (file)
index 0000000..53b2c03
--- /dev/null
@@ -0,0 +1 @@
+NO BUG
diff --git a/shell/ash_test/ash-heredoc/heredoc_side_effects.tests b/shell/ash_test/ash-heredoc/heredoc_side_effects.tests
new file mode 100755 (executable)
index 0000000..3fb622a
--- /dev/null
@@ -0,0 +1,5 @@
+unset a
+cat <<EOF >/dev/null
+${a=NO}
+EOF
+echo $a BUG