Hello, I work with a lot of sources that have strange formatting (as do you no doubt). I noticed that sometimes changing the tabstop value in search of a reasonable display vi would crash.
Took me a bit to figure out the reproducible steps to be able to come up with a fix. Steps to reproduce the crash. Reproducible on i386, amd64, and macppc: 1. Imagine a file edited with a small tabstop value (say 2 or 3) containing lines long enough so they wrap in default tabstop (8), but possibly not in the smaller tabstop values. 2. While tabstop set to 8, position one of the wrapping lines such that the beginning of said line is off screen and the tail end of the wrapped portion is the first line on the screen with the cursor positioned on same first line. 3. Change tabstop to 2 (or 3). Assuming there were more lines below the line your cursor is on, you will notice a drawing glitch where only the top line is redrawn and the rest of the screen is blanked out. 4. If at this point you press ^B (page backwards) vi will core dump. A visual of what I experience (series of five screen-shots): http://sidster.com/scratch/nvi/ The patch below resets the HMAP->soff (screen offset of line) to 1 if the number of lines HMAP->lno spans has changed and is now less than HMAP->soff. This essentially forces the entire line to be redrawn at the top of the screen, avoids the redraw glitch and eventual crash. Comments? --patrick Index: vi/vs_smap.c =================================================================== RCS file: /cvs/obsd/src/usr.bin/vi/vi/vs_smap.c,v retrieving revision 1.7 diff -u -p vi/vs_smap.c --- vi/vs_smap.c 27 Oct 2009 23:59:49 -0000 1.7 +++ vi/vs_smap.c 8 Dec 2010 06:22:09 -0000 @@ -224,6 +224,17 @@ top: HMAP->lno = lno; HMAP->coff = 0; HMAP->soff = 1; } + else { + /* + * If number of lines HMAP->lno (top line) spans + * changed due to, say reformatting, and now is + * fewer than HMAP->soff, reset so the line is + * redrawn at the top of the screen. + */ + cnt = vs_screens(sp, HMAP->lno, NULL); + if (cnt < HMAP->soff) + HMAP->soff = 1; + } /* If we fail, just punt. */ for (p = HMAP, cnt = sp->t_rows; --cnt; ++p) if (vs_sm_next(sp, p, p + 1))