Author: jilles
Date: Wed Mar 26 20:43:40 2014
New Revision: 263777
URL: http://svnweb.freebsd.org/changeset/base/263777

Log:
  sh: Fix possible memory leaks and double frees with unexpected SIGINT.

Modified:
  head/bin/sh/alias.c
  head/bin/sh/exec.c
  head/bin/sh/expand.c
  head/bin/sh/redir.c
  head/bin/sh/var.c

Modified: head/bin/sh/alias.c
==============================================================================
--- head/bin/sh/alias.c Wed Mar 26 20:10:07 2014        (r263776)
+++ head/bin/sh/alias.c Wed Mar 26 20:43:40 2014        (r263777)
@@ -180,6 +180,7 @@ printaliases(void)
        int i, j;
        struct alias **sorted, *ap;
 
+       INTOFF;
        sorted = ckmalloc(aliases * sizeof(*sorted));
        j = 0;
        for (i = 0; i < ATABSIZE; i++)
@@ -187,9 +188,13 @@ printaliases(void)
                        if (*ap->name != '\0')
                                sorted[j++] = ap;
        qsort(sorted, aliases, sizeof(*sorted), comparealiases);
-       for (i = 0; i < aliases; i++)
+       for (i = 0; i < aliases; i++) {
                printalias(sorted[i]);
+               if (int_pending())
+                       break;
+       }
        ckfree(sorted);
+       INTON;
 }
 
 int

Modified: head/bin/sh/exec.c
==============================================================================
--- head/bin/sh/exec.c  Wed Mar 26 20:10:07 2014        (r263776)
+++ head/bin/sh/exec.c  Wed Mar 26 20:43:40 2014        (r263777)
@@ -612,6 +612,7 @@ defun(const char *name, union node *func
 
 /*
  * Delete a function if it exists.
+ * Called with interrupts off.
  */
 
 int

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c        Wed Mar 26 20:10:07 2014        (r263776)
+++ head/bin/sh/expand.c        Wed Mar 26 20:43:40 2014        (r263777)
@@ -956,6 +956,7 @@ recordregion(int start, int end, int inq
 {
        struct ifsregion *ifsp;
 
+       INTOFF;
        if (ifslastp == NULL) {
                ifsp = &ifsfirst;
        } else {
@@ -963,6 +964,7 @@ recordregion(int start, int end, int inq
                    && ifslastp->inquotes == inquotes) {
                        /* extend previous area */
                        ifslastp->endoff = end;
+                       INTON;
                        return;
                }
                ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
@@ -973,6 +975,7 @@ recordregion(int start, int end, int inq
        ifslastp->begoff = start;
        ifslastp->endoff = end;
        ifslastp->inquotes = inquotes;
+       INTON;
 }
 
 

Modified: head/bin/sh/redir.c
==============================================================================
--- head/bin/sh/redir.c Wed Mar 26 20:10:07 2014        (r263776)
+++ head/bin/sh/redir.c Wed Mar 26 20:43:40 2014        (r263777)
@@ -92,6 +92,13 @@ static int openhere(union node *);
  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  * standard output, and the standard error if it becomes a duplicate of
  * stdout, is saved in memory.
+*
+ * We suppress interrupts so that we won't leave open file
+ * descriptors around.  Because the signal handler remains
+ * installed and we do not use system call restart, interrupts
+ * will still abort blocking opens such as fifos (they will fail
+ * with EINTR). There is, however, a race condition if an interrupt
+ * arrives after INTOFF and before open blocks.
  */
 
 void
@@ -103,6 +110,7 @@ redirect(union node *redir, int flags)
        int fd;
        char memory[10];        /* file descriptors to write to memory */
 
+       INTOFF;
        for (i = 10 ; --i >= 0 ; )
                memory[i] = 0;
        memory[1] = flags & REDIR_BACKQ;
@@ -139,11 +147,14 @@ redirect(union node *redir, int flags)
                        INTON;
                }
                openredirect(n, memory);
+               INTON;
+               INTOFF;
        }
        if (memory[1])
                out1 = &memout;
        if (memory[2])
                out2 = &memout;
+       INTON;
 }
 
 
@@ -156,15 +167,6 @@ openredirect(union node *redir, char mem
        int f;
        int e;
 
-       /*
-        * We suppress interrupts so that we won't leave open file
-        * descriptors around.  Because the signal handler remains
-        * installed and we do not use system call restart, interrupts
-        * will still abort blocking opens such as fifos (they will fail
-        * with EINTR). There is, however, a race condition if an interrupt
-        * arrives after INTOFF and before open blocks.
-        */
-       INTOFF;
        memory[fd] = 0;
        switch (redir->nfile.type) {
        case NFROM:
@@ -237,7 +239,6 @@ movefd:
        default:
                abort();
        }
-       INTON;
 }
 
 

Modified: head/bin/sh/var.c
==============================================================================
--- head/bin/sh/var.c   Wed Mar 26 20:10:07 2014        (r263776)
+++ head/bin/sh/var.c   Wed Mar 26 20:43:40 2014        (r263777)
@@ -249,6 +249,7 @@ setvar(const char *name, const char *val
                vallen = strlen(val);
                len += vallen;
        }
+       INTOFF;
        nameeq = ckmalloc(len);
        memcpy(nameeq, name, namelen);
        nameeq[namelen] = '=';
@@ -257,6 +258,7 @@ setvar(const char *name, const char *val
        else
                nameeq[namelen + 1] = '\0';
        setvareq(nameeq, flags);
+       INTON;
 }
 
 static int
@@ -289,6 +291,7 @@ change_env(const char *s, int set)
        char *eqp;
        char *ss;
 
+       INTOFF;
        ss = savestr(s);
        if ((eqp = strchr(ss, '=')) != NULL)
                *eqp = '\0';
@@ -297,6 +300,7 @@ change_env(const char *s, int set)
        else
                (void) unsetenv(ss);
        ckfree(ss);
+       INTON;
 
        return;
 }
