Merge branch 'jk/path-name-safety-2.5' into jk/path-name-safety-2.6
authorJunio C Hamano <gitster@pobox.com>
Wed, 16 Mar 2016 17:42:02 +0000 (10:42 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Mar 2016 17:42:02 +0000 (10:42 -0700)
* jk/path-name-safety-2.5:
list-objects: pass full pathname to callbacks
list-objects: drop name_path entirely
list-objects: convert name_path to a strbuf
show_object_with_name: simplify by using path_name()
http-push: stop using name_path
tree-diff: catch integer overflow in combine_diff_path allocation
add helpers for detecting size_t overflow

1  2 
builtin/pack-objects.c
diff.h
git-compat-util.h
reachable.c
revision.c
revision.h
diff --combined builtin/pack-objects.c
index 1c63f8f28c7d925ee5647f190d236e64fc6e05a2,53307d53b00812a40b2958aa01bff3ccca6f6298..676727e1c6fadfb40d4c6586167ec9ca87970c46
@@@ -25,8 -25,8 +25,8 @@@
  #include "argv-array.h"
  
  static const char *pack_usage[] = {
 -      N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
 -      N_("git pack-objects [options...] base-name [< ref-list | < object-list]"),
 +      N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
 +      N_("git pack-objects [<options>...] <base-name> [< <ref-list> | < <object-list>]"),
        NULL
  };
  
@@@ -2284,21 -2284,11 +2284,11 @@@ static void show_commit(struct commit *
                index_commit_for_bitmap(commit);
  }
  
- static void show_object(struct object *obj,
-                       const struct name_path *path, const char *last,
-                       void *data)
+ static void show_object(struct object *obj, const char *name, void *data)
  {
-       char *name = path_name(path, last);
        add_preferred_base_object(name);
        add_object_entry(obj->sha1, obj->type, name, 0);
        obj->flags |= OBJECT_ADDED;
-       /*
-        * We will have generated the hash from the name,
-        * but not saved a pointer to it - we can free it
-        */
-       free((char *)name);
  }
  
  static void show_edge(struct commit *commit)
@@@ -2480,8 -2470,7 +2470,7 @@@ static int get_object_list_from_bitmap(
  }
  
  static void record_recent_object(struct object *obj,
-                                const struct name_path *path,
-                                const char *last,
+                                const char *name,
                                 void *data)
  {
        sha1_array_append(&recent_objects, obj->sha1);
@@@ -2588,6 -2577,23 +2577,6 @@@ static int option_parse_unpack_unreacha
        return 0;
  }
  
 -static int option_parse_ulong(const struct option *opt,
 -                            const char *arg, int unset)
 -{
 -      if (unset)
 -              die(_("option %s does not accept negative form"),
 -                  opt->long_name);
 -
 -      if (!git_parse_ulong(arg, opt->value))
 -              die(_("unable to parse value '%s' for option %s"),
 -                  arg, opt->long_name);
 -      return 0;
 -}
 -
 -#define OPT_ULONG(s, l, v, h) \
 -      { OPTION_CALLBACK, (s), (l), (v), "n", (h),     \
 -        PARSE_OPT_NONEG, option_parse_ulong }
 -
  int cmd_pack_objects(int argc, const char **argv, const char *prefix)
  {
        int use_internal_rev_list = 0;
                { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
                  N_("write the pack index file in the specified idx format version"),
                  0, option_parse_index_version },
 -              OPT_ULONG(0, "max-pack-size", &pack_size_limit,
 -                        N_("maximum size of each output pack file")),
 +              OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
 +                            N_("maximum size of each output pack file")),
                OPT_BOOL(0, "local", &local,
                         N_("ignore borrowed objects from alternate object store")),
                OPT_BOOL(0, "incremental", &incremental,
                         N_("ignore packed objects")),
                OPT_INTEGER(0, "window", &window,
                            N_("limit pack window by objects")),
 -              OPT_ULONG(0, "window-memory", &window_memory_limit,
 -                        N_("limit pack window by memory in addition to object limit")),
 +              OPT_MAGNITUDE(0, "window-memory", &window_memory_limit,
 +                            N_("limit pack window by memory in addition to object limit")),
                OPT_INTEGER(0, "depth", &depth,
                            N_("maximum length of delta chain allowed in the resulting pack")),
                OPT_BOOL(0, "reuse-delta", &reuse_delta,
diff --combined diff.h
index f7208ad103d4b81194e5b14e7e027a2d25388667,37e43bc537fac4044d528a64f2dd7fd26a7353af..c6b66d5a201fc6d4b93d1602a95b6facd79994ff
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -91,7 -91,6 +91,7 @@@ typedef struct strbuf *(*diff_prefix_fn
  #define DIFF_OPT_DIRSTAT_BY_LINE     (1 << 28)
  #define DIFF_OPT_FUNCCONTEXT         (1 << 29)
  #define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
 +#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1 << 31)
  
  #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
  #define DIFF_OPT_TOUCHED(opts, flag)    ((opts)->touched_flags & DIFF_OPT_##flag)
@@@ -222,8 -221,8 +222,8 @@@ struct combine_diff_path 
        } parent[FLEX_ARRAY];
  };
  #define combine_diff_path_size(n, l) \
-       (sizeof(struct combine_diff_path) + \
-        sizeof(struct combine_diff_parent) * (n) + (l) + 1)
+       st_add4(sizeof(struct combine_diff_path), (l), 1, \
+               st_mult(sizeof(struct combine_diff_parent), (n)))
  
  extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
                              int dense, struct rev_info *);
