Merge branch 'rs/fmt-merge-msg-string-leak-fix'
authorJunio C Hamano <gitster@pobox.com>
Wed, 27 Dec 2017 19:16:23 +0000 (11:16 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 27 Dec 2017 19:16:23 +0000 (11:16 -0800)
Leakfix.

* rs/fmt-merge-msg-string-leak-fix:
fmt-merge-msg: avoid leaking strbuf in shortlog()

1  2 
builtin/fmt-merge-msg.c
diff --combined builtin/fmt-merge-msg.c
index 22034f87e7f8c7fa1166d3731319aca610fef2a2,578a0a20e1e7248f916e0fe847481ff70c18187d..8e8a15ea4ad6de2bb73f63d39a0895a263918774
@@@ -1,6 -1,5 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
 +#include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "diff.h"
@@@ -42,7 -41,7 +42,7 @@@ struct src_data 
  };
  
  struct origin_data {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        unsigned is_local_branch:1;
  };
  
@@@ -60,8 -59,8 +60,8 @@@ static struct string_list origins = STR
  struct merge_parents {
        int alloc, nr;
        struct merge_parent {
 -              unsigned char given[20];
 -              unsigned char commit[20];
 +              struct object_id given;
 +              struct object_id commit;
                unsigned char used;
        } *item;
  };
   * hundreds of heads at a time anyway.
   */
  static struct merge_parent *find_merge_parent(struct merge_parents *table,
 -                                            unsigned char *given,
 -                                            unsigned char *commit)
 +                                            struct object_id *given,
 +                                            struct object_id *commit)
  {
        int i;
        for (i = 0; i < table->nr; i++) {
 -              if (given && hashcmp(table->item[i].given, given))
 +              if (given && oidcmp(&table->item[i].given, given))
                        continue;
 -              if (commit && hashcmp(table->item[i].commit, commit))
 +              if (commit && oidcmp(&table->item[i].commit, commit))
                        continue;
                return &table->item[i];
        }
  }
  
  static void add_merge_parent(struct merge_parents *table,
 -                           unsigned char *given,
 -                           unsigned char *commit)
 +                           struct object_id *given,
 +                           struct object_id *commit)
  {
        if (table->nr && find_merge_parent(table, given, commit))
                return;
        ALLOC_GROW(table->item, table->nr + 1, table->alloc);
 -      hashcpy(table->item[table->nr].given, given);
 -      hashcpy(table->item[table->nr].commit, commit);
 +      oidcpy(&table->item[table->nr].given, given);
 +      oidcpy(&table->item[table->nr].commit, commit);
        table->item[table->nr].used = 0;
        table->nr++;
  }
