Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 13 Sep 1998 20:30:41 -0700 (PDT)
From:      Archie Cobbs <archie@whistle.com>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   bin/7923: scandir(3) does not clean up after itself if it fails
Message-ID:  <199809140330.UAA15858@bubba.whistle.com>

next in thread | raw e-mail | index | archive | help

>Number:         7923
>Category:       bin
>Synopsis:       scandir(3) does not clean up after itself if it fails
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Sep 13 20:40:01 PDT 1998
>Last-Modified:
>Originator:     Archie Cobbs
>Organization:
Whistle Communications, Inc.
>Release:        FreeBSD 2.2.6-RELEASE i386
>Environment:

	FreeBSD 3.0-current circa July 13, 1998 20:00 GMT

>Description:

	The scandir() function returns -1 if it fails.
	In many cases when this happens, it does not free
	the memory that it allocated, resulting in a memory
	leak, or close the directory opened with opendir().
	BAD DOG, BAD!

>How-To-Repeat:


>Fix:
	
Index: scandir.c
===================================================================
RCS file: /cvs/freebsd/src/lib/libc/gen/scandir.c,v
retrieving revision 1.3
diff -c -u -r1.3 scandir.c
--- scandir.c	1995/05/30 05:40:23	1.3
+++ scandir.c	1998/09/14 03:29:09
@@ -66,8 +66,8 @@
 	int (*select) __P((struct dirent *));
 	int (*dcomp) __P((const void *, const void *));
 {
-	register struct dirent *d, *p, **names;
-	register size_t nitems;
+	register struct dirent *d, *p, **names = NULL;
+	register size_t nitems = 0;
 	struct stat stb;
 	long arraysz;
 	DIR *dirp;
@@ -75,7 +75,7 @@
 	if ((dirp = opendir(dirname)) == NULL)
 		return(-1);
 	if (fstat(dirp->dd_fd, &stb) < 0)
-		return(-1);
+		goto fail;
 
 	/*
 	 * estimate the array size by taking the size of the directory file
@@ -84,9 +84,8 @@
 	arraysz = (stb.st_size / 24);
 	names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
 	if (names == NULL)
-		return(-1);
+		goto fail;
 
-	nitems = 0;
 	while ((d = readdir(dirp)) != NULL) {
 		if (select != NULL && !(*select)(d))
 			continue;	/* just selected names */
@@ -95,7 +94,7 @@
 		 */
 		p = (struct dirent *)malloc(DIRSIZ(d));
 		if (p == NULL)
-			return(-1);
+			goto fail;
 		p->d_fileno = d->d_fileno;
 		p->d_type = d->d_type;
 		p->d_reclen = d->d_reclen;
@@ -105,22 +104,36 @@
 		 * Check to make sure the array has space left and
 		 * realloc the maximum size.
 		 */
-		if (++nitems >= arraysz) {
-			if (fstat(dirp->dd_fd, &stb) < 0)
-				return(-1);	/* just might have grown */
+		if (nitems + 1 >= arraysz) {
+			struct dirent **names2;
+
+			if (fstat(dirp->dd_fd, &stb) < 0) {
+				free(p);
+				goto fail;	/* just might have grown */
+			}
 			arraysz = stb.st_size / 12;
-			names = (struct dirent **)realloc((char *)names,
+			names2 = (struct dirent **)realloc((char *)names,
 				arraysz * sizeof(struct dirent *));
-			if (names == NULL)
-				return(-1);
+			if (names2 == NULL) {
+				free(p);
+				goto fail;
+			}
+			names = names2;
 		}
-		names[nitems-1] = p;
+		names[nitems++] = p;
 	}
 	closedir(dirp);
 	if (nitems && dcomp != NULL)
 		qsort(names, nitems, sizeof(struct dirent *), dcomp);
 	*namelist = names;
 	return(nitems);
+
+fail:
+	while (nitems > 0)
+		free(names[--nitems]);
+	free(names);
+	closedir(dirp);
+	return -1;
 }
 
 /*
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199809140330.UAA15858>