diff --combined git-compat-util.h
index 0feeae298340afbe22276ce595de4a6cba397926,d20fa89d5f32e0c76c7a9e6f77d91be6cb0d9f09..f035363ba6047c20e76dd9532521c0852a7d6b1f
  #define unsigned_add_overflows(a, b) \
      ((b) > maximum_unsigned_value_of_type(a) - (a))
  
+ /*
+  * Returns true if the multiplication of "a" and "b" will
+  * overflow. The types of "a" and "b" must match and must be unsigned.
+  * Note that this macro evaluates "a" twice!
+  */
+ #define unsigned_mult_overflows(a, b) \
+     ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
  #ifdef __GNUC__
  #define TYPEOF(x) (__typeof__(x))
  #else
@@@ -296,10 -304,6 +304,10 @@@ extern char *gitbasename(char *)
  #define PRIuMAX "llu"
  #endif
  
 +#ifndef SCNuMAX
 +#define SCNuMAX PRIuMAX
 +#endif
 +
  #ifndef PRIu32
  #define PRIu32 "u"
  #endif
@@@ -572,7 -576,7 +580,7 @@@ extern int git_lstat(const char *, stru
  #endif
  
  #define DEFAULT_PACKED_GIT_LIMIT \
 -      ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
 +      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256))
  
  #ifdef NO_PREAD
  #define pread git_pread
@@@ -703,6 -707,32 +711,32 @@@ extern void release_pack_memory(size_t)
  typedef void (*try_to_free_t)(size_t);
  extern try_to_free_t set_try_to_free_routine(try_to_free_t);
  
+ static inline size_t st_add(size_t a, size_t b)
+ {
+       if (unsigned_add_overflows(a, b))
+               die("size_t overflow: %"PRIuMAX" + %"PRIuMAX,
+                   (uintmax_t)a, (uintmax_t)b);
+       return a + b;
+ }
+ #define st_add3(a,b,c)   st_add((a),st_add((b),(c)))
+ #define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))
+ static inline size_t st_mult(size_t a, size_t b)
+ {
+       if (unsigned_mult_overflows(a, b))
+               die("size_t overflow: %"PRIuMAX" * %"PRIuMAX,
+                   (uintmax_t)a, (uintmax_t)b);
+       return a * b;
+ }
+ static inline size_t st_sub(size_t a, size_t b)
+ {
+       if (a < b)
+               die("size_t underflow: %"PRIuMAX" - %"PRIuMAX,
+                   (uintmax_t)a, (uintmax_t)b);
+       return a - b;
+ }
  #ifdef HAVE_ALLOCA_H
  # include <alloca.h>
  # define xalloca(size)      (alloca(size))
@@@ -721,12 -751,10 +755,12 @@@ extern void *xrealloc(void *ptr, size_
  extern void *xcalloc(size_t nmemb, size_t size);
  extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
  extern void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset);
 +extern int xopen(const char *path, int flags, ...);
  extern ssize_t xread(int fd, void *buf, size_t len);
  extern ssize_t xwrite(int fd, const void *buf, size_t len);
  extern ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
  extern int xdup(int fd);
 +extern FILE *xfopen(const char *path, const char *mode);
  extern FILE *xfdopen(int fd, const char *mode);
  extern int xmkstemp(char *template);
  extern int xmkstemp_mode(char *template, int mode);
