[net.emacs] Bug in ReadDir in Gosling Emacs #264

glenn@nsc.UUCP (Glenn Skinner) (03/26/84)

There is a serious bug in the filename completion code in emacs #264
that can cause emacs to core dump when reading large directories.

The problem arises when reading directory entries.  The code maintains
two dynamically allocated arrays to hold character strings for the
directory entries and to hold pointers into this flat array of strings.
When either of these arrays overflows it is realloc'ed.  The bug is that
when the string array is reallocated, the pointers in the pointer array
must be adjusted to point into the new location.  The original code omits
this adjustment.

The fix is as follows.  Line numbers will almost certainly be off.

		-- Glenn Skinner
		National Semiconductor, Microprocessor Systems Division
		(408) 733-2600 x 335
		{amd70,fortune,hplabs,menlo70}!nsc!glenn

-------------------------------
*** filecomp.c-264.1	Mon Mar 26 10:51:04 1984
--- filecomp.c-264.2	Mon Mar 26 10:51:30 1984
***************
*** 181,187
  	}
  	if (KeepThisOne) {
  	    if (p -> d_namlen > ColumnWidth) ColumnWidth = p->d_namlen;
! 	    if (BytesUsed + p -> d_namlen + 2 >= EntryNameSize) {
  		EntryNameSize = (BytesUsed + p -> d_namlen) * 3 / 2;
  		if (EntryNameSize < 1000)
  		    EntryNameSize = 1000;

--- 181,187 -----
  	}
  	if (KeepThisOne) {
  	    if (p -> d_namlen > ColumnWidth) ColumnWidth = p->d_namlen;
! 	    if (BytesUsed + p -> d_namlen + 6 >= EntryNameSize) {
  		EntryNameSize = (BytesUsed + p -> d_namlen) * 3 / 2;
  		if (EntryNameSize < 1000)
  		    EntryNameSize = 1000;
***************
*** 185,192
  		EntryNameSize = (BytesUsed + p -> d_namlen) * 3 / 2;
  		if (EntryNameSize < 1000)
  		    EntryNameSize = 1000;
! 		EntryNames = EntryNames ? (char *) realloc (EntryNames, EntryNameSize)
! 		    : (char *) malloc (EntryNameSize);
  	    }
  	    if (DirUsed >= DirSize) {
  		DirSize = DirUsed + 50;

--- 185,202 -----
  		EntryNameSize = (BytesUsed + p -> d_namlen) * 3 / 2;
  		if (EntryNameSize < 1000)
  		    EntryNameSize = 1000;
! 		if (EntryNames) {
! 		    char *OldEntryNames = EntryNames;
! 		    register int bias, i;
! 
! 		    EntryNames = (char *) realloc (EntryNames, EntryNameSize);
! 		    /* Adjust DirEnts to point into EntryNames's new home: */
! 		    bias = EntryNames - OldEntryNames;
! 		    for (i = DirUsed; i; )
! 			DirEnts[--i] += bias;
! 		}
! 		else
! 		    EntryNames = (char *) malloc (EntryNameSize);
  	    }
  	    if (DirUsed >= DirSize-2) {
  		DirSize = DirUsed + 50;
***************
*** 188,194
  		EntryNames = EntryNames ? (char *) realloc (EntryNames, EntryNameSize)
  		    : (char *) malloc (EntryNameSize);
  	    }
! 	    if (DirUsed >= DirSize) {
  		DirSize = DirUsed + 50;
  		DirEnts = DirEnts ? (char **) realloc (DirEnts, DirSize * sizeof (char *))
  		    : (char **) malloc (DirSize * sizeof (char *));

--- 198,204 -----
  		else
  		    EntryNames = (char *) malloc (EntryNameSize);
  	    }
! 	    if (DirUsed >= DirSize-2) {
  		DirSize = DirUsed + 50;
  		DirEnts = DirEnts ? (char **) realloc (DirEnts, DirSize * sizeof (char *))
  		    : (char **) malloc (DirSize * sizeof (char *));