aboutsummaryrefslogtreecommitdiff
path: root/newlib
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2008-11-24 20:42:33 +0000
committerJeff Johnston <jjohnstn@redhat.com>2008-11-24 20:42:33 +0000
commitdf913771a7eadea673eb7b3208e1d656782efe3e (patch)
treeb8e820cd991c4ab7b7a653a2e84c404f1f9e8789 /newlib
parentb45d16228b32524557e6dadd7dc140124dd3225b (diff)
downloadnewlib-df913771a7eadea673eb7b3208e1d656782efe3e.zip
newlib-df913771a7eadea673eb7b3208e1d656782efe3e.tar.gz
newlib-df913771a7eadea673eb7b3208e1d656782efe3e.tar.bz2
2008-11-24 Joel Sherrill <joel.sherrill@oarcorp.com>
* libc/posix/scandir.c: Fix memory leaks.
Diffstat (limited to 'newlib')
-rw-r--r--newlib/ChangeLog4
-rw-r--r--newlib/libc/posix/scandir.c75
2 files changed, 44 insertions, 35 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index 1a8c559..5e676cf 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -1,5 +1,9 @@
2008-11-24 Joel Sherrill <joel.sherrill@oarcorp.com>
+ * libc/posix/scandir.c: Fix memory leaks.
+
+2008-11-24 Joel Sherrill <joel.sherrill@oarcorp.com>
+
* libc/posix/Makefile.am: Compile readdir_r.c
* libc/posix/Makefile.in: Regenerated.
diff --git a/newlib/libc/posix/scandir.c b/newlib/libc/posix/scandir.c
index ef3e9db..96a66de 100644
--- a/newlib/libc/posix/scandir.c
+++ b/newlib/libc/posix/scandir.c
@@ -78,18 +78,25 @@ _DEFUN(scandir, (dirname, namelist, select, dcomp),
struct stat stb;
long arraysz;
DIR *dirp;
+ int successful = 0;
+ int rc = 0;
+
+ dirp = NULL;
+ names = NULL;
if ((dirp = opendir(dirname)) == NULL)
return(-1);
#ifdef HAVE_DD_LOCK
__lock_acquire_recursive(dirp->dd_lock);
#endif
- if (fstat(dirp->dd_fd, &stb) < 0) {
-#ifdef HAVE_DD_LOCK
- __lock_release_recursive(dirp->dd_lock);
-#endif
- return(-1);
- }
+ if (fstat(dirp->dd_fd, &stb) < 0)
+ goto cleanup;
+
+ /*
+ * If there were no directory entries, then bail.
+ */
+ if (stb.st_size == 0)
+ goto cleanup;
/*
* estimate the array size by taking the size of the directory file
@@ -97,12 +104,8 @@ _DEFUN(scandir, (dirname, namelist, select, dcomp),
*/
arraysz = (stb.st_size / 24);
names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
- if (names == NULL) {
-#ifdef HAVE_DD_LOCK
- __lock_release_recursive(dirp->dd_lock);
-#endif
- return(-1);
- }
+ if (names == NULL)
+ goto cleanup;
nitems = 0;
while ((d = readdir(dirp)) != NULL) {
@@ -112,12 +115,8 @@ _DEFUN(scandir, (dirname, namelist, select, dcomp),
* Make a minimum size copy of the data
*/
p = (struct dirent *)malloc(DIRSIZ(d));
- if (p == NULL) {
-#ifdef HAVE_DD_LOCK
- __lock_release_recursive(dirp->dd_lock);
-#endif
- return(-1);
- }
+ if (p == NULL)
+ goto cleanup;
p->d_ino = d->d_ino;
p->d_reclen = d->d_reclen;
#ifdef _DIRENT_HAVE_D_NAMLEN
@@ -131,32 +130,38 @@ _DEFUN(scandir, (dirname, namelist, select, dcomp),
* realloc the maximum size.
*/
if (++nitems >= arraysz) {
- if (fstat(dirp->dd_fd, &stb) < 0) {
-#ifdef HAVE_DD_LOCK
- __lock_release_recursive(dirp->dd_lock);
-#endif
- return(-1); /* just might have grown */
- }
+ if (fstat(dirp->dd_fd, &stb) < 0)
+ goto cleanup;
arraysz = stb.st_size / 12;
- names = (struct dirent **)realloc((char *)names,
+ names = (struct dirent **)reallocf((char *)names,
arraysz * sizeof(struct dirent *));
- if (names == NULL) {
-#ifdef HAVE_DD_LOCK
- __lock_release_recursive(dirp->dd_lock);
-#endif
- return(-1);
- }
+ if (names == NULL)
+ goto cleanup;
}
names[nitems-1] = p;
}
+ successful = 1;
+cleanup:
closedir(dirp);
- if (nitems && dcomp != NULL)
- qsort(names, nitems, sizeof(struct dirent *), (void *)dcomp);
- *namelist = names;
+ if (successful) {
+ if (nitems && dcomp != NULL)
+ qsort(names, nitems, sizeof(struct dirent *), (void *)dcomp);
+ *namelist = names;
+ rc = nitems;
+ } else { /* We were unsuccessful, clean up storage and return -1. */
+ if ( names ) {
+ int i;
+ for (i=0; i < nitems; i++ )
+ free( names[i] );
+ free( names );
+ }
+ rc = -1;
+ }
+
#ifdef HAVE_DD_LOCK
__lock_release_recursive(dirp->dd_lock);
#endif
- return(nitems);
+ return(rc);
}
/*