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))

Reply via email to