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>
