[net.bugs.4bsd] scandir

lepreau@utah-cs.UUCP (Jay Lepreau) (11/30/83)

Index:	lib/libc/gen/scandir.c 4.2BSD Fix

Description:
	1.  If the arraysz estimate proved low, scandir does a realloc
	assuming the worst, but it never recomputes the new arraysz,
	so it keeps calling realloc all the rest of the way thru the dir.
	(This isn't as bad as it sounds, for realloc is smart enuf not
	to do anything if the same size is requested.)
	2. scandir is overly optimistic about the worst case: the directory
	could grow on it (unless there's some synchrony out there I don't
	know about), leading to an infinite loop.  It should restat the
	directory.
Repeat-By:
	Well, *I* noticed it from that nifty gprof output showing
	hundreds of realloc calls.  Obvious from inspection too.
Fix:
***************
*** 60,61
  		if (++nitems >= arraysz) {
  			names = (struct direct **)realloc((char *)names,

--- 62,66 -----
  		if (++nitems >= arraysz) {
+ 			if (fstat(dirp->dd_fd, &stb) < 0)
+ 				return(-1);	/* just might have grown */
+ 			arraysz = stb.st_size/12;
  			names = (struct direct **)realloc((char *)names,
***************
*** 61,63
  			names = (struct direct **)realloc((char *)names,
! 				(stb.st_size/12) * sizeof(struct direct *));
  			if (names == NULL)

--- 66,68 -----
  			names = (struct direct **)realloc((char *)names,
! 				arraysz * sizeof(struct direct *));
  			if (names == NULL)

jdb@mordor.UUCP (John Bruner) (06/28/85)

Index:	lib/libc/gen/scandir.c 4.2

Description:

The manual page (and source code) for scandir() declare the
second argument to be

	struct direct *(*namelist[]);

This is an array of pointers to pointers, which is incorrect.
However, in scandir() it compiles correctly because it is a formal
parameter and array parameters are considered to have pointer type.

This argument should be the address of a pointer to an array of
pointers to elements of type "struct direct":

	struct direct *(**namelist)[];

or, more simply:

	struct direct ***namelist;
-- 
  John Bruner (S-1 Project, Lawrence Livermore National Laboratory)
  MILNET: jdb@mordor [jdb@s1-c.ARPA]	(415) 422-0758
  UUCP: ...!ucbvax!dual!mordor!jdb 	...!seismo!mordor!jdb

rees@apollo.uucp (Jim Rees) (07/02/85)

While you're at it, fix the realloc logic.  It can't ever work, because
once it runs out of space, it realloc's every time through the loop.
And it thinks it's smarter than it really is about how big a directory
entry should be.  It shouldn't have numbers like "24" hard wired into
the source code.

***************
*** 55,61
  		for (cp1 = p->d_name, cp2 = d->d_name; *cp1++ = *cp2++; );
  		/*
  		 * Check to make sure the array has space left and
! 		 * realloc the maximum size.
  		 */
  		if (++nitems >= arraysz) {
  			names = (struct direct **)realloc((char *)names,

--- 70,76 -----
  		for (cp1 = p->d_name, cp2 = d->d_name; *cp1++ = *cp2++; );
  		/*
  		 * Check to make sure the array has space left and
! 		 * realloc some more.
  		 */
  		if (nitems >= arraysz) {
  			arraysz += arraysz / 2 + 2;
***************
*** 57,63
  		 * Check to make sure the array has space left and
  		 * realloc the maximum size.
  		 */
! 		if (++nitems >= arraysz) {
  			names = (struct direct **)realloc((char *)names,
  				(stb.st_size/12) * sizeof(struct direct *));
  			if (names == NULL)

--- 72,79 -----
  		 * Check to make sure the array has space left and
  		 * realloc some more.
  		 */
! 		if (nitems >= arraysz) {
! 			arraysz += arraysz / 2 + 2;
  			names = (struct direct **)realloc((char *)names,
  				arraysz * sizeof(struct direct *));
  			if (names == NULL)
***************
*** 59,65
  		 */
  		if (++nitems >= arraysz) {
  			names = (struct direct **)realloc((char *)names,
! 				(stb.st_size/12) * sizeof(struct direct *));
  			if (names == NULL)
  				return(-1);
  		}

--- 75,81 -----
  		if (nitems >= arraysz) {
  			arraysz += arraysz / 2 + 2;
  			names = (struct direct **)realloc((char *)names,
! 				arraysz * sizeof(struct direct *));
  			if (names == NULL)
  				return(-1);
  		}
***************
*** 63,69
  			if (names == NULL)
  				return(-1);
  		}
! 		names[nitems-1] = p;
  	}
  	closedir(dirp);
  	if (nitems && dcomp != NULL)

--- 79,85 -----
  			if (names == NULL)
  				return(-1);
  		}
! 		names[nitems++] = p;
  	}
  	closedir(dirp);
  	if (nitems && dcomp != NULL)