Merge branch 'jk/avoid-unbounded-alloca' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 6 Jul 2016 20:06:39 +0000 (13:06 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 6 Jul 2016 20:06:39 +0000 (13:06 -0700)
A codepath that used alloca(3) to place an unbounded amount of data
on the stack has been updated to avoid doing so.

* jk/avoid-unbounded-alloca:
tree-diff: avoid alloca for large allocations

1  2 
tree-diff.c
diff --combined tree-diff.c
index ff4e0d3cb60b51080d2f6100e38d1476e6eb6dcf,286cab8177b421b971f9b864ce7dffd583af541e..ebf40f44faab9c41430c259132ca600d7810316b
   */
  #define S_IFXMIN_NEQ  S_DIFFTREE_IFXMIN_NEQ
  
+ #define FAST_ARRAY_ALLOC(x, nr) do { \
+       if ((nr) <= 2) \
+               (x) = xalloca((nr) * sizeof(*(x))); \
+       else \
+               ALLOC_ARRAY((x), nr); \
+ } while(0)
+ #define FAST_ARRAY_FREE(x, nr) do { \
+       if ((nr) > 2) \
+               free((x)); \
+ } while(0)
  
  static struct combine_diff_path *ll_diff_tree_paths(
        struct combine_diff_path *p, const unsigned char *sha1,
@@@ -64,7 -74,7 +74,7 @@@ static int emit_diff_first_parent_only(
  {
        struct combine_diff_parent *p0 = &p->parent[0];
        if (p->mode && p0->mode) {
 -              opt->change(opt, p0->mode, p->mode, p0->sha1, p->sha1,
 +              opt->change(opt, p0->mode, p->mode, p0->oid.hash, p->oid.hash,
                        1, 1, p->path, 0, 0);
        }
        else {
  
                if (p->mode) {
                        addremove = '+';
 -                      sha1 = p->sha1;
 +                      sha1 = p->oid.hash;
                        mode = p->mode;
                } else {
                        addremove = '-';
 -                      sha1 = p0->sha1;
 +                      sha1 = p0->oid.hash;
                        mode = p0->mode;
                }
  
@@@ -151,7 -161,7 +161,7 @@@ static struct combine_diff_path *path_a
        memcpy(p->path + base->len, path, pathlen);
        p->path[len] = 0;
        p->mode = mode;
 -      hashcpy(p->sha1, sha1 ? sha1 : null_sha1);
 +      hashcpy(p->oid.hash, sha1 ? sha1 : null_sha1);
  
        return p;
  }
@@@ -183,7 -193,7 +193,7 @@@ static struct combine_diff_path *emit_p
  
        if (t) {
                /* path present in resulting tree */
 -              sha1 = tree_entry_extract(t, &path, &mode);
 +              sha1 = tree_entry_extract(t, &path, &mode)->hash;
                pathlen = tree_entry_len(&t->entry);
                isdir = S_ISDIR(mode);
        } else {
                                                DIFF_STATUS_ADDED;
  
                        if (tpi_valid) {
 -                              sha1_i = tp[i].entry.sha1;
 +                              sha1_i = tp[i].entry.oid->hash;
                                mode_i = tp[i].entry.mode;
                        }
                        else {
                        }
  
                        p->parent[i].mode = mode_i;
 -                      hashcpy(p->parent[i].sha1, sha1_i ? sha1_i : null_sha1);
 +                      hashcpy(p->parent[i].oid.hash, sha1_i ? sha1_i : null_sha1);
                }
  
                keep = 1;
        if (recurse) {
                const unsigned char **parents_sha1;
  
-               parents_sha1 = xalloca(nparent * sizeof(parents_sha1[0]));
+               FAST_ARRAY_ALLOC(parents_sha1, nparent);
                for (i = 0; i < nparent; ++i) {
                        /* same rule as in emitthis */
                        int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
  
 -                      parents_sha1[i] = tpi_valid ? tp[i].entry.sha1
 +                      parents_sha1[i] = tpi_valid ? tp[i].entry.oid->hash
                                                    : NULL;
                }
  
                strbuf_add(base, path, pathlen);
                strbuf_addch(base, '/');
                p = ll_diff_tree_paths(p, sha1, parents_sha1, nparent, base, opt);
-               xalloca_free(parents_sha1);
+               FAST_ARRAY_FREE(parents_sha1, nparent);
        }
  
        strbuf_setlen(base, old_baselen);
@@@ -402,8 -412,8 +412,8 @@@ static struct combine_diff_path *ll_dif
        void *ttree, **tptree;
        int i;
  
-       tp     = xalloca(nparent * sizeof(tp[0]));
-       tptree = xalloca(nparent * sizeof(tptree[0]));
+       FAST_ARRAY_ALLOC(tp, nparent);
+       FAST_ARRAY_ALLOC(tptree, nparent);
  
        /*
         * load parents first, as they are probably already cached.
                                                continue;
  
                                        /* diff(t,pi) != ΓΈ */
 -                                      if (hashcmp(t.entry.sha1, tp[i].entry.sha1) ||
 +                                      if (oidcmp(t.entry.oid, tp[i].entry.oid) ||
                                            (t.entry.mode != tp[i].entry.mode))
                                                continue;
  
        free(ttree);
        for (i = nparent-1; i >= 0; i--)
                free(tptree[i]);
-       xalloca_free(tptree);
-       xalloca_free(tp);
+       FAST_ARRAY_FREE(tptree, nparent);
+       FAST_ARRAY_FREE(tp, nparent);
  
        return p;
  }