This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
scandir leak patch
- From: Joel Sherrill <joel dot sherrill at oarcorp dot com>
- To: "newlib at sources dot redhat dot com" <newlib at sources dot redhat dot com>
- Date: Mon, 24 Nov 2008 13:34:45 -0600
- Subject: scandir leak patch
Attached is the current newlib scandir.c with
the "goto cleanup_and_bail" modification from
the RTEMS one plus an explicit check for 0
entries from the fstat.
How does this look?
2008-11-24 Joel Sherrill <joel.sherrill@oarcorp.com>
* libc/posix/scandir.c: Fix memory leaks.
--
Joel Sherrill, Ph.D. Director of Research & Development
joel.sherrill@OARcorp.com On-Line Applications Research
Ask me about RTEMS: a free RTOS Huntsville AL 35805
Support Available (256) 722-9985
Index: scandir.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/posix/scandir.c,v
retrieving revision 1.6
diff -u -r1.6 scandir.c
--- scandir.c 31 Oct 2008 21:03:41 -0000 1.6
+++ scandir.c 24 Nov 2008 19:32:17 -0000
@@ -79,17 +79,22 @@
long arraysz;
DIR *dirp;
+ 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_and_bail;
+
+ /*
+ * If there were no directory entries, then bail.
+ */
+ if (stb.st_size == 0)
+ goto cleanup_and_bail;
/*
* estimate the array size by taking the size of the directory file
@@ -97,12 +102,8 @@
*/
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_and_bail;
nitems = 0;
while ((d = readdir(dirp)) != NULL) {
@@ -112,12 +113,8 @@
* 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_and_bail;
p->d_ino = d->d_ino;
p->d_reclen = d->d_reclen;
#ifdef _DIRENT_HAVE_D_NAMLEN
@@ -131,21 +128,13 @@
* 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_and_bail;
arraysz = stb.st_size / 12;
names = (struct dirent **)realloc((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_and_bail;
}
names[nitems-1] = p;
}
@@ -157,6 +146,24 @@
__lock_release_recursive(dirp->dd_lock);
#endif
return(nitems);
+
+cleanup_and_bail:
+
+ if ( dirp )
+ closedir( dirp );
+
+ if ( names ) {
+ int i;
+ for (i=0; i < nitems; i++ )
+ free( names[i] );
+ free( names );
+ }
+
+#ifdef HAVE_DD_LOCK
+ __lock_release_recursive(dirp->dd_lock);
+#endif
+
+ return(-1);
}
/*