Hi Ingo,

thanks for your detailed analysis, makes sense to me OK florian@

Apologies to Hiltjo for slacking on this. I looked at it multiple
times but couldn't make any progress on it.

Florian

On Thu, Jul 06, 2017 at 04:08:09PM +0200, Ingo Schwarze wrote:
> Hi,
> 
> Hiltjo Posthuma wrote on Sun, Jun 18, 2017 at 03:04:31PM +0200:
> 
> > mg crashes with certain (unicode) characters and moving the cursor to the
> > end of the line.
> 
> Even though i failed to reproduce the crash, even with MALLOC_OPTIONS=S,
> i see how it may happen.  Your analysis looks at the right functions,
> but part of it is inaccurate.
> 
> > The characters are printed to the screen as \nnn in vtpute()
> 
> No, they are not, which is another bug that needs fixing.
> 
> > and vtcol is updated,
> 
> No, not sufficiently, which is exactly the problem.
> 
> > however vteeol() will write beyond the buffer.
> 
> More precisely, before the beginning of the buffer.
> 
> > A test file contains the data:
> >
> > ??????????????????????????????????????????????????????
> 
> [ Regarding vteeol() ]
> > It is safer to use vtpute() here because it checks if vtcol >= 0.
> 
> No, that is not needed.  Apart from incrementing vtcol, the only
> place where vtcol is changed is vtmove().  The only place where
> vtmove() is called with a non-zero second argument is in updext().
> In updext(), when calculating lbound, both numbers subtracted are
> clearly non-negative, so we have lbound <= curcol.  So after the
> loop calling vtpute() repeatedly, vtcol >= 0 ought to be guaranteed.
> To summarize, vtcol >= 0 is an invariant except for a very short
> section of code inside updext(), and the check in vtpute() is only
> needed for the call from that section.  In vteeol(), no such check
> is needed.
> 
> The problem is that vtpute() is not handling bytes correctly that
> are neither printable nor control characters.  It does not print
> anything for them and it increments vtcol only by one.  Consequently,
> whenn there are many bytes with the high bit set, vtcol may remain
> negative after finishing the loop in updext(), and vteeol() gets
> fatally called with negative vtcol.
> 
> The patch below fixes the root cause by adding the same logic for
> handling special characters to vtpute() that you can already see
> in vtputc().  I tried to keep the patch minimal, and to also mimick
> the existing style.
> 
> OK to commit that?
> 
> > Below is a patch:
> 
> Your patch would merely hide the bug, and the editor still wouldn't
> operate correctly.
> 
> Yours,
>   Ingo
> 
> 
> Index: display.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/display.c,v
> retrieving revision 1.47
> diff -u -p -r1.47 display.c
> --- display.c 3 Apr 2015 22:10:29 -0000       1.47
> +++ display.c 6 Jul 2017 13:55:43 -0000
> @@ -366,10 +366,16 @@ vtpute(int c)
>       } else if (ISCTRL(c) != FALSE) {
>               vtpute('^');
>               vtpute(CCHR(c));
> -     } else {
> +     } else if (isprint(c)) {
>               if (vtcol >= 0)
>                       vp->v_text[vtcol] = c;
>               ++vtcol;
> +     } else {
> +             char bf[5], *cp;
> +
> +             snprintf(bf, sizeof(bf), "\\%o", c);
> +             for (cp = bf; *cp != '\0'; cp++)
> +                     vtpute(*cp);
>       }
>  }
>  

-- 
I'm not entirely sure you are real.

Reply via email to