@@ -359,13 +363,13 @@ setvareq(char *s, int flags)
        /* not found */
        if (flags & VNOSET)
                return;
+       INTOFF;
        vp = ckmalloc(sizeof (*vp));
        vp->flags = flags;
        vp->text = s;
        vp->name_len = nlen;
        vp->next = *vpp;
        vp->func = NULL;
-       INTOFF;
        *vpp = vp;
        if ((vp->flags & VEXPORT) && localevar(s)) {
                change_env(s, 1);
@@ -773,6 +777,7 @@ poplocalvars(void)
        struct localvar *lvp;
        struct var *vp;
 
+       INTOFF;
        while ((lvp = localvars) != NULL) {
                localvars = lvp->next;
                vp = lvp->vp;
@@ -790,6 +795,7 @@ poplocalvars(void)
                }
                ckfree(lvp);
        }
+       INTON;
 }
 
 
@@ -828,18 +834,21 @@ unsetcmd(int argc __unused, char **argv 
        if (flg_func == 0 && flg_var == 0)
                flg_var = 1;
 
+       INTOFF;
        for (ap = argptr; *ap ; ap++) {
                if (flg_func)
                        ret |= unsetfunc(*ap);
                if (flg_var)
                        ret |= unsetvar(*ap);
        }
+       INTON;
        return ret;
 }
 
 
 /*
  * Unset the specified variable.
+ * Called with interrupts off.
  */
 
 int
@@ -853,7 +862,6 @@ unsetvar(const char *s)
                return (0);
        if (vp->flags & VREADONLY)
                return (1);
-       INTOFF;
        if (vp->text[vp->name_len + 1] != '\0')
                setvar(s, nullstr, 0);
        if ((vp->flags & VEXPORT) && localevar(vp->text)) {
@@ -869,7 +877,6 @@ unsetvar(const char *s)
                *vpp = vp->next;
                ckfree(vp);
        }
-       INTON;
        return (0);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to