Merge branch 'ma/ref-filter-leakfix'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Jul 2019 18:30:23 +0000 (11:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Jul 2019 18:30:23 +0000 (11:30 -0700)
Leakfix.

* ma/ref-filter-leakfix:
ref-filter: fix memory leak in `free_array_item()`

1  2 
ref-filter.c
diff --combined ref-filter.c
index 56528caafd59c90de18b9fa951cf45d64712d59d,1c1a2af880b60bbb7d47c74c1d233b45577cf288..f27cfc8c3e358fa27d7aec78c0b3c44c816402b3
@@@ -22,7 -22,6 +22,7 @@@
  #include "commit-reach.h"
  #include "worktree.h"
  #include "hashmap.h"
 +#include "argv-array.h"
  
  static struct ref_msg {
        const char *gone;
@@@ -1864,62 -1863,21 +1864,62 @@@ static int filter_pattern_match(struct 
        return match_pattern(filter, refname);
  }
  
 -/*
 - * Find the longest prefix of pattern we can pass to
 - * `for_each_fullref_in()`, namely the part of pattern preceding the
 - * first glob character. (Note that `for_each_fullref_in()` is
 - * perfectly happy working with a prefix that doesn't end at a
 - * pathname component boundary.)
 - */
 -static void find_longest_prefix(struct strbuf *out, const char *pattern)
 +static int qsort_strcmp(const void *va, const void *vb)
 +{
 +      const char *a = *(const char **)va;
 +      const char *b = *(const char **)vb;
 +
 +      return strcmp(a, b);
 +}
 +
 +static void find_longest_prefixes_1(struct string_list *out,
 +                                struct strbuf *prefix,
 +                                const char **patterns, size_t nr)
  {
 -      const char *p;
 +      size_t i;
 +
 +      for (i = 0; i < nr; i++) {
 +              char c = patterns[i][prefix->len];
 +              if (!c || is_glob_special(c)) {
 +                      string_list_append(out, prefix->buf);
 +                      return;
 +              }
 +      }
 +
 +      i = 0;
 +      while (i < nr) {
 +              size_t end;
 +
 +              /*
 +              * Set "end" to the index of the element _after_ the last one
 +              * in our group.
 +              */
 +              for (end = i + 1; end < nr; end++) {
 +                      if (patterns[i][prefix->len] != patterns[end][prefix->len])
 +                              break;
 +              }
  
 -      for (p = pattern; *p && !is_glob_special(*p); p++)
 -              ;
 +              strbuf_addch(prefix, patterns[i][prefix->len]);
 +              find_longest_prefixes_1(out, prefix, patterns + i, end - i);
 +              strbuf_setlen(prefix, prefix->len - 1);
  
 -      strbuf_add(out, pattern, p - pattern);
 +              i = end;
 +      }
 +}
 +
 +static void find_longest_prefixes(struct string_list *out,
 +                                const char **patterns)
 +{
 +      struct argv_array sorted = ARGV_ARRAY_INIT;
 +      struct strbuf prefix = STRBUF_INIT;
 +
 +      argv_array_pushv(&sorted, patterns);
 +      QSORT(sorted.argv, sorted.argc, qsort_strcmp);
 +
 +      find_longest_prefixes_1(out, &prefix, sorted.argv, sorted.argc);
 +
 +      argv_array_clear(&sorted);
 +      strbuf_release(&prefix);
  }
  
  /*
@@@ -1932,8 -1890,7 +1932,8 @@@ static int for_each_fullref_in_pattern(
                                       void *cb_data,
                                       int broken)
  {
 -      struct strbuf prefix = STRBUF_INIT;
 +      struct string_list prefixes = STRING_LIST_INIT_DUP;
 +      struct string_list_item *prefix;
        int ret;
  
        if (!filter->match_as_path) {
                return for_each_fullref_in("", cb, cb_data, broken);
        }
  
 -      if (filter->name_patterns[1]) {
 -              /*
 -               * multiple patterns; in theory this could still work as long
 -               * as the patterns are disjoint. We'd just make multiple calls
 -               * to for_each_ref(). But if they're not disjoint, we'd end up
 -               * reporting the same ref multiple times. So let's punt on that
 -               * for now.
 -               */
 -              return for_each_fullref_in("", cb, cb_data, broken);
 -      }
 +      find_longest_prefixes(&prefixes, filter->name_patterns);
  
 -      find_longest_prefix(&prefix, filter->name_patterns[0]);
 +      for_each_string_list_item(prefix, &prefixes) {
 +              ret = for_each_fullref_in(prefix->string, cb, cb_data, broken);
 +              if (ret)
 +                      break;
 +      }
  
 -      ret = for_each_fullref_in(prefix.buf, cb, cb_data, broken);
 -      strbuf_release(&prefix);
 +      string_list_clear(&prefixes, 0);
        return ret;
  }
  
@@@ -2142,7 -2105,9 +2142,9 @@@ static void free_array_item(struct ref_
  {
        free((char *)item->symref);
        if (item->value) {
-               free((char *)item->value->s);
+               int i;
+               for (i = 0; i < used_atom_cnt; i++)
+                       free((char *)item->value[i].s);
                free(item->value);
        }
        free(item);
@@@ -2153,14 -2118,16 +2155,16 @@@ void ref_array_clear(struct ref_array *
  {
        int i;
  
-       for (i = 0; i < used_atom_cnt; i++)
-               free((char *)used_atom[i].name);
-       FREE_AND_NULL(used_atom);
-       used_atom_cnt = 0;
        for (i = 0; i < array->nr; i++)
                free_array_item(array->items[i]);
        FREE_AND_NULL(array->items);
        array->nr = array->alloc = 0;
+       for (i = 0; i < used_atom_cnt; i++)
+               free((char *)used_atom[i].name);
+       FREE_AND_NULL(used_atom);
+       used_atom_cnt = 0;
        if (ref_to_worktree_map.worktrees) {
                hashmap_free(&(ref_to_worktree_map.map), 1);
                free_worktrees(ref_to_worktree_map.worktrees);