]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix memory leak in ISO reader.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 6 Jan 2010 09:24:48 +0000 (04:24 -0500)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 6 Jan 2010 09:24:48 +0000 (04:24 -0500)
Do not use a reference counter to decide to release a memory
used for struct file_info.
Release all memories of struct file_info at the end instead.

SVN-Revision: 1808

libarchive/archive_read_support_format_iso9660.c

index 02498456197ff0fa7a07a9b52d39f3596afb1380..7bc031af864a334b0a54851b616a114688b54e51 100644 (file)
@@ -258,9 +258,9 @@ struct content {
 
 /* In-memory storage for a directory record. */
 struct file_info {
+       struct file_info        *use_next;
        struct file_info        *parent;
        struct file_info        *next;
-       int              refcount;
        int              subdirs;
        uint64_t         key;           /* Heap Key.                    */
        uint64_t         offset;        /* Offset on disk.              */
@@ -331,6 +331,7 @@ struct iso9660 {
        int64_t         previous_number;
        struct archive_string previous_pathname;
 
+       struct file_info                *use_files;
        struct heap_queue                pending_files;
        struct {
                struct file_info        *first;
@@ -396,7 +397,8 @@ static void parse_rockridge_TF1(struct file_info *,
                    const unsigned char *, int);
 static void    parse_rockridge_ZF1(struct file_info *,
                    const unsigned char *, int);
-static void    release_file(struct iso9660 *, struct file_info *);
+static void    register_file(struct iso9660 *, struct file_info *);
+static void    release_files(struct iso9660 *);
 static unsigned        toi(const void *p, int n);
 static inline void cache_add_entry(struct iso9660 *iso9660,
                    struct file_info *file);
@@ -980,7 +982,6 @@ read_children(struct archive_read *a, struct file_info *parent)
                                        }
                                        con = malloc(sizeof(struct content));
                                        if (con == NULL) {
-                                               release_file(iso9660, child);
                                                archive_set_error(
                                                    &a->archive, ENOMEM,
                                                    "No memory for "
@@ -998,7 +999,6 @@ read_children(struct archive_read *a, struct file_info *parent)
                                                multi->size += child->size;
                                                if (!child->multi_extent)
                                                        multi = NULL;
-                                               release_file(iso9660, child);
                                        }
                                } else
                                        add_entry(iso9660, child);
@@ -1029,10 +1029,8 @@ relocate_dir(struct iso9660 *iso9660, struct file_info *file)
                /* This case is wrong pattern. */
                return (0);
        if (re->offset == file->cl_offset) {
-               re->parent->refcount--;
                re->parent->subdirs--;
                re->parent = file->parent;
-               re->parent->refcount++;
                re->parent->subdirs++;
                cache_add_to_next_of_parent(iso9660, re);
                return (1);
@@ -1077,10 +1075,8 @@ read_entries(struct archive_read *a)
                /*
                 * Relocate directory which rr_moved has.
                 */
-               while ((file = heap_get_entry(&(iso9660->cl_files))) != NULL) {
+               while ((file = heap_get_entry(&(iso9660->cl_files))) != NULL)
                        relocate_dir(iso9660, file);
-                       release_file(iso9660, file);
-               }
 
                /* If rr_moved directory still has children,
                 * Add rr_moved into pending_files to show
@@ -1092,10 +1088,8 @@ read_entries(struct archive_read *a)
                         * is broken), the entries won't be exposed. */
                        while ((file = heap_get_entry(&(iso9660->re_dirs))) != NULL)
                                cache_add_entry(iso9660, file);
-               } else {
+               } else
                        iso9660->rr_moved->parent->subdirs--;
-                       release_file(iso9660, iso9660->rr_moved);
-               }
        } else {
                /*
                 * In case ISO image is broken. If the name of rr_moved
@@ -1174,7 +1168,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
                if (vd == &(iso9660->primary) && !iso9660->seenRockridge
                    && iso9660->seenJoliet) {
                        /* Switch reading data from primary to joliet. */ 
-                       release_file(iso9660, file);
                        vd = &(iso9660->joliet);
                        skipsize = LOGICAL_BLOCK_SIZE * vd->location;
                        skipsize -= iso9660->current_position;
@@ -1214,10 +1207,8 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
 
        /* Get the next entry that appears after the current offset. */
        r = next_entry_seek(a, iso9660, &file);
-       if (r != ARCHIVE_OK) {
-               release_file(iso9660, file);
+       if (r != ARCHIVE_OK)
                return (r);
-       }
 
        iso9660->entry_bytes_remaining = file->size;
        iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
@@ -1227,7 +1218,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
                    "File is beyond end-of-media: %s", file->name);
                iso9660->entry_bytes_remaining = 0;
                iso9660->entry_sparse_offset = 0;
-               release_file(iso9660, file);
                return (ARCHIVE_WARN);
        }
 
@@ -1263,7 +1253,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
                archive_entry_unset_size(entry);
                iso9660->entry_bytes_remaining = 0;
                iso9660->entry_sparse_offset = 0;
