mutt/1536: Segment fault with long lines when LANG=*.UTF-8
On Sunday, 07 August 2005 at 01:36, TAKAHASHI Tamotsu wrote:
> On Fri, 05 Aug 2005, Brendan Cully wrote:
> > Ok, this sounds a little bit risky. How about another suggestion: we
> > only do the check when b_read == blen - 2? that is, when fgets has run
> > all the way to the end of the buffer. That should keep things speedy
> > in the normal case.
>
> Sounds good!
>
>
> But please don't forget the following issue:
>
> > On Friday, 05 August 2005 at 18:40, TAKAHASHI Tamotsu wrote:
> > > And I'm afraid the patches should malloc, clear and use mbstate
> > > instead of NULL. Every other mbrtowc() in mutt is using its own
> > > mbstate, AFAIK. It could work well even without its own mbstate,
> > > but it would be hard to debug once a problem occurred.
Does this work? I've never been able to reproduce the segfault, so I
don't know whether or not I've introduced an off-by-one error or
something.
Index: pager.c
===================================================================
RCS file: /home/roessler/cvs/mutt/pager.c,v
retrieving revision 3.21
diff -u -p -r3.21 pager.c
--- pager.c 30 Jul 2005 04:40:45 -0000 3.21
+++ pager.c 6 Aug 2005 18:04:04 -0000
@@ -969,13 +969,34 @@ static int grok_ansi(unsigned char *buf,
return pos;
}
+/* trim tail of buf so that it contains complete multibyte characters */
+static int
+trim_incomplete_mbyte(unsigned char *buf, size_t len)
+{
+ mbstate_t mbstate;
+ size_t k;
+
+ memset (&mbstate, 0, sizeof (mbstate));
+ for (; len > 0; buf += k, len -= k)
+ {
+ k = mbrtowc (NULL, (char *) buf, len, &mbstate);
+ if (k == -2)
+ break;
+ else if (k == -1 || k == 0)
+ k = 1;
+ }
+ *buf = '\0';
+
+ return len;
+}
+
static int
fill_buffer (FILE *f, long *last_pos, long offset, unsigned char *buf,
unsigned char *fmt, size_t blen, int *buf_ready)
{
unsigned char *p;
static int b_read;
-
+
if (*buf_ready == 0)
{
buf[blen - 1] = 0;
@@ -990,6 +1011,9 @@ fill_buffer (FILE *f, long *last_pos, lo
b_read = (int) (*last_pos - offset);
*buf_ready = 1;
+ if (b_read == blen - 2)
+ b_read -= trim_incomplete_mbyte(buf, b_read);
+
/* copy "buf" to "fmt", but without bold and underline controls */
p = buf;
while (*p)