Ok.. so there's been a couple attempts to patch the leak that were all
wrong due to mixed memory management for that array.  Here's a seed for
discussion on how to plug that leak.  Some would argue that it's not
leaking enough to fix, but for those that want to turn git into a library,
the lifetime of the cache could end up not being short any more, so it's
worth discussing how to fix it.

The q&d fix in this patch isn't elegant, but gets the job done.  More
interesting could be to have the entry itself contain a state bit, though
that wastes storage space.

Two basic changes:

1) introduce a set_active_cache() api and change all 'active_cache[i] = ce'
   calls to use it.
2) add a active_cache_malloced array to parallel the active_cache array.

I don't like #2, but see that q&d comment. :)

It's only lightly tested as I'm still trying to wrap my head around how to
actually use git and git-pasky.

I was tempted to add a get_cache_entry api as well, so that nothing
outside of read-cache.c touched active_cache directly, but that can come
next.

Later,
Brad

--- cache.h
+++ cache.h     2005-04-16 23:08:37.000000000 -0700
@@ -88,6 +88,7 @@
 extern int read_cache(void);
 extern int write_cache(int newfd, struct cache_entry **cache, int entries);
 extern int cache_name_pos(const char *name, int namelen);
+extern int set_cache_entry(struct cache_entry *ce, int pos, int 
malloced_entry);
 extern int add_cache_entry(struct cache_entry *ce, int ok_to_add);
 extern int remove_file_from_cache(char *path);
 extern int cache_match_stat(struct cache_entry *ce, struct stat *st);
--- read-cache.c
+++ read-cache.c        2005-04-16 23:32:34.000000000 -0700
@@ -8,6 +8,7 @@
 
 const char *sha1_file_directory = NULL;
 struct cache_entry **active_cache = NULL;
+static int * active_cache_malloced = NULL;
 unsigned int active_nr = 0, active_alloc = 0;
 
 void usage(const char *err)
@@ -381,6 +382,15 @@
        return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
+int set_cache_entry(struct cache_entry *ce, int pos, int malloced_entry)
+{
+       if (active_cache_malloced[pos])
+               free(active_cache[pos]);
+       active_cache[pos] = ce;
+       active_cache_malloced[pos] = malloced_entry;
+       return 0;
+}
+
 int add_cache_entry(struct cache_entry *ce, int ok_to_add)
 {
        int pos;
@@ -389,7 +399,7 @@
 
        /* existing match? Just replace it */
        if (pos >= 0) {
-               active_cache[pos] = ce;
+               set_cache_entry(ce, pos, 0);
                return 0;
        }
        pos = -pos-1;
@@ -414,13 +424,16 @@
        if (active_nr == active_alloc) {
                active_alloc = alloc_nr(active_alloc);
                active_cache = realloc(active_cache, active_alloc * 
sizeof(struct cache_entry *));
+               active_cache_malloced = realloc(active_cache, active_alloc * 
sizeof(int));
        }
 
        /* Add it in.. */
        active_nr++;
-       if (active_nr > pos)
+       if (active_nr > pos) {
                memmove(active_cache + pos + 1, active_cache + pos, (active_nr 
- pos - 1) * sizeof(ce));
-       active_cache[pos] = ce;
+               memmove(active_cache_malloced + pos + 1, active_cache_malloced 
+ pos, (active_nr - pos - 1) * sizeof(int));
+       }
+       set_cache_entry(ce, pos, 1);
        return 0;
 }
 
@@ -482,12 +495,13 @@
        active_nr = ntohl(hdr->hdr_entries);
        active_alloc = alloc_nr(active_nr);
        active_cache = calloc(active_alloc, sizeof(struct cache_entry *));
+       active_cache_malloced = calloc(active_alloc, sizeof(int));
 
        offset = sizeof(*hdr);
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = map + offset;
                offset = offset + ce_size(ce);
-               active_cache[i] = ce;
+               set_cache_entry(ce, i, 0);
        }
        return active_nr;
 
--- update-cache.c
+++ update-cache.c      2005-04-16 23:33:28.000000000 -0700
@@ -199,11 +199,14 @@
                struct cache_entry *ce = active_cache[i];
                struct cache_entry *new = refresh_entry(ce);
 
+               if (new == ce)
+                       continue;
+
                if (!new) {
                        printf("%s: needs update\n", ce->name);
                        continue;
                }
-               active_cache[i] = new;
+               set_cache_entry(new, i, 1);
        }
 }
 

Reply via email to