=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.286 retrieving revision 1.293 diff -u -p -r1.286 -r1.293 --- mandoc/roff.c 2017/01/10 14:09:07 1.286 +++ mandoc/roff.c 2017/03/09 15:29:35 1.293 @@ -1,7 +1,7 @@ -/* $Id: roff.c,v 1.286 2017/01/10 14:09:07 schwarze Exp $ */ +/* $Id: roff.c,v 1.293 2017/03/09 15:29:35 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons - * Copyright (c) 2010-2015 Ingo Schwarze + * Copyright (c) 2010-2015, 2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1017,9 +1017,13 @@ roff_node_append(struct roff_man *man, struct roff_nod n->parent = man->last->parent; break; case ROFF_NEXT_CHILD: + if (man->last->child != NULL) { + n->next = man->last->child; + man->last->child->prev = n; + } else + man->last->last = n; man->last->child = n; n->parent = man->last; - n->parent->last = n; break; default: abort(); @@ -1219,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) { + for (cp = n->string; *cp != '\0'; cp++) { + if (cp[0] == '\\' && cp[1] != '\0' && + strchr(" %&0^|~", cp[1]) != NULL) cp++; - mandoc_escape((const char **)&cp, NULL, NULL); - } else if (isspace((unsigned char)*cp)) - 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; @@ -1601,7 +1608,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, 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); } @@ -3031,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; /* @@ -3055,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. */ @@ -3076,6 +3084,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. */ @@ -3358,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);