Date: Mon, 29 Sep 1997 15:38:57 +0100 From: Gareth McCaughan <gjm11@dpmms.cam.ac.uk> To: freebsd-bugs@freebsd.org Subject: bin/4520 and fmt Message-ID: <E0xFgyQ-0006sX-00@g.pet.cam.ac.uk>
next in thread | raw e-mail | index | archive | help
Mikhail Teterin reported a bug in fmt whereby it dumps core when given a long line (more precisely, it happens when it's given a line that contains a long "word"). I offer two solutions. 1. The following patch, which also fixes a so-far-unreported bug (fmt allows backslashed whitespace inside words, but it only counts each such as one character long). (It's relative to the version of fmt.c in 2.2-stable as of early August.) --------------------------- patch begins --------------------------- *** fmt.c.orig Mon Sep 29 14:35:34 1997 --- fmt.c Mon Sep 29 15:04:55 1997 *************** *** 335,347 **** char line[]; { register char *cp, *cp2; ! char word[BUFSIZ]; int wordl; /* LIZ@UOM 6/18/85 */ cp = line; while (*cp) { cp2 = word; wordl = 0; /* LIZ@UOM 6/18/85 */ /* * Collect a 'word,' allowing it to contain escaped white --- 335,354 ---- char line[]; { register char *cp, *cp2; ! char *word; int wordl; /* LIZ@UOM 6/18/85 */ + int wordsize, wordleft; + + word = malloc(BUFSIZ); + if (word == 0) + abort(); + wordsize=BUFSIZ; cp = line; while (*cp) { cp2 = word; wordl = 0; /* LIZ@UOM 6/18/85 */ + wordleft = wordsize; /* * Collect a 'word,' allowing it to contain escaped white *************** *** 349,357 **** */ while (*cp && *cp != ' ') { if (*cp == '\\' && isspace(cp[1])) ! *cp2++ = *cp++; *cp2++ = *cp++; wordl++;/* LIZ@UOM 6/18/85 */ } /* --- 356,372 ---- */ while (*cp && *cp != ' ') { if (*cp == '\\' && isspace(cp[1])) ! *cp2++ = *cp++, wordl++, wordleft--; *cp2++ = *cp++; wordl++;/* LIZ@UOM 6/18/85 */ + if (--wordleft < 4) { + char *oldword = word; + wordleft += wordsize; wordsize *= 2; + word = realloc(word, wordsize); + if (word == 0) + abort(); + cp2 += word-oldword; + } } /* *************** *** 363,376 **** if (index(".:!", cp[-1])) *cp2++ = ' '; } ! while (*cp == ' ') *cp2++ = *cp++; *cp2 = '\0'; /* * LIZ@UOM 6/18/85 pack(word); */ pack(word, wordl); } } /* --- 378,401 ---- if (index(".:!", cp[-1])) *cp2++ = ' '; } ! while (*cp == ' ') { *cp2++ = *cp++; + if (--wordleft < 3) { /* yes, 3. Sorry. */ + char *oldword = word; + wordleft += wordsize; wordsize *= 2; + word = realloc(word, wordsize); + if (word == 0) + abort(); + cp2 += word-oldword; + } + } *cp2 = '\0'; /* * LIZ@UOM 6/18/85 pack(word); */ pack(word, wordl); } + free(word); } /* *************** *** 382,389 **** * there ain't nothing in there yet. At the bottom of this whole mess, * leading tabs are reinserted. */ ! char outbuf[BUFSIZ]; /* Sandbagged output line image */ char *outp; /* Pointer in above */ /* * Initialize the output section. --- 407,415 ---- * there ain't nothing in there yet. At the bottom of this whole mess, * leading tabs are reinserted. */ ! char *outbuf; /* Sandbagged output line image */ char *outp; /* Pointer in above */ + int outbuf_size; /* er, size of outbuf */ /* * Initialize the output section. *************** *** 391,396 **** --- 417,426 ---- void setout() { + outbuf = malloc(BUFSIZ); + if (outbuf == 0) + abort(); + outbuf_size = BUFSIZ; outp = NOSTR; } *************** *** 421,426 **** --- 451,463 ---- { register char *cp; register int s, t; + + if (((outp==NOSTR) ? wl : outp-outbuf + wl) >= outbuf_size) { + outbuf_size *= 2; + outbuf = realloc(outbuf, outbuf_size); + if (outbuf == 0) + abort(); + } if (outp == NOSTR) leadin(); ---------------------------- patch ends ---------------------------- 2. The source for fmt is a real mess. It's full of fixed-size buffers and calls to |abort| and basically it's horrible. This will still be the case no matter how many fixes of the above type get contributed. I have a drop-in replacement for it, written by me, which the FreeBSD project can have on any reasonable terms. It contains no fixed-size buffers, no calls to |abort| and no ghastly ad-hockery. It's also significantly faster (not that that matters). Official FreeBSD People: Are you interested in this? A couple of other fmt things: - It also appears that my patch for bin/2968 has been applied to fix bin/4607 (fine) and that bin/4607 hasn't been closed (not fine). - When fmt sees a mailbox From line (`From foo@bar Mon Sep 12 ...') it attempts to put it and any following To:, Cc:, Subject: lines on output lines of their own. It seems to me that this is the Wrong Thing to do. Either mail headers should be treated specially all the time (and not just those three, of course), even when not preceded by a mailbox From line, or they should be treated exactly like ordinary text all the time. I vote for the latter. The only reason I can see for doing special things with mail headers is because people might want to use fmt to format mail messages. Mail messages do not generally contain mailbox headers; only the mail headers themselves. Does anyone really do `fmt /var/mail/me'? -- Gareth McCaughan Dept. of Pure Mathematics & Mathematical Statistics, gjm11@dpmms.cam.ac.uk Cambridge University, England.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E0xFgyQ-0006sX-00>