@@@ -107,30 -106,30 +107,30 @@@ static int handle_line(char *line, stru
        struct src_data *src_data;
        struct string_list_item *item;
        int pulling_head = 0;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
 -      if (len < 43 || line[40] != '\t')
 +      if (len < GIT_SHA1_HEXSZ + 3 || line[GIT_SHA1_HEXSZ] != '\t')
                return 1;
  
 -      if (starts_with(line + 41, "not-for-merge"))
 +      if (starts_with(line + GIT_SHA1_HEXSZ + 1, "not-for-merge"))
                return 0;
  
 -      if (line[41] != '\t')
 +      if (line[GIT_SHA1_HEXSZ + 1] != '\t')
                return 2;
  
 -      i = get_sha1_hex(line, sha1);
 +      i = get_oid_hex(line, &oid);
        if (i)
                return 3;
  
 -      if (!find_merge_parent(merge_parents, sha1, NULL))
 +      if (!find_merge_parent(merge_parents, &oid, NULL))
                return 0; /* subsumed by other parents */
  
        origin_data = xcalloc(1, sizeof(struct origin_data));
 -      hashcpy(origin_data->sha1, sha1);
 +      oidcpy(&origin_data->oid, &oid);
  
        if (line[len - 1] == '\n')
                line[len - 1] = 0;
 -      line += 42;
 +      line += GIT_SHA1_HEXSZ + 2;
  
        /*
         * At this point, line points at the beginning of comment e.g.
@@@ -339,10 -338,10 +339,10 @@@ static void shortlog(const char *name
        struct string_list committers = STRING_LIST_INIT_DUP;
        int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
        struct strbuf sb = STRBUF_INIT;
 -      const unsigned char *sha1 = origin_data->sha1;
 +      const struct object_id *oid = &origin_data->oid;
        int limit = opts->shortlog_len;
  
 -      branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
 +      branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ);
        if (!branch || branch->type != OBJ_COMMIT)
                return;
  
                        string_list_append(&subjects,
                                           oid_to_hex(&commit->object.oid));
                else
-                       string_list_append(&subjects, strbuf_detach(&sb, NULL));
+                       string_list_append_nodup(&subjects,
+                                                strbuf_detach(&sb, NULL));
        }
  
        if (opts->credit_people)
  }
  
  static void fmt_merge_msg_title(struct strbuf *out,
 -      const char *current_branch) {
 +                              const char *current_branch)
 +{
        int i = 0;
        char *sep = "";
  
@@@ -533,7 -532,7 +534,7 @@@ static void fmt_merge_msg_sigs(struct s
  }
  
  static void find_merge_parents(struct merge_parents *result,
 -                             struct strbuf *in, unsigned char *head)
 +                             struct strbuf *in, struct object_id *head)
  {
        struct commit_list *parents;
        struct commit *head_commit;
                int len;
                char *p = in->buf + pos;
                char *newline = strchr(p, '\n');
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct commit *parent;
                struct object *obj;
  
                len = newline ? newline - p : strlen(p);
                pos += len + !!newline;
  
 -              if (len < 43 ||
 -                  get_sha1_hex(p, sha1) ||
 -                  p[40] != '\t' ||
 -                  p[41] != '\t')
 +              if (len < GIT_SHA1_HEXSZ + 3 ||
 +                  get_oid_hex(p, &oid) ||
 +                  p[GIT_SHA1_HEXSZ] != '\t' ||
 +                  p[GIT_SHA1_HEXSZ + 1] != '\t')
                        continue; /* skip not-for-merge */
                /*
                 * Do not use get_merge_parent() here; we do not have
                 * "name" here and we do not want to contaminate its
                 * util field yet.
                 */
 -              obj = parse_object(sha1);
 +              obj = parse_object(&oid);
                parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
                if (!parent)
                        continue;
                commit_list_insert(parent, &parents);
 -              add_merge_parent(result, obj->oid.hash, parent->object.oid.hash);
 +              add_merge_parent(result, &obj->oid, &parent->object.oid);
        }
        head_commit = lookup_commit(head);
        if (head_commit)
                commit_list_insert(head_commit, &parents);
 -      parents = reduce_heads(parents);
 +      reduce_heads_replace(&parents);
  
        while (parents) {
                struct commit *cmit = pop_commit(&parents);
                for (i = 0; i < result->nr; i++)
 -                      if (!hashcmp(result->item[i].commit, cmit->object.oid.hash))
 +                      if (!oidcmp(&result->item[i].commit, &cmit->object.oid))
                                result->item[i].used = 1;
        }
  
@@@ -594,7 -593,7 +595,7 @@@ int fmt_merge_msg(struct strbuf *in, st
                  struct fmt_merge_msg_opts *opts)
  {
        int i = 0, pos = 0;
 -      unsigned char head_sha1[20];
 +      struct object_id head_oid;
        const char *current_branch;
        void *current_branch_to_free;
        struct merge_parents merge_parents;
  
        /* get current branch */
        current_branch = current_branch_to_free =
 -              resolve_refdup("HEAD", RESOLVE_REF_READING, head_sha1, NULL);
 +              resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL);
        if (!current_branch)
                die("No current branch");
        if (starts_with(current_branch, "refs/heads/"))
                current_branch += 11;
  
 -      find_merge_parents(&merge_parents, in, head_sha1);
 +      find_merge_parents(&merge_parents, in, &head_oid);
  
        /* get a line */
        while (pos < in->len) {
                struct commit *head;
                struct rev_info rev;
  
 -              head = lookup_commit_or_die(head_sha1, "HEAD");
 +              head = lookup_commit_or_die(&head_oid, "HEAD");
                init_revisions(&rev, NULL);
                rev.commit_format = CMIT_FMT_ONELINE;
                rev.ignore_merges = 1;