-               release_file(iso9660, file);
                return (ARCHIVE_OK);
        }
 
@@ -1291,7 +1280,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
                    file->offset, iso9660->current_position);
                iso9660->entry_bytes_remaining = 0;
                iso9660->entry_sparse_offset = 0;
-               release_file(iso9660, file);
                return (ARCHIVE_WARN);
        }
 
@@ -1331,8 +1319,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
                file->exposed = 1;
        }
 
-       release_file(iso9660, file);
-
        if (rd_r != ARCHIVE_OK)
                return (rd_r);
        return (ARCHIVE_OK);
@@ -1648,14 +1634,10 @@ static int
 archive_read_format_iso9660_cleanup(struct archive_read *a)
 {
        struct iso9660 *iso9660;
-       struct file_info *file;
        int r = ARCHIVE_OK;
 
        iso9660 = (struct iso9660 *)(a->format->data);
-       while ((file = cache_get_entry(iso9660)) != NULL)
-               release_file(iso9660, file);
-       while ((file = next_entry(iso9660)) != NULL)
-               release_file(iso9660, file);
+       release_files(iso9660);
        free(iso9660->read_ce_req.reqs);
        archive_string_free(&iso9660->pathname);
        archive_string_free(&iso9660->previous_pathname);
@@ -1736,8 +1718,6 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
        }
        memset(file, 0, sizeof(*file));
        file->parent = parent;
-       if (parent != NULL)
-               parent->refcount++;
        file->offset = iso9660->logical_block_size * (uint64_t)location;
        file->size = toi(isodirrec + DR_size_offset, DR_size_size);
        file->mtime = isodate7(isodirrec + DR_date_offset);
@@ -1869,8 +1849,6 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
                        rr_start += iso9660->suspOffset;
                        r = parse_rockridge(a, file, rr_start, rr_end);
                        if (r != ARCHIVE_OK) {
-                               if (parent != NULL)
-                                       parent->refcount--;
                                free(file);
                                return (NULL);
                        }
@@ -1908,6 +1886,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
                fprintf(stderr, "\n");
        }
 #endif
+       register_file(iso9660, file);
        return (file);
 }
 
@@ -2460,18 +2439,24 @@ parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,
        }
 }
 
+static void
+register_file(struct iso9660 *iso9660, struct file_info *file)
+{
+
+       file->use_next = iso9660->use_files;
+       iso9660->use_files = file;
+}
 
 static void
-release_file(struct iso9660 *iso9660, struct file_info *file)
+release_files(struct iso9660 *iso9660)
 {
-       struct file_info *parent;
        struct content *con, *connext;
+       struct file_info *file;
 
-       if (file == NULL)
-               return;
+       file = iso9660->use_files;
+       while (file != NULL) {
+               struct file_info *next = file->use_next;
 
-       if (file->refcount == 0) {
-               parent = file->parent;
                archive_string_free(&file->name);
                archive_string_free(&file->symlink);
                con = file->contents.first;
@@ -2481,10 +2466,7 @@ release_file(struct iso9660 *iso9660, struct file_info *file)
                        con = connext;
                }
                free(file);
-               if (parent != NULL) {
-                       parent->refcount--;
-                       release_file(iso9660, parent);
-               }
+               file = next;
        }
 }
 
@@ -2568,7 +2550,6 @@ next_cache_entry(struct iso9660 *iso9660)
                         * happen.
                         */
                        file->next = NULL;
-                       file->refcount++;
                        *empty_files.last = file;
                        empty_files.last = &(file->next);
                } else {
@@ -2611,7 +2592,6 @@ static inline void
 cache_add_entry(struct iso9660 *iso9660, struct file_info *file)
 {
        file->next = NULL;
-       file->refcount++;
        *iso9660->cache_files.last = file;
        iso9660->cache_files.last = &(file->next);
 }
@@ -2621,7 +2601,6 @@ cache_add_to_next_of_parent(struct iso9660 *iso9660, struct file_info *file)
 {
        file->next = file->parent->next;
        file->parent->next = file;
-       file->refcount++;
        if (iso9660->cache_files.last == &(file->parent->next))
                iso9660->cache_files.last = &(file->next);
 }
@@ -2633,7 +2612,6 @@ cache_get_entry(struct iso9660 *iso9660)
 
        if ((file = iso9660->cache_files.first) != NULL) {
                iso9660->cache_files.first = file->next;
-               file->refcount--;
                if (iso9660->cache_files.first == NULL)
                        iso9660->cache_files.last = &(iso9660->cache_files.first);
        }
@@ -2669,7 +2647,6 @@ heap_add_entry(struct heap_queue *heap, struct file_info *file, uint64_t key)
        }
 
        file_key = file->key = key;
-       file->refcount++;
 
        /*
         * Start with hole at end, walk it up tree to find insertion point.
@@ -2703,7 +2680,6 @@ heap_get_entry(struct heap_queue *heap)
         * The first file in the list is the earliest; we'll return this.
         */
        r = heap->files[0];
-       r->refcount--;
 
        /*
         * Move the last item in the heap to the root of the tree