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); } }