diff options
author | Junio C Hamano <gitster@pobox.com> | 2009-11-20 23:44:35 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2009-11-20 23:44:35 -0800 |
commit | 1b8dbdb41e503f6829be4e1d8ada4c8eabbc49bd (patch) | |
tree | 1281bbf5a21e3381efde6ca8866c0cd17aecea25 /remote.c | |
parent | 7a0d61bb45055cacf85111e7c48dfb9054b0abb0 (diff) | |
parent | 95c96d48e65a597cfd2bf7228ddc8c7ca30b55b7 (diff) | |
download | git-1b8dbdb41e503f6829be4e1d8ada4c8eabbc49bd.tar.gz |
Merge branch 'jp/fetch-cull-many-refs'
* jp/fetch-cull-many-refs:
remote: fix use-after-free error detected by glibc in ref_remove_duplicates
fetch: Speed up fetch of large numbers of refs
remote: Make ref_remove_duplicates faster for large numbers of refs
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 43 |
1 files changed, 24 insertions, 19 deletions
@@ -6,6 +6,7 @@ #include "revision.h" #include "dir.h" #include "tag.h" +#include "string-list.h" static struct refspec s_tag_refspec = { 0, @@ -734,29 +735,33 @@ int for_each_remote(each_remote_fn fn, void *priv) void ref_remove_duplicates(struct ref *ref_map) { - struct ref **posn; - struct ref *next; - for (; ref_map; ref_map = ref_map->next) { + struct string_list refs = { NULL, 0, 0, 0 }; + struct string_list_item *item = NULL; + struct ref *prev = NULL, *next = NULL; + for (; ref_map; prev = ref_map, ref_map = next) { + next = ref_map->next; if (!ref_map->peer_ref) continue; - posn = &ref_map->next; - while (*posn) { - if ((*posn)->peer_ref && - !strcmp((*posn)->peer_ref->name, - ref_map->peer_ref->name)) { - if (strcmp((*posn)->name, ref_map->name)) - die("%s tracks both %s and %s", - ref_map->peer_ref->name, - (*posn)->name, ref_map->name); - next = (*posn)->next; - free((*posn)->peer_ref); - free(*posn); - *posn = next; - } else { - posn = &(*posn)->next; - } + + item = string_list_lookup(ref_map->peer_ref->name, &refs); + if (item) { + if (strcmp(((struct ref *)item->util)->name, + ref_map->name)) + die("%s tracks both %s and %s", + ref_map->peer_ref->name, + ((struct ref *)item->util)->name, + ref_map->name); + prev->next = ref_map->next; + free(ref_map->peer_ref); + free(ref_map); + ref_map = prev; /* skip this; we freed it */ + continue; } + + item = string_list_insert(ref_map->peer_ref->name, &refs); + item->util = ref_map; } + string_list_clear(&refs, 0); } int remote_has_url(struct remote *remote, const char *url) |