tree-walk: use size_t consistently
authorJeff King <peff@peff.net>
Wed, 31 Jul 2019 04:38:18 +0000 (00:38 -0400)
committerJunio C Hamano <gitster@pobox.com>
Thu, 1 Aug 2019 20:06:40 +0000 (13:06 -0700)
We store and manipulate the cumulative traverse_info.pathlen as an
"int", which can overflow when we are fed ridiculously long pathnames
(e.g., ones at the edge of 2GB or 4GB, even if the individual tree entry
names are smaller than that). The results can be confusing, though
after some prodding I was not able to use this integer overflow to cause
an under-allocated buffer.

Let's consistently use size_t to generate and store these, and make
sure our addition doesn't overflow.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
tree-walk.c
tree-walk.h
unpack-trees.c
index 4610f77383527d38d58dfc2de9ccfa340f19d2f4..70f9eb5f1b449cfa59a871caa22010a7d9eae0a3 100644 (file)
@@ -168,7 +168,7 @@ int tree_entry_gently(struct tree_desc *desc, struct name_entry *entry)
 
 void setup_traverse_info(struct traverse_info *info, const char *base)
 {
-       int pathlen = strlen(base);
+       size_t pathlen = strlen(base);
        static struct traverse_info dummy;
 
        memset(info, 0, sizeof(*info));
@@ -184,7 +184,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
 char *make_traverse_path(char *path, const struct traverse_info *info,
                         const char *name, size_t namelen)
 {
-       int pathlen = info->pathlen;
+       size_t pathlen = info->pathlen;
 
        path[pathlen + namelen] = 0;
        for (;;) {
index baa2aa62c76ff326eaf5f134caf1c185558e662f..47bf85d28287d231362461b39cc1a07568e1303d 100644 (file)
@@ -60,7 +60,7 @@ struct traverse_info {
        size_t namelen;
        unsigned mode;
 
-       int pathlen;
+       size_t pathlen;
        struct pathspec *pathspec;
 
        unsigned long df_conflicts;
@@ -74,9 +74,9 @@ char *make_traverse_path(char *path, const struct traverse_info *info,
                         const char *name, size_t namelen);
 void setup_traverse_info(struct traverse_info *info, const char *base);
 
-static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
+static inline size_t traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
 {
-       return info->pathlen + tree_entry_len(n);
+       return st_add(info->pathlen, tree_entry_len(n));
 }
 
 /* in general, positive means "kind of interesting" */
index 26f971f7ffc9cae59a3b5c7b702c72b91cc63c59..8dbfb22770df155c734103872e91becf1777bd3c 100644 (file)
@@ -686,7 +686,7 @@ static int index_pos_by_traverse_info(struct name_entry *names,
                                      struct traverse_info *info)
 {
        struct unpack_trees_options *o = info->data;
-       int len = traverse_path_len(info, names);
+       size_t len = traverse_path_len(info, names);
        char *name = xmalloc(len + 1 /* slash */ + 1 /* NUL */);
        int pos;
 
@@ -814,7 +814,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
        newinfo.name = p->path;
        newinfo.namelen = p->pathlen;
        newinfo.mode = p->mode;
-       newinfo.pathlen += tree_entry_len(p) + 1;
+       newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
        newinfo.df_conflicts |= df_conflicts;
 
        /*
@@ -960,7 +960,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
        struct index_state *istate,
        int is_transient)
 {
-       int len = traverse_path_len(info, n);
+       size_t len = traverse_path_len(info, n);
        struct cache_entry *ce =
                is_transient ?
                make_empty_transient_cache_entry(len) :