[gnu.emacs.bug] Bug in termcap.c

bruno@future.gipsi.fr (Bruno Verlyck) (10/12/89)

 I recently found a bug in termcap.c, that could be related to a
problem described by turner@uicsrd.csrd.uiuc.edu (Steve Turner):
> ..  then emacs dies in a call to free()!  ..
 At least the symptom is the same.

emacs-version: 18.55 

Description:

 Near line 660 in termcap.c, the loop:

	while (*end && *end != '\n') end++;

obviously expects a '\0' after the last (useful) byte in the buffer.
But this '\0' is set only if the buffer is not full (near line 685):

      if (bufp->full != bufp->size)
	buf[bufp->full] = 0;

If bufp->full == bufp->size, there is no warranty that bufp->ptr won't
go past the end of the buffer.  If this happens, bufp->full will
become negative near line 679:

	  bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);

since bufp->ptr - buf > bufp->size (max value of bufp->full).  Three
lines below:

      if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))

will read in memory before buf (= bufp->beg), destroying malloc info;
emacs will abort later, while trying:

  free (buf.beg);


If this may help to reproduce the bug: it happens to me after loading
gnus in site-load.el (don't forget to add gnus.elc to make {etcdir}DOC
in ymakefile): this lets huge doc strings in memory.  Note that you
also have to type emacs -nw if you are using X.

 Now, the minimal patch (and cleanest, I hope) I used to cure the bug.
It simply allocates one more byte for the buffer, and clears it
unconditionally.

*** termcap.c	Tue Sep 19 19:24:49 1989
--- old/termcap.c	Thu Nov 24 14:00:10 1988
***************
*** 470,476 ****
      return -1;
  
    buf.size = BUFSIZE;
!   buf.beg = (char *) xmalloc (buf.size + 1);
    term = indirect ? indirect : name;
  
    if (!bp)
--- 470,476 ----
      return -1;
  
    buf.size = BUFSIZE;
!   buf.beg = (char *) xmalloc (buf.size);
    term = indirect ? indirect : name;
  
    if (!bp)
***************
*** 667,673 ****
  	  if (bufp->full == bufp->size)
  	    {
  	      bufp->size *= 2;
! 	      tem = (char *) xrealloc (buf, bufp->size + 1);
  	      bufp->ptr += tem - buf;
  	      append_end += tem - buf;
  	      bufp->beg = buf = tem;
--- 667,673 ----
  	  if (bufp->full == bufp->size)
  	    {
  	      bufp->size *= 2;
! 	      tem = (char *) xrealloc (buf, bufp->size);
  	      bufp->ptr += tem - buf;
  	      append_end += tem - buf;
  	      bufp->beg = buf = tem;
***************
*** 682,688 ****
        if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
  	bufp->ateof = 1;
        bufp->full += nread;
!       buf[bufp->full] = 0;
      }
    return end + 1;
  }
--- 682,689 ----
        if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
  	bufp->ateof = 1;
        bufp->full += nread;
!       if (bufp->full != bufp->size)
! 	buf[bufp->full] = 0;
      }
    return end + 1;
  }