diff options
author | julian <julian@FreeBSD.org> | 1998-10-07 01:30:02 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1998-10-07 01:30:02 +0000 |
commit | 7ae06315295ae0d16f7a0aeec3eaae9ae43ab2e1 (patch) | |
tree | 076b06da3b09c3b9ab27255a43d088587cf655b8 /lib/libc/gen/scandir.c | |
parent | 6d718e342c3ef45c17af49a7b5e6b95c88440b75 (diff) | |
download | FreeBSD-src-7ae06315295ae0d16f7a0aeec3eaae9ae43ab2e1.zip FreeBSD-src-7ae06315295ae0d16f7a0aeec3eaae9ae43ab2e1.tar.gz |
Fix a memory leak
PR: 7923
Submitted by: Archie Cobbs <archie@whistle.com>
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!
Diffstat (limited to 'lib/libc/gen/scandir.c')
-rw-r--r-- | lib/libc/gen/scandir.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 8a8b7d2..5c64b29 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -66,8 +66,8 @@ scandir(dirname, namelist, select, dcomp) 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 @@ scandir(dirname, namelist, select, dcomp) 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 @@ scandir(dirname, namelist, select, dcomp) 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 @@ scandir(dirname, namelist, select, dcomp) */ 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,33 @@ scandir(dirname, namelist, select, dcomp) * 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 */ - arraysz = stb.st_size / 12; - names = (struct dirent **)reallocf((char *)names, - arraysz * sizeof(struct dirent *)); - if (names == NULL) - return(-1); + if (nitems >= arraysz) { + const int inc = 10; /* increase by this much */ + struct dirent **names2; + + names2 = (struct dirent **)realloc((char *)names, + (arraysz + inc) * sizeof(struct dirent *)); + if (names2 == NULL) { + free(p); + goto fail; + } + names = names2; + arraysz += inc; } - 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; } /* |