@@@ -923,6 -951,9 +957,6 @@@ int access_or_die(const char *path, in
  /* Warn on an inaccessible file that ought to be accessible */
  void warn_on_inaccessible(const char *path);
  
 -/* Get the passwd entry for the UID of the current process. */
 -struct passwd *xgetpwuid_self(void);
 -
  #ifdef GMTIME_UNRELIABLE_ERRORS
  struct tm *git_gmtime(const time_t *);
  struct tm *git_gmtime_r(const time_t *, struct tm *);
diff --combined reachable.c
index 43616d49c7f88166d2fa2f009ca5b926d751ab0b,59196253a60c03a622276279788e642fe36f076b..ed352018964ef2260f5da51239800bbcc816ad1b
@@@ -25,15 -25,9 +25,15 @@@ static void update_progress(struct conn
  static int add_one_ref(const char *path, const struct object_id *oid,
                       int flag, void *cb_data)
  {
 -      struct object *object = parse_object_or_die(oid->hash, path);
        struct rev_info *revs = (struct rev_info *)cb_data;
 +      struct object *object;
  
 +      if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
 +              warning("symbolic ref is dangling: %s", path);
 +              return 0;
 +      }
 +
 +      object = parse_object_or_die(oid->hash, path);
        add_pending_object(revs, object, "");
  
        return 0;
   * The traversal will have already marked us as SEEN, so we
   * only need to handle any progress reporting here.
   */
- static void mark_object(struct object *obj, const struct name_path *path,
-                       const char *name, void *data)
+ static void mark_object(struct object *obj, const char *name, void *data)
  {
        update_progress(data);
  }
  
  static void mark_commit(struct commit *c, void *data)
  {
-       mark_object(&c->object, NULL, NULL, data);
+       mark_object(&c->object, NULL, data);
  }
  
  struct recent_data {
diff --combined revision.c
index e0107738b7ad4faa8c5937f4589d306382d65030,8f30ab1e46b4a07148b7dfe0e8f7950fd241c325..8435ce5256217536214136767e19017671f0bd17
  #include "commit-slab.h"
  #include "dir.h"
  #include "cache-tree.h"
 +#include "bisect.h"
  
  volatile show_early_output_fn_t show_early_output;
  
- char *path_name(const struct name_path *path, const char *name)
 +static const char *term_bad;
 +static const char *term_good;
 +
+ void show_object_with_name(FILE *out, struct object *obj, const char *name)
  {
-       const struct name_path *p;
-       char *n, *m;
-       int nlen = strlen(name);
-       int len = nlen + 1;
-       for (p = path; p; p = p->up) {
-               if (p->elem_len)
-                       len += p->elem_len + 1;
-       }
-       n = xmalloc(len);
-       m = n + len - (nlen + 1);
-       strcpy(m, name);
-       for (p = path; p; p = p->up) {
-               if (p->elem_len) {
-                       m -= p->elem_len + 1;
-                       memcpy(m, p->elem, p->elem_len);
-                       m[p->elem_len] = '/';
-               }
-       }
-       return n;
- }
- static int show_path_component_truncated(FILE *out, const char *name, int len)
- {
-       int cnt;
-       for (cnt = 0; cnt < len; cnt++) {
-               int ch = name[cnt];
-               if (!ch || ch == '\n')
-                       return -1;
-               fputc(ch, out);
-       }
-       return len;
- }
- static int show_path_truncated(FILE *out, const struct name_path *path)
- {
-       int emitted, ours;
-       if (!path)
-               return 0;
-       emitted = show_path_truncated(out, path->up);
-       if (emitted < 0)
-               return emitted;
-       if (emitted)
-               fputc('/', out);
-       ours = show_path_component_truncated(out, path->elem, path->elem_len);
-       if (ours < 0)
-               return ours;
-       return ours || emitted;
- }
- void show_object_with_name(FILE *out, struct object *obj,
-                          const struct name_path *path, const char *component)
- {
-       struct name_path leaf;
-       leaf.up = (struct name_path *)path;
-       leaf.elem = component;
-       leaf.elem_len = strlen(component);
+       const char *p;
  
        fprintf(out, "%s ", sha1_to_hex(obj->sha1));
-       show_path_truncated(out, &leaf);
+       for (p = name; *p && *p != '\n'; p++)
+               fputc(*p, out);
        fputc('\n', out);
  }
  
@@@ -135,12 -75,10 +79,12 @@@ static void mark_tree_contents_unintere
  
  void mark_tree_uninteresting(struct tree *tree)
  {
 -      struct object *obj = &tree->object;
 +      struct object *obj;
  
        if (!tree)
                return;
 +
 +      obj = &tree->object;
        if (obj->flags & UNINTERESTING)
                return;
        obj->flags |= UNINTERESTING;
@@@ -155,7 -93,10 +99,7 @@@ void mark_parents_uninteresting(struct 
                commit_list_insert(l->item, &parents);
  
        while (parents) {
 -              struct commit *commit = parents->item;
 -              l = parents;
 -              parents = parents->next;
 -              free(l);
 +              struct commit *commit = pop_commit(&parents);
  
                while (commit) {
                        /*
@@@ -294,8 -235,9 +238,8 @@@ static struct commit *handle_commit(str
                /*
                 * We'll handle the tagged object by looping or dropping
                 * through to the non-tag handlers below. Do not
 -               * propagate data from the tag's pending entry.
 +               * propagate path data from the tag's pending entry.
                 */
 -              name = "";
                path = NULL;
                mode = 0;
        }
@@@ -1100,10 -1042,14 +1044,10 @@@ static int limit_list(struct rev_info *
        }
  
        while (list) {
 -              struct commit_list *entry = list;
 -              struct commit *commit = list->item;
 +              struct commit *commit = pop_commit(&list);
                struct object *obj = &commit->object;
                show_early_output_fn_t show;
  
 -              list = list->next;
 -              free(entry);
 -
                if (commit == interesting_cache)
                        interesting_cache = NULL;
  
@@@ -1994,10 -1940,10 +1938,10 @@@ static int handle_revision_opt(struct r
        } else if (!strcmp(arg, "--full-history")) {
                revs->simplify_history = 0;
        } else if (!strcmp(arg, "--relative-date")) {
 -              revs->date_mode = DATE_RELATIVE;
 +              revs->date_mode.type = DATE_RELATIVE;
                revs->date_mode_explicit = 1;
        } else if ((argcount = parse_long_opt("date", argv, &optarg))) {
 -              revs->date_mode = parse_date_format(optarg);
 +              parse_date_format(optarg, &revs->date_mode);
                revs->date_mode_explicit = 1;
                return argcount;
        } else if (!strcmp(arg, "--log-size")) {
@@@ -2074,23 -2020,14 +2018,23 @@@ void parse_revision_opt(struct rev_inf
        ctx->argc -= n;
  }
  
 +static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {
 +      struct strbuf bisect_refs = STRBUF_INIT;
 +      int status;
 +      strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
 +      status = for_each_ref_in_submodule(submodule, bisect_refs.buf, fn, cb_data);
 +      strbuf_release(&bisect_refs);
 +      return status;
 +}
 +
  static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
  {
 -      return for_each_ref_in_submodule(submodule, "refs/bisect/bad", fn, cb_data);
 +      return for_each_bisect_ref(submodule, fn, cb_data, term_bad);
  }
  
  static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
  {
 -      return for_each_ref_in_submodule(submodule, "refs/bisect/good", fn, cb_data);
 +      return for_each_bisect_ref(submodule, fn, cb_data, term_good);
  }
  
  static int handle_revision_pseudo_opt(const char *submodule,
                handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
                clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--bisect")) {
 +              read_bisect_terms(&term_bad, &term_good);
                handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
                handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
                revs->bisect = 1;
@@@ -2727,7 -2663,10 +2671,7 @@@ static void simplify_merges(struct rev_
                yet_to_do = NULL;
                tail = &yet_to_do;
                while (list) {
 -                      commit = list->item;
 -                      next = list->next;
 -                      free(list);
 -                      list = next;
 +                      commit = pop_commit(&list);
                        tail = simplify_one(revs, commit, tail);
                }
        }
        while (list) {
                struct merge_simplify_state *st;
  
 -              commit = list->item;
 -              next = list->next;
 -              free(list);
 -              list = next;
 +              commit = pop_commit(&list);
                st = locate_simplify_state(revs, commit);
                if (st->simplified == commit)
                        tail = &commit_list_insert(commit, tail)->next;
@@@ -3113,7 -3055,11 +3057,7 @@@ static struct commit *get_revision_1(st
                return NULL;
  
        do {
 -              struct commit_list *entry = revs->commits;
 -              struct commit *commit = entry->item;
 -
 -              revs->commits = entry->next;
 -              free(entry);
 +              struct commit *commit = pop_commit(&revs->commits);
  
                if (revs->reflog_info) {
                        save_parents(revs, commit);
diff --combined revision.h
index 5bc9686846045182c3d2393a98e3018df2f05af4,1b58aacc03bd330ebf70ee71aac0d38fd18743c7..974130280120d11781c2ea5e7fda84e3d12f80c8
@@@ -146,7 -146,7 +146,7 @@@ struct rev_info 
                        track_first_time:1,
                        linear:1;
  
 -      enum date_mode date_mode;
 +      struct date_mode date_mode;
  
        unsigned int    abbrev;
        enum cmit_fmt   commit_format;
@@@ -256,16 -256,9 +256,9 @@@ extern void put_revision_mark(const str
  extern void mark_parents_uninteresting(struct commit *commit);
  extern void mark_tree_uninteresting(struct tree *tree);
  
- struct name_path {
-       struct name_path *up;
-       int elem_len;
-       const char *elem;
- };
- char *path_name(const struct name_path *path, const char *name);
+ char *path_name(struct strbuf *path, const char *name);
  
- extern void show_object_with_name(FILE *, struct object *,
-                                 const struct name_path *, const char *);
+ extern void show_object_with_name(FILE *, struct object *, const char *);
  
  extern void add_pending_object(struct rev_info *revs,
                               struct object *obj, const char *name);