]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
In URIs in apropos(1) result tables,
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 6b736bec6d056cc94b60b1a2776570e5d3861b49..268d6470ade19460f23314ccd25ff6a3156c0cbb 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/*     $Id: roff.c,v 1.287 2017/01/10 21:59:47 schwarze Exp $ */
+/*     $Id: roff.c,v 1.293 2017/03/09 15:29:35 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -1223,22 +1223,25 @@ deroff(char **dest, const struct roff_node *n)
                return;
        }
 
-       /* Skip leading whitespace and escape sequences. */
+       /* Skip leading whitespace. */
 
-       cp = n->string;
-       while (*cp != '\0') {
-               if ('\\' == *cp) {
-                       cp++;
-                       mandoc_escape((const char **)&cp, NULL, NULL);
-               } else if (isspace((unsigned char)*cp))
+       for (cp = n->string; *cp != '\0'; cp++) {
+               if (cp[0] == '\\' && cp[1] != '\0' &&
+                   strchr(" %&0^|~", cp[1]) != NULL)
                        cp++;
-               else
+               else if ( ! isspace((unsigned char)*cp))
                        break;
        }
 
+       /* Skip trailing backslash. */
+
+       sz = strlen(cp);
+       if (sz > 0 && cp[sz - 1] == '\\')
+               sz--;
+
        /* Skip trailing whitespace. */
 
-       for (sz = strlen(cp); sz; sz--)
+       for (; sz; sz--)
                if ( ! isspace((unsigned char)cp[sz-1]))
                        break;
 
@@ -1605,7 +1608,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
                        return ROFF_IGN;
                while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
                        pos++;
-               while (buf->buf[pos] != '\0' && buf->buf[pos] == ' ')
+               while (buf->buf[pos] == ' ')
                        pos++;
                return tbl_read(r->tbl, ln, buf->buf, pos);
        }
@@ -3035,7 +3038,7 @@ roff_userdef(ROFF_ARGS)
 {
        const char       *arg[9], *ap;
        char             *cp, *n1, *n2;
-       int               i, ib, ie;
+       int               expand_count, i, ib, ie;
        size_t            asz, rsz;
 
        /*
@@ -3059,8 +3062,9 @@ roff_userdef(ROFF_ARGS)
         */
 
        buf->sz = strlen(r->current_string) + 1;
-       n1 = cp = mandoc_malloc(buf->sz);
+       n1 = n2 = cp = mandoc_malloc(buf->sz);
        memcpy(n1, r->current_string, buf->sz);
+       expand_count = 0;
        while (*cp != '\0') {
 
                /* Scan ahead for the next argument invocation. */
@@ -3079,6 +3083,20 @@ roff_userdef(ROFF_ARGS)
                }
                cp -= 2;
 
+               /*
+                * Prevent infinite recursion.
+                */
+
+               if (cp >= n2)
+                       expand_count = 1;
+               else if (++expand_count > EXPAND_LIMIT) {
+                       mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+                           ln, (int)(cp - n1), NULL);
+                       free(buf->buf);
+                       buf->buf = n1;
+                       return ROFF_IGN;
+               }
+
                /*
                 * Determine the size of the expanded argument,
                 * taking escaping of quotes into account.
@@ -3362,7 +3380,8 @@ roff_strdup(const struct roff *r, const char *p)
        ssz = 0;
 
        while ('\0' != *p) {
-               if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
+               assert((unsigned int)*p < 128);
+               if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) {
                        sz = r->xtab[(int)*p].sz;
                        res = mandoc_realloc(res, ssz + sz + 1);
                        memcpy(res + ssz, r->xtab[(int)*p].p, sz);