Merge branch 'ma/bisect-leakfix'
authorJunio C Hamano <gitster@pobox.com>
Wed, 15 Nov 2017 03:14:28 +0000 (12:14 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 15 Nov 2017 03:14:28 +0000 (12:14 +0900)
Leak fixes.

* ma/bisect-leakfix:
bisect: fix memory leak when returning best element
bisect: fix off-by-one error in `best_bisection_sorted()`
bisect: fix memory leak in `find_bisection()`
bisect: change calling-convention of `find_bisection()`

1  2 
bisect.c
bisect.h
builtin/rev-list.c
diff --combined bisect.c
index fda2c4a186e8a937a53a4114bb24f3196b8b941b,3756f127b0fbaee3959011dbcd2beebbf067c5af..de551c6d5ecef5cfb9d04e836854750ef08741c4
+++ b/bisect.c
@@@ -226,10 -226,11 +226,11 @@@ static struct commit_list *best_bisecti
                add_name_decoration(DECORATION_NONE, buf.buf, obj);
  
                p->item = array[i].commit;
-               p = p->next;
+               if (i < cnt - 1)
+                       p = p->next;
        }
-       if (p)
-               p->next = NULL;
+       free_commit_list(p->next);
+       p->next = NULL;
        strbuf_release(&buf);
        free(array);
        return list;
@@@ -360,28 -361,29 +361,29 @@@ static struct commit_list *do_find_bise
                return best_bisection_sorted(list, nr);
  }
  
- struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all,
-                                         int find_all)
+ void find_bisection(struct commit_list **commit_list, int *reaches,
+                   int *all, int find_all)
  {
        int nr, on_list;
-       struct commit_list *p, *best, *next, *last;
+       struct commit_list *list, *p, *best, *next, *last;
        int *weights;
  
-       show_list("bisection 2 entry", 0, 0, list);
+       show_list("bisection 2 entry", 0, 0, *commit_list);
  
        /*
         * Count the number of total and tree-changing items on the
         * list, while reversing the list.
         */
-       for (nr = on_list = 0, last = NULL, p = list;
+       for (nr = on_list = 0, last = NULL, p = *commit_list;
             p;
             p = next) {
                unsigned flags = p->item->object.flags;
  
                next = p->next;
-               if (flags & UNINTERESTING)
+               if (flags & UNINTERESTING) {
+                       free(p);
                        continue;
+               }
                p->next = last;
                last = p;
                if (!(flags & TREESAME))
        /* Do the real work of finding bisection commit. */
        best = do_find_bisection(list, nr, weights, find_all);
        if (best) {
-               if (!find_all)
+               if (!find_all) {
+                       list->item = best->item;
+                       free_commit_list(list->next);
+                       best = list;
                        best->next = NULL;
+               }
                *reaches = weight(best);
        }
        free(weights);
-       return best;
+       *commit_list = best;
  }
  
  static int register_ref(const char *refname, const struct object_id *oid,
@@@ -433,12 -439,7 +439,12 @@@ static int read_bisect_refs(void
  
  static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
  static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 +static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 +static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 +static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 +static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
  static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 +static GIT_PATH_FUNC(git_path_head_name, "head-name")
  
  static void read_bisect_paths(struct argv_array *array)
  {
@@@ -690,12 -691,11 +696,12 @@@ static int bisect_checkout(const struc
        char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
  
        memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
 -      update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 +      update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
  
        argv_checkout[2] = bisect_rev_hex;
        if (no_checkout) {
 -              update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 +              update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0,
 +                         UPDATE_REFS_DIE_ON_ERR);
        } else {
                int res;
                res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@@@ -960,8 -960,7 +966,7 @@@ int bisect_next_all(const char *prefix
  
        bisect_common(&revs);
  
-       revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                      !!skipped_revs.nr);
+       find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
        revs.commits = managed_skipped(revs.commits, &tried);
  
        if (!revs.commits) {
@@@ -1050,40 -1049,3 +1055,40 @@@ int estimate_bisect_steps(int all
  
        return (e < 3 * x) ? n : n - 1;
  }
 +
 +static int mark_for_removal(const char *refname, const struct object_id *oid,
 +                          int flag, void *cb_data)
 +{
 +      struct string_list *refs = cb_data;
 +      char *ref = xstrfmt("refs/bisect%s", refname);
 +      string_list_append(refs, ref);
 +      return 0;
 +}
 +
 +int bisect_clean_state(void)
 +{
 +      int result = 0;
 +
 +      /* There may be some refs packed during bisection */
 +      struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
 +      for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
 +      string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
 +      result = delete_refs("bisect: remove", &refs_for_removal, REF_NODEREF);
 +      refs_for_removal.strdup_strings = 1;
 +      string_list_clear(&refs_for_removal, 0);
 +      unlink_or_warn(git_path_bisect_expected_rev());
 +      unlink_or_warn(git_path_bisect_ancestors_ok());
 +      unlink_or_warn(git_path_bisect_log());
 +      unlink_or_warn(git_path_bisect_names());
 +      unlink_or_warn(git_path_bisect_run());
 +      unlink_or_warn(git_path_bisect_terms());
 +      /* Cleanup head-name if it got left by an old version of git-bisect */
 +      unlink_or_warn(git_path_head_name());
 +      /*
 +       * Cleanup BISECT_START last to support the --no-checkout option
 +       * introduced in the commit 4796e823a.
 +       */
 +      unlink_or_warn(git_path_bisect_start());
 +
 +      return result;
 +}
diff --combined bisect.h
index 0ae63d4616dc69712faff17930e39d4c521927e5,c535e6d12e434a36569c18da81ea9cf916393363..a5d9248a47675194e7e0d16aed37018cbb67eb33
+++ b/bisect.h
@@@ -1,9 -1,15 +1,15 @@@
  #ifndef BISECT_H
  #define BISECT_H
  
- extern struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all,
-                                         int find_all);
+ /*
+  * Find bisection. If something is found, `reaches` will be the number of
+  * commits that the best commit reaches. `all` will be the count of
+  * non-SAMETREE commits. If nothing is found, `list` will be NULL.
+  * Otherwise, it will be either all non-SAMETREE commits or the single
+  * best commit, as chosen by `find_all`.
+  */
+ extern void find_bisection(struct commit_list **list, int *reaches, int *all,
+                          int find_all);
  
  extern struct commit_list *filter_skipped(struct commit_list *list,
                                          struct commit_list **tried,
@@@ -28,6 -34,4 +34,6 @@@ extern int estimate_bisect_steps(int al
  
  extern void read_bisect_terms(const char **bad, const char **good);
  
 +extern int bisect_clean_state(void);
 +
  #endif
diff --combined builtin/rev-list.c
index 8034d2eff24eb17b230fdbc28e8c02783e7fb53e,fb1c36af6abef0b6169348381e712883bba7e1b3..4032eb381158942b83e9ce12a5c984fceb239b20
@@@ -258,14 -258,14 +258,14 @@@ static int show_bisect_vars(struct rev_
  }
  
  static int show_object_fast(
 -      const unsigned char *sha1,
 +      const struct object_id *oid,
        enum object_type type,
        int exclude,
        uint32_t name_hash,
        struct packed_git *found_pack,
        off_t found_offset)
  {
 -      fprintf(stdout, "%s\n", sha1_to_hex(sha1));
 +      fprintf(stdout, "%s\n", oid_to_hex(oid));
        return 1;
  }
  
@@@ -294,7 -294,7 +294,7 @@@ int cmd_rev_list(int argc, const char *
        if (revs.bisect)
                bisect_list = 1;
  
 -      if (DIFF_OPT_TST(&revs.diffopt, QUICK))
 +      if (revs.diffopt.flags.quick)
                info.flags |= REV_LIST_QUIET;
        for (i = 1 ; i < argc; i++) {
                const char *arg = argv[i];
        if (bisect_list) {
                int reaches = reaches, all = all;
  
-               revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                             bisect_find_all);
+               find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
  
                if (bisect_show_vars)
                        return show_bisect_vars(&info, reaches, all);