From: Sven Verdoolaege <skimo@xxxxxxxxxx> If the function called by for_each_ref modifies a ref in any way, the cached_refs that for_each_ref was looping over would be removed, resulting in undefined behavior. This patch prevents the cached_refs from being removed while for_each_ref is still iterating over them. Signed-off-by: Sven Verdoolaege <skimo@xxxxxxxxxx> --- refs.c | 37 +++++++++++++++++++++++++++++++++---- 1 files changed, 33 insertions(+), 4 deletions(-) diff --git a/refs.c b/refs.c index 4dc7e8b..e710903 100644 --- a/refs.c +++ b/refs.c @@ -153,6 +153,8 @@ static struct ref_list *sort_ref_list(struct ref_list *list) static struct cached_refs { char did_loose; char did_packed; + char is_locked; + char is_invalidated; struct ref_list *loose; struct ref_list *packed; } cached_refs; @@ -170,6 +172,11 @@ static void invalidate_cached_refs(void) { struct cached_refs *ca = &cached_refs; + if (ca->is_locked) { + ca->is_invalidated = 1; + return; + } + if (ca->did_loose && ca->loose) free_ref_list(ca->loose); if (ca->did_packed && ca->packed) @@ -178,6 +185,24 @@ static void invalidate_cached_refs(void) ca->did_loose = ca->did_packed = 0; } +static void lock_cached_refs(void) +{ + struct cached_refs *ca = &cached_refs; + + ca->is_locked = 1; +} + +static void unlock_cached_refs(void) +{ + struct cached_refs *ca = &cached_refs; + + ca->is_locked = 0; + if (ca->is_invalidated) { + invalidate_cached_refs(); + ca->is_invalidated = 0; + } +} + static void read_packed_refs(FILE *f, struct cached_refs *cached_refs) { struct ref_list *list = NULL; @@ -518,10 +543,12 @@ int peel_ref(const char *ref, unsigned char *sha1) static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, void *cb_data) { - int retval; + int retval = 0; struct ref_list *packed = get_packed_refs(); struct ref_list *loose = get_loose_refs(); + lock_cached_refs(); + while (packed && loose) { struct ref_list *entry; int cmp = strcmp(packed->name, loose->name); @@ -538,15 +565,17 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, } retval = do_one_ref(base, fn, trim, cb_data, entry); if (retval) - return retval; + goto out; } for (packed = packed ? packed : loose; packed; packed = packed->next) { retval = do_one_ref(base, fn, trim, cb_data, packed); if (retval) - return retval; + goto out; } - return 0; + out: + unlock_cached_refs(); + return retval; } int head_ref(each_ref_fn fn, void *cb_data) -- 1.5.3.rc0.100.ge60b4 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html