The following commit has been merged in the master branch:
commit 365611d9f86e1da98007e5b3b3a14dfea2d5acda
Author: Guillem Jover <[email protected]>
Date:   Mon Nov 9 19:06:18 2009 +0100

    libcompat: Fix resource leaks on error conditions in scandir

diff --git a/TODO b/TODO
index e8b640b..84693f7 100644
--- a/TODO
+++ b/TODO
@@ -56,7 +56,6 @@ TODO
 
  * Cleanup libcompat:
    - Add fnmatch, IRIX5 doesn't have it.
-   - Fix scandir, leaks on malloc and realloc.
 
  * Man pages:
    - Add example to dpkg-scanfoo manpages?
diff --git a/lib/compat/scandir.c b/lib/compat/scandir.c
index 95b4808..2fc8d01 100644
--- a/lib/compat/scandir.c
+++ b/lib/compat/scandir.c
@@ -2,6 +2,7 @@
  * libcompat - system compatibility library
  *
  * Copyright © 1995 Ian Jackson <[email protected]>
+ * Copyright © 2008, 2009 Guillem Jover <[email protected]>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,14 +27,31 @@
 #include <stdlib.h>
 
 #ifndef HAVE_SCANDIR
+static int
+cleanup(DIR *dir, struct dirent **dirlist, int used)
+{
+       if (dir)
+               closedir(dir);
+
+       if (dirlist) {
+               int i;
+
+               for (i = 0; i < used; i++)
+                       free(dirlist[i]);
+               free(dirlist);
+       }
+
+       return -1;
+}
+
 int
 scandir(const char *dir, struct dirent ***namelist,
         int (*filter)(const struct dirent *),
         int (*cmp)(const void *, const void *))
 {
        DIR *d;
+       struct dirent *e, *m, **list;
        int used, avail;
-       struct dirent *e, *m;
 
        d = opendir(dir);
        if (!d)
@@ -42,34 +60,40 @@ scandir(const char *dir, struct dirent ***namelist,
        used = 0;
        avail = 20;
 
-       *namelist = malloc(avail * sizeof(struct dirent *));
-       if (!*namelist)
-               return -1;
+       list = malloc(avail * sizeof(struct dirent *));
+       if (!list)
+               return cleanup(d, list, used);
 
        while ((e = readdir(d)) != NULL) {
                if (filter != NULL && !filter(e))
                        continue;
 
+               if (used >= avail - 1) {
+                       struct dirent **newlist;
+
+                       avail += avail;
+                       newlist = realloc(list, avail * sizeof(struct dirent 
*));
+                       if (!newlist)
+                               return cleanup(d, list, used);
+               }
+
                m = malloc(sizeof(struct dirent) + strlen(e->d_name));
                if (!m)
-                       return -1;
+                       return cleanup(d, list, used);
                *m = *e;
                strcpy(m->d_name, e->d_name);
 
-               if (used >= avail - 1) {
-                       avail += avail;
-                       *namelist = realloc(*namelist, avail * sizeof(struct 
dirent *));
-                       if (!*namelist)
-                               return -1;
-               }
-
-               (*namelist)[used] = m;
+               list[used] = m;
                used++;
        }
-       (*namelist)[used] = NULL;
+       list[used] = NULL;
+
+       closedir(d);
 
        if (cmp != NULL)
-               qsort(*namelist, used, sizeof(struct dirent *), cmp);
+               qsort(list, used, sizeof(struct dirent *), cmp);
+
+       *namelist = list;
 
        return used;
 }

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to