{"thread":{"id":"41418","subject":"[PATCH 0/18] hardening allocations against integer overflow","startedAt":"2016-02-15T21:45:16Z","lastAt":"2016-02-22T23:08:51Z","messageCount":93,"participants":["Jeff King","Eric Sunshine","Junio C Hamano","René Scharfe"],"isPatch":true,"patchVersion":1,"patchTotal":18},"messages":[{"id":"278209","messageId":"20160215214516.GA4015@sigill.intra.peff.net","threadId":"41418","inReplyTo":null,"subject":"[PATCH 0/18] hardening allocations against integer overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:45:16Z","receivedAt":"2016-02-15T21:45:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"About 6 months or so ago, I did an audit of git's code base for uses of\nstrcpy and sprintf that could overflow, fixing any bugs and cleaning up\nany suspect spots to make further audits simpler.  This is a\ncontinuation of that work, for size computations which can overflow and\ncause us to allocate a too-small buffer. E.g., something like:\n\n  char *concat(const char *a, const char *b)\n  {\n\tunsigned len_a = strlen(a);\n\tunsigned len_b = strlen(b);\n\tchar *ret = xmalloc(len_a + len_b);\n\tmemcpy(ret, a, len_a);\n\tmemcpy(ret, b, len_b);\n  }\n\nwill behave badly if the sum of \"a\" and \"b\" overflows \"unsigned\". There\nare other variants, too (we are also truncating the return value from\nstrlen, and we'd frequently use \"int\" here, so the lengths can actually\nbe negative!). It also varies based on platform. If the sites use size_t\ninstead of int, then 64-bit systems are typically hard to trigger in\npractice (just because you'd need petabytes to store \"a\" and \"b\" in the\nfirst place).\n\nThe only bug I have actually confirmed in practice here is fixed by\npatch 2 (which is why it's at the front). There's another one in\npath_name(), but that function is already dropped by the nearby\njk/lose-name-path topic.\n\nThe rest are cleanups of spots which _might_ be buggy, but I didn't dig\ntoo far to find out. As with the earlier audit, I tried to refactor\nusing helpers that make the code clearer and less error-prone. So maybe\nthey're fixing bugs or not, but they certainly make it easier to audit\nthe result for problems.\n\n  [01/18]: add helpers for detecting size_t overflow\n  [02/18]: tree-diff: catch integer overflow in combine_diff_path allocation\n  [03/18]: harden REALLOC_ARRAY and xcalloc against size_t overflow\n  [04/18]: add helpers for allocating flex-array structs\n  [05/18]: convert trivial cases to ALLOC_ARRAY\n  [06/18]: use xmallocz to avoid size arithmetic\n  [07/18]: convert trivial cases to FLEX_ARRAY macros\n  [08/18]: use st_add and st_mult for allocation size computation\n  [09/18]: write_untracked_extension: use FLEX_ALLOC helper\n  [10/18]: fast-import: simplify allocation in start_packfile\n  [11/18]: fetch-pack: simplify add_sought_entry\n  [12/18]: test-path-utils: fix normalize_path_copy output buffer size\n  [13/18]: sequencer: simplify memory allocation of get_message\n  [14/18]: git-compat-util: drop mempcpy compat code\n  [15/18]: transport_anonymize_url: use xstrfmt\n  [16/18]: diff_populate_gitlink: use a strbuf\n  [17/18]: convert ewah/bitmap code to use xmalloc\n  [18/18]: ewah: convert to REALLOC_ARRAY, etc\n\n-Peff\n"},{"id":"278211","messageId":"20160215214900.GA10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 01/18] add helpers for detecting size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:49:00Z","receivedAt":"2016-02-15T21:49:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Performing computations on size_t variables that we feed to\nxmalloc and friends can be dangerous, as an integer overflow\ncan cause us to allocate a much smaller chunk than we\nrealized.\n\nWe already have unsigned_add_overflows(), but let's add\nunsigned_mult_overflows() to that. Furthermore, rather than\nhave each site manually check and die on overflow, we can\nprovide some helpers that will:\n\n  - promote the arguments to size_t, so that we know we are\n    doing our computation in the same size of integer that\n    will ultimately be fed to xmalloc\n\n  - check and die on overflow\n\n  - return the result so that computations can be done in\n    the parameter list of xmalloc.\n\nThese functions are a lot uglier to use than normal\narithmetic operators (you have to do \"st_add(foo, bar)\"\ninstead of \"foo + bar\"). To at least limit the damage, we\nalso provide multi-valued versions. So rather than:\n\n  st_add(st_add(a, b), st_add(c, d));\n\nyou can write:\n\n  st_add4(a, b, c, d);\n\nThis isn't nearly as elegant as a varargs function, but it's\na lot harder to get it wrong. You don't have to remember to\nadd a sentinel value at the end, and the compiler will\ncomplain if you get the number of arguments wrong. This\npatch adds only the numbered variants required to convert\nthe current code base; we can easily add more later if\nneeded.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThe st_* names aren't amazing, but I think they mostly work. Suggestions\nwelcome, but please keep bikeshedding to a minimum. :)\n\nI almost went with checked_add(), checked_mult(), etc. But these\ninherently promote their arguments to size_t, so:\n\n  int x = checked_add(a, b);\n\nis buggy; the user _should_ be reminded of the result type in each call.\n\nThese could also build on compiler intrinsics for extra speed. I'm happy\nto do that as a follow-up, but I doubt it really matters in practice.\nWe're about to call malloc() in all cases, so an extra integer\ncomputation is almost certainly irrelevant. So I went for simplicity to\nstart with.\n\n git-compat-util.h | 34 ++++++++++++++++++++++++++++++++++\n 1 file changed, 34 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 693a336..0c65033 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -96,6 +96,14 @@\n #define unsigned_add_overflows(a, b) \\\n     ((b) > maximum_unsigned_value_of_type(a) - (a))\n \n+/*\n+ * Returns true if the multiplication of \"a\" and \"b\" will\n+ * overflow. The types of \"a\" and \"b\" must match and must be unsigned.\n+ * Note that this macro evaluates \"a\" twice!\n+ */\n+#define unsigned_mult_overflows(a, b) \\\n+    ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))\n+\n #ifdef __GNUC__\n #define TYPEOF(x) (__typeof__(x))\n #else\n@@ -713,6 +721,32 @@ extern void release_pack_memory(size_t);\n typedef void (*try_to_free_t)(size_t);\n extern try_to_free_t set_try_to_free_routine(try_to_free_t);\n \n+static inline size_t st_add(size_t a, size_t b)\n+{\n+\tif (unsigned_add_overflows(a, b))\n+\t\tdie(\"size_t overflow: %\"PRIuMAX\" + %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a + b;\n+}\n+#define st_add3(a,b,c)   st_add((a),st_add((b),(c)))\n+#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))\n+\n+static inline size_t st_mult(size_t a, size_t b)\n+{\n+\tif (unsigned_mult_overflows(a, b))\n+\t\tdie(\"size_t overflow: %\"PRIuMAX\" * %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a * b;\n+}\n+\n+static inline size_t st_sub(size_t a, size_t b)\n+{\n+\tif (a < b)\n+\t\tdie(\"size_t underflow: %\"PRIuMAX\" - %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a - b;\n+}\n+\n #ifdef HAVE_ALLOCA_H\n # include <alloca.h>\n # define xalloca(size)      (alloca(size))\n-- \n2.7.1.572.gf718037\n"},{"id":"278212","messageId":"20160215214931.GB10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 02/18] tree-diff: catch integer overflow in combine_diff_path allocation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:49:31Z","receivedAt":"2016-02-15T21:49:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"A combine_diff_path struct has two \"flex\" members allocated\nalongside the struct: a string to hold the pathname, and an\narray of parent pointers. We use an \"int\" to compute this,\nmeaning we may easily overflow it if the pathname is\nextremely long.\n\nWe can fix this by using size_t, and checking for overflow\nwith the st_add helper.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.h      | 4 ++--\n tree-diff.c | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/diff.h b/diff.h\nindex 70b2d70..beafbbd 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -222,8 +222,8 @@ struct combine_diff_path {\n \t} parent[FLEX_ARRAY];\n };\n #define combine_diff_path_size(n, l) \\\n-\t(sizeof(struct combine_diff_path) + \\\n-\t sizeof(struct combine_diff_parent) * (n) + (l) + 1)\n+\tst_add4(sizeof(struct combine_diff_path), (l), 1, \\\n+\t\tst_mult(sizeof(struct combine_diff_parent), (n)))\n \n extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t      int dense, struct rev_info *);\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 290a1da..4dda9a1 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -124,8 +124,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \tunsigned mode, const unsigned char *sha1)\n {\n \tstruct combine_diff_path *p;\n-\tint len = base->len + pathlen;\n-\tint alloclen = combine_diff_path_size(nparent, len);\n+\tsize_t len = st_add(base->len, pathlen);\n+\tsize_t alloclen = combine_diff_path_size(nparent, len);\n \n \t/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */\n \tp = last->next;\n-- \n2.7.1.572.gf718037\n"},{"id":"278213","messageId":"20160215215030.GC10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 03/18] harden REALLOC_ARRAY and xcalloc against size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:50:30Z","receivedAt":"2016-02-15T21:50:30Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"REALLOC_ARRAY inherently involves a multiplication which can\noverflow size_t, resulting in a much smaller buffer than we\nthink we've allocated. We can easily harden it by using\nst_mult() to check for overflow.  Likewise, we can add\nALLOC_ARRAY to do the same thing for xmalloc calls.\n\nxcalloc() should already be fine, because it takes the two\nfactors separately, assuming the system calloc actually\nchecks for overflow. However, before we even hit the system\ncalloc(), we do our memory_limit_check, which involves a\nmultiplication. Let's check for overflow ourselves so that\nthis limit cannot be bypassed.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 3 ++-\n wrapper.c         | 3 +++\n 2 files changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 0c65033..55c073d 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -779,7 +779,8 @@ extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);\n extern char *xgetcwd(void);\n extern FILE *fopen_for_writing(const char *path);\n \n-#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))\n+#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n \n static inline char *xstrdup_or_null(const char *str)\n {\ndiff --git a/wrapper.c b/wrapper.c\nindex 29a45d2..9afc1a0 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -152,6 +152,9 @@ void *xcalloc(size_t nmemb, size_t size)\n {\n \tvoid *ret;\n \n+\tif (unsigned_mult_overflows(nmemb, size))\n+\t\tdie(\"data too large to fit into virtual memory space\");\n+\n \tmemory_limit_check(size * nmemb, 0);\n \tret = calloc(nmemb, size);\n \tif (!ret && (!nmemb || !size))\n-- \n2.7.1.572.gf718037\n"},{"id":"278214","messageId":"20160215215054.GD10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 04/18] add helpers for allocating flex-array structs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:50:55Z","receivedAt":"2016-02-15T21:50:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Allocating a struct with a flex array is pretty simple in\npractice: you over-allocate the struct, then copy some data\ninto the over-allocation. But it can be a slight pain to\nmake sure you're allocating and copying the right amounts.\n\nThis patch adds a few helpers to turn simple cases of into a\none-liner that properly checks for overflow. See the\nembedded documentation for details.\n\nIdeally we could provide a more flexible version that could\nhandle multiple strings, like:\n\n  FLEX_ALLOC_FMT(ref, name, \"%s%s\", prefix, name);\n\nBut we have to implement this as a macro (because of the\noffset calculation of the flex member), which means we would\nneed all compilers to support variadic macros.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 62 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 55c073d..8f23801 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -782,6 +782,68 @@ extern FILE *fopen_for_writing(const char *path);\n #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n \n+/*\n+ * These functions help you allocate structs with flex arrays, and copy\n+ * the data directly into the array. For example, if you had:\n+ *\n+ *   struct foo {\n+ *     int bar;\n+ *     char name[FLEX_ARRAY];\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_MEM(f, name, src, len);\n+ *\n+ * to allocate a \"foo\" with the contents of \"src\" in the \"name\" field.\n+ * The resulting struct is automatically zero'd, and the flex-array field\n+ * is NUL-terminated (whether the incoming src buffer was or not).\n+ *\n+ * The FLEXPTR_* variants operate on structs that don't use flex-arrays,\n+ * but do want to store a pointer to some extra data in the same allocated\n+ * block. For example, if you have:\n+ *\n+ *   struct foo {\n+ *     char *name;\n+ *     int bar;\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_STR(f, name, src);\n+ *\n+ * and \"name\" will point to a block of memory after the struct, which will be\n+ * freed along with the struct (but the pointer can be repoined anywhere).\n+ *\n+ * The *_STR variants accept a string parameter rather than a ptr/len\n+ * combination.\n+ *\n+ * Note that these macros will evaluate the first parameter multiple\n+ * times, and it must be assignable as an lvalue.\n+ */\n+#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \\\n+\t(x) = NULL; /* silence -Wuninitialized for offset calculation */ \\\n+\t(x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \\\n+} while (0)\n+#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \\\n+\t(x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \\\n+\t(x)->ptrname = (void *)((x)+1); \\\n+} while(0)\n+#define FLEX_ALLOC_STR(x, flexname, str) \\\n+\tFLEX_ALLOC_MEM((x), flexname, (str), strlen(str))\n+#define FLEXPTR_ALLOC_STR(x, ptrname, str) \\\n+\tFLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))\n+\n+static inline void *xalloc_flex(size_t base_len, size_t offset,\n+\t\t\t\tconst void *src, size_t src_len)\n+{\n+\tunsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));\n+\tmemcpy(ret + offset, src, src_len);\n+\treturn ret;\n+}\n+\n static inline char *xstrdup_or_null(const char *str)\n {\n \treturn str ? xstrdup(str) : NULL;\n-- \n2.7.1.572.gf718037\n"},{"id":"278215","messageId":"20160215215154.GE10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 05/18] convert trivial cases to ALLOC_ARRAY","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:51:54Z","receivedAt":"2016-02-15T21:51:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Each of these cases can be converted to use ALLOC_ARRAY or\nREALLOC_ARRAY, which has two advantages:\n\n  1. It automatically checks the array-size multiplication\n     for overflow.\n\n  2. It always uses sizeof(*array) for the element-size,\n     so that it can never go out of sync with the declared\n     type of the array.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n alias.c                  |  2 +-\n attr.c                   |  2 +-\n bisect.c                 |  4 ++--\n builtin/blame.c          |  3 ++-\n builtin/clean.c          |  2 +-\n builtin/fast-export.c    |  2 +-\n builtin/grep.c           |  3 ++-\n builtin/index-pack.c     |  4 ++--\n builtin/merge-base.c     |  2 +-\n builtin/mv.c             |  3 ++-\n builtin/pack-objects.c   |  7 ++++---\n builtin/pack-redundant.c |  2 +-\n builtin/receive-pack.c   |  7 +++----\n builtin/remote-ext.c     |  2 +-\n column.c                 |  2 +-\n combine-diff.c           |  4 ++--\n commit.c                 |  2 +-\n compat/mingw.c           |  6 +++---\n daemon.c                 |  2 +-\n diffcore-order.c         |  4 ++--\n dir.c                    |  6 +++---\n exec_cmd.c               |  2 +-\n fast-import.c            |  5 +++--\n fsck.c                   |  3 ++-\n git.c                    |  2 +-\n graph.c                  | 10 ++++------\n khash.h                  |  2 +-\n levenshtein.c            |  8 +++++---\n line-log.c               | 10 +++++-----\n notes.c                  |  2 +-\n pack-check.c             |  2 +-\n pack-revindex.c          | 12 ++++++++----\n pathspec.c               |  5 +++--\n remote-curl.c            |  6 ++++--\n run-command.c            |  2 +-\n sha1_file.c              |  4 ++--\n shallow.c                |  6 +++---\n show-index.c             |  3 ++-\n transport.c              |  2 +-\n xdiff-interface.c        |  2 +-\n 40 files changed, 86 insertions(+), 73 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex a11229d..3b90397 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -23,7 +23,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \tint src, dst, count = 0, size = 16;\n \tchar quoted = 0;\n \n-\t*argv = xmalloc(sizeof(**argv) * size);\n+\tALLOC_ARRAY(*argv, size);\n \n \t/* split alias_string */\n \t(*argv)[count++] = cmdline;\ndiff --git a/attr.c b/attr.c\nindex 086c08d..c83ec49 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -799,7 +799,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)\n \t\t\t++count;\n \t}\n \t*num = count;\n-\t*check = xmalloc(sizeof(**check) * count);\n+\tALLOC_ARRAY(*check, count);\n \tj = 0;\n \tfor (i = 0; i < attr_nr; i++) {\n \t\tconst char *value = check_all_attr[i].value;\ndiff --git a/bisect.c b/bisect.c\nindex 06ec54e..7996c29 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -708,10 +708,10 @@ static struct commit *get_commit_reference(const unsigned char *sha1)\n \n static struct commit **get_bad_and_good_commits(int *rev_nr)\n {\n-\tint len = 1 + good_revs.nr;\n-\tstruct commit **rev = xmalloc(len * sizeof(*rev));\n+\tstruct commit **rev;\n \tint i, n = 0;\n \n+\tALLOC_ARRAY(rev, 1 + good_revs.nr);\n \trev[n++] = get_commit_reference(current_bad_oid->hash);\n \tfor (i = 0; i < good_revs.nr; i++)\n \t\trev[n++] = get_commit_reference(good_revs.sha1[i]);\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 55bf5fa..b4ed462 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2059,7 +2059,8 @@ static int prepare_lines(struct scoreboard *sb)\n \tfor (p = buf; p < end; p = get_next_line(p, end))\n \t\tnum++;\n \n-\tsb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1));\n+\tALLOC_ARRAY(sb->lineno, num + 1);\n+\tlineno = sb->lineno;\n \n \tfor (p = buf; p < end; p = get_next_line(p, end))\n \t\t*lineno++ = p - buf;\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 7b08237..8229f7e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -543,7 +543,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \tint eof = 0;\n \tint i;\n \n-\tchosen = xmalloc(sizeof(int) * stuff->nr);\n+\tALLOC_ARRAY(chosen, stuff->nr);\n \t/* set chosen as uninitialized */\n \tfor (i = 0; i < stuff->nr; i++)\n \t\tchosen[i] = -1;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 2471297..8164b58 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -1021,7 +1021,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)\n \t\tconst char **refspecs_str;\n \t\tint i;\n \n-\t\trefspecs_str = xmalloc(sizeof(*refspecs_str) * refspecs_list.nr);\n+\t\tALLOC_ARRAY(refspecs_str, refspecs_list.nr);\n \t\tfor (i = 0; i < refspecs_list.nr; i++)\n \t\t\trefspecs_str[i] = refspecs_list.items[i].string;\n \ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 8c516a9..fa9c9ef 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -365,9 +365,10 @@ static void append_path(struct grep_opt *opt, const void *data, size_t len)\n static void run_pager(struct grep_opt *opt, const char *prefix)\n {\n \tstruct string_list *path_list = opt->output_priv;\n-\tconst char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));\n+\tconst char **argv;\n \tint i, status;\n \n+\tALLOC_ARRAY(argv, path_list->nr + 1);\n \tfor (i = 0; i < path_list->nr; i++)\n \t\targv[i] = path_list->items[i].string;\n \targv[path_list->nr] = NULL;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 6a01509..a60bcfa 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1346,7 +1346,7 @@ static void fix_unresolved_deltas(struct sha1file *f)\n \t * before deltas depending on them, a good heuristic is to start\n \t * resolving deltas in the same order as their position in the pack.\n \t */\n-\tsorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos));\n+\tALLOC_ARRAY(sorted_by_pos, nr_ref_deltas);\n \tfor (i = 0; i < nr_ref_deltas; i++)\n \t\tsorted_by_pos[i] = &ref_deltas[i];\n \tqsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare);\n@@ -1759,7 +1759,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \tif (show_stat)\n \t\tshow_pack_info(stat_only);\n \n-\tidx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));\n+\tALLOC_ARRAY(idx_objects, nr_objects);\n \tfor (i = 0; i < nr_objects; i++)\n \t\tidx_objects[i] = &objects[i].idx;\n \tcurr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex a891162..c0d1822 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -252,7 +252,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)\n \tif (argc < 2)\n \t\tusage_with_options(merge_base_usage, options);\n \n-\trev = xmalloc(argc * sizeof(*rev));\n+\tALLOC_ARRAY(rev, argc);\n \twhile (argc-- > 0)\n \t\trev[rev_nr++] = get_commit_reference(*argv++);\n \treturn show_merge_base(rev, rev_nr, show_all);\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex d1d4316..9a9813a 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -24,7 +24,8 @@ static const char **internal_copy_pathspec(const char *prefix,\n \t\t\t\t\t   int count, unsigned flags)\n {\n \tint i;\n-\tconst char **result = xmalloc((count + 1) * sizeof(const char *));\n+\tconst char **result;\n+\tALLOC_ARRAY(result, count + 1);\n \tmemcpy(result, pathspec, count * sizeof(const char *));\n \tresult[count] = NULL;\n \tfor (i = 0; i < count; i++) {\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 4dae5b1..b4f1fa6 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -624,7 +624,7 @@ static struct object_entry **compute_write_order(void)\n {\n \tunsigned int i, wo_end, last_untagged;\n \n-\tstruct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));\n+\tstruct object_entry **wo;\n \tstruct object_entry *objects = to_pack.objects;\n \n \tfor (i = 0; i < to_pack.nr_objects; i++) {\n@@ -657,6 +657,7 @@ static struct object_entry **compute_write_order(void)\n \t * Give the objects in the original recency order until\n \t * we see a tagged tip.\n \t */\n+\tALLOC_ARRAY(wo, to_pack.nr_objects);\n \tfor (i = wo_end = 0; i < to_pack.nr_objects; i++) {\n \t\tif (objects[i].tagged)\n \t\t\tbreak;\n@@ -769,7 +770,7 @@ static void write_pack_file(void)\n \n \tif (progress > pack_to_stdout)\n \t\tprogress_state = start_progress(_(\"Writing objects\"), nr_result);\n-\twritten_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));\n+\tALLOC_ARRAY(written_list, to_pack.nr_objects);\n \twrite_order = compute_write_order();\n \n \tdo {\n@@ -2129,7 +2130,7 @@ static void prepare_pack(int window, int depth)\n \tif (!to_pack.nr_objects || !window || !depth)\n \t\treturn;\n \n-\tdelta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));\n+\tALLOC_ARRAY(delta_list, to_pack.nr_objects);\n \tnr_deltas = n = 0;\n \n \tfor (i = 0; i < to_pack.nr_objects; i++) {\ndiff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c\nindex d0532f6..72c8158 100644\n--- a/builtin/pack-redundant.c\n+++ b/builtin/pack-redundant.c\n@@ -53,7 +53,7 @@ static inline struct llist_item *llist_item_get(void)\n \t\tfree_nodes = free_nodes->next;\n \t} else {\n \t\tint i = 1;\n-\t\tnew = xmalloc(sizeof(struct llist_item) * BLKSIZE);\n+\t\tALLOC_ARRAY(new, BLKSIZE);\n \t\tfor (; i < BLKSIZE; i++)\n \t\t\tllist_item_put(&new[i]);\n \t}\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex f2d6761..ad2fdaa 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1044,7 +1044,7 @@ static void run_update_post_hook(struct command *commands)\n \tif (!argc || !hook)\n \t\treturn;\n \n-\targv = xmalloc(sizeof(*argv) * (2 + argc));\n+\tALLOC_ARRAY(argv, 2 + argc);\n \targv[0] = hook;\n \n \tfor (argc = 1, cmd = commands; cmd; cmd = cmd->next) {\n@@ -1597,8 +1597,7 @@ static void prepare_shallow_update(struct command *commands,\n {\n \tint i, j, k, bitmap_size = (si->ref->nr + 31) / 32;\n \n-\tsi->used_shallow = xmalloc(sizeof(*si->used_shallow) *\n-\t\t\t\t   si->shallow->nr);\n+\tALLOC_ARRAY(si->used_shallow, si->shallow->nr);\n \tassign_shallow_commits_to_refs(si, si->used_shallow, NULL);\n \n \tsi->need_reachability_test =\n@@ -1664,7 +1663,7 @@ static void update_shallow_info(struct command *commands,\n \t\treturn;\n \t}\n \n-\tref_status = xmalloc(sizeof(*ref_status) * ref->nr);\n+\tALLOC_ARRAY(ref_status, ref->nr);\n \tassign_shallow_commits_to_refs(si, NULL, ref_status);\n \tfor (cmd = commands; cmd; cmd = cmd->next) {\n \t\tif (is_null_sha1(cmd->new_sha1))\ndiff --git a/builtin/remote-ext.c b/builtin/remote-ext.c\nindex e3cd25d..681894a 100644\n--- a/builtin/remote-ext.c\n+++ b/builtin/remote-ext.c\n@@ -133,7 +133,7 @@ static const char **parse_argv(const char *arg, const char *service)\n \t\t\ttemparray[arguments++] = expanded;\n \t}\n \n-\tret = xmalloc((arguments + 1) * sizeof(char *));\n+\tALLOC_ARRAY(ret, arguments + 1);\n \tfor (i = 0; i < arguments; i++)\n \t\tret[i] = temparray[i];\n \tret[arguments] = NULL;\ndiff --git a/column.c b/column.c\nindex 786abe6..f9fda68 100644\n--- a/column.c\n+++ b/column.c\n@@ -164,7 +164,7 @@ static void display_table(const struct string_list *list,\n \tdata.colopts = colopts;\n \tdata.opts = *opts;\n \n-\tdata.len = xmalloc(sizeof(*data.len) * list->nr);\n+\tALLOC_ARRAY(data.len, list->nr);\n \tfor (i = 0; i < list->nr; i++)\n \t\tdata.len[i] = item_length(colopts, list->items[i].string);\n \ndiff --git a/combine-diff.c b/combine-diff.c\nindex 5571304..a698016 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1372,7 +1372,7 @@ static struct combine_diff_path *find_paths_multitree(\n \tstruct combine_diff_path paths_head;\n \tstruct strbuf base;\n \n-\tparents_sha1 = xmalloc(nparent * sizeof(parents_sha1[0]));\n+\tALLOC_ARRAY(parents_sha1, nparent);\n \tfor (i = 0; i < nparent; i++)\n \t\tparents_sha1[i] = parents->sha1[i];\n \n@@ -1483,7 +1483,7 @@ void diff_tree_combined(const unsigned char *sha1,\n \tif (opt->orderfile && num_paths) {\n \t\tstruct obj_order *o;\n \n-\t\to = xmalloc(sizeof(*o) * num_paths);\n+\t\tALLOC_ARRAY(o, num_paths);\n \t\tfor (i = 0, p = paths; p; p = p->next, i++)\n \t\t\to[i].obj = p;\n \t\torder_objects(opt->orderfile, path_path, o, num_paths);\ndiff --git a/commit.c b/commit.c\nindex 40388d7..31cd91f 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -903,7 +903,7 @@ static int remove_redundant(struct commit **array, int cnt)\n \n \twork = xcalloc(cnt, sizeof(*work));\n \tredundant = xcalloc(cnt, 1);\n-\tfilled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));\n+\tALLOC_ARRAY(filled_index, cnt - 1);\n \n \tfor (i = 0; i < cnt; i++)\n \t\tparse_commit(array[i]);\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 77a51d3..0eabe68 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -854,7 +854,7 @@ static char **get_path_split(void)\n \tif (!n)\n \t\treturn NULL;\n \n-\tpath = xmalloc((n+1)*sizeof(char *));\n+\tALLOC_ARRAY(path, n+1);\n \tp = envpath;\n \ti = 0;\n \tdo {\n@@ -939,7 +939,7 @@ static wchar_t *make_environment_block(char **deltaenv)\n \t\ti++;\n \n \t/* copy the environment, leaving space for changes */\n-\ttmpenv = xmalloc((size + i) * sizeof(char*));\n+\tALLOC_ARRAY(tmpenv, size + i);\n \tmemcpy(tmpenv, environ, size * sizeof(char*));\n \n \t/* merge supplied environment changes into the temporary environment */\n@@ -1129,7 +1129,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)\n \t\tint argc = 0;\n \t\tconst char **argv2;\n \t\twhile (argv[argc]) argc++;\n-\t\targv2 = xmalloc(sizeof(*argv) * (argc+1));\n+\t\tALLOC_ARRAY(argv2, argc + 1);\n \t\targv2[0] = (char *)cmd;\t/* full path to the script file */\n \t\tmemcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);\n \t\tpid = mingw_spawnv(prog, argv2, 1);\ndiff --git a/daemon.c b/daemon.c\nindex 46b411c..0f48b34 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1374,7 +1374,7 @@ int main(int argc, char **argv)\n \t\twrite_file(pid_file, \"%\"PRIuMAX, (uintmax_t) getpid());\n \n \t/* prepare argv for serving-processes */\n-\tcld_argv = xmalloc(sizeof (char *) * (argc + 2));\n+\tALLOC_ARRAY(cld_argv, argc + 2);\n \tcld_argv[0] = argv[0];\t/* git-daemon */\n \tcld_argv[1] = \"--serve\";\n \tfor (i = 1; i < argc; ++i)\ndiff --git a/diffcore-order.c b/diffcore-order.c\nindex 97dd3d0..69d41f7 100644\n--- a/diffcore-order.c\n+++ b/diffcore-order.c\n@@ -52,7 +52,7 @@ static void prepare_order(const char *orderfile)\n \t\t}\n \t\tif (pass == 0) {\n \t\t\torder_cnt = cnt;\n-\t\t\torder = xmalloc(sizeof(*order) * cnt);\n+\t\t\tALLOC_ARRAY(order, cnt);\n \t\t}\n \t}\n }\n@@ -120,7 +120,7 @@ void diffcore_order(const char *orderfile)\n \tif (!q->nr)\n \t\treturn;\n \n-\to = xmalloc(sizeof(*o) * q->nr);\n+\tALLOC_ARRAY(o, q->nr);\n \tfor (i = 0; i < q->nr; i++)\n \t\to[i].obj = q->queue[i];\n \torder_objects(orderfile, pair_pathtwo, o, q->nr);\ndiff --git a/dir.c b/dir.c\nindex f0b6d0a..66c93c1 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2484,14 +2484,14 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,\n \tud.untracked_alloc = value;\n \tud.untracked_nr\t   = value;\n \tif (ud.untracked_nr)\n-\t\tud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);\n+\t\tALLOC_ARRAY(ud.untracked, ud.untracked_nr);\n \tdata = next;\n \n \tnext = data;\n \tud.dirs_alloc = ud.dirs_nr = decode_varint(&next);\n \tif (next > end)\n \t\treturn -1;\n-\tud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);\n+\tALLOC_ARRAY(ud.dirs, ud.dirs_nr);\n \tdata = next;\n \n \tlen = strlen((const char *)data);\n@@ -2611,7 +2611,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long\n \trd.data\t      = next;\n \trd.end\t      = end;\n \trd.index      = 0;\n-\trd.ucd        = xmalloc(sizeof(*rd.ucd) * len);\n+\tALLOC_ARRAY(rd.ucd, len);\n \n \tif (read_one_dir(&uc->root, &rd) || rd.index != len)\n \t\tgoto done;\ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex e85f0fd..17b7918 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -114,7 +114,7 @@ const char **prepare_git_cmd(const char **argv)\n \n \tfor (argc = 0; argv[argc]; argc++)\n \t\t; /* just counting */\n-\tnargv = xmalloc(sizeof(*nargv) * (argc + 2));\n+\tALLOC_ARRAY(nargv, argc + 2);\n \n \tnargv[0] = \"git\";\n \tfor (argc = 0; argv[argc]; argc++)\ndiff --git a/fast-import.c b/fast-import.c\nindex bf01b34..a6467cb 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -814,7 +814,8 @@ static struct tree_entry *new_tree_entry(void)\n \tif (!avail_tree_entry) {\n \t\tunsigned int n = tree_entry_alloc;\n \t\ttotal_allocd += n * sizeof(struct tree_entry);\n-\t\tavail_tree_entry = e = xmalloc(n * sizeof(struct tree_entry));\n+\t\tALLOC_ARRAY(e, n);\n+\t\tavail_tree_entry = e;\n \t\twhile (n-- > 1) {\n \t\t\t*((void**)e) = e + 1;\n \t\t\te++;\n@@ -898,7 +899,7 @@ static const char *create_index(void)\n \tstruct object_entry_pool *o;\n \n \t/* Build the table of object IDs. */\n-\tidx = xmalloc(object_count * sizeof(*idx));\n+\tALLOC_ARRAY(idx, object_count);\n \tc = idx;\n \tfor (o = blocks; o; o = o->next_pool)\n \t\tfor (e = o->next_free; e-- != o->entries;)\ndiff --git a/fsck.c b/fsck.c\nindex c637f66..ca4c685 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -199,7 +199,8 @@ void fsck_set_msg_type(struct fsck_options *options,\n \n \tif (!options->msg_type) {\n \t\tint i;\n-\t\tint *msg_type = xmalloc(sizeof(int) * FSCK_MSG_MAX);\n+\t\tint *msg_type;\n+\t\tALLOC_ARRAY(msg_type, FSCK_MSG_MAX);\n \t\tfor (i = 0; i < FSCK_MSG_MAX; i++)\n \t\t\tmsg_type[i] = fsck_msg_type(i, options);\n \t\toptions->msg_type = msg_type;\ndiff --git a/git.c b/git.c\nindex da278c3..0bd92a7 100644\n--- a/git.c\n+++ b/git.c\n@@ -249,7 +249,7 @@ static int handle_alias(int *argcp, const char ***argv)\n \t\t\trestore_env(1);\n \n \t\t\t/* build alias_argv */\n-\t\t\talias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));\n+\t\t\tALLOC_ARRAY(alias_argv, argc + 1);\n \t\t\talias_argv[0] = alias_string + 1;\n \t\t\tfor (i = 1; i < argc; ++i)\n \t\t\t\talias_argv[i] = (*argv)[i];\ndiff --git a/graph.c b/graph.c\nindex c25a09a..1350bdd 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -234,12 +234,10 @@ struct git_graph *graph_init(struct rev_info *opt)\n \t * We'll automatically grow columns later if we need more room.\n \t */\n \tgraph->column_capacity = 30;\n-\tgraph->columns = xmalloc(sizeof(struct column) *\n-\t\t\t\t graph->column_capacity);\n-\tgraph->new_columns = xmalloc(sizeof(struct column) *\n-\t\t\t\t     graph->column_capacity);\n-\tgraph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n-\tgraph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n+\tALLOC_ARRAY(graph->columns, graph->column_capacity);\n+\tALLOC_ARRAY(graph->new_columns, graph->column_capacity);\n+\tALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);\n+\tALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity);\n \n \t/*\n \t * The diff output prefix callback, with this we can make\ndiff --git a/khash.h b/khash.h\nindex 376475a..c0da40d 100644\n--- a/khash.h\n+++ b/khash.h\n@@ -117,7 +117,7 @@ static const double __ac_HASH_UPPER = 0.77;\n \t\t\tif (new_n_buckets < 4) new_n_buckets = 4;\t\t\t\t\t\\\n \t\t\tif (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0;\t/* requested size is too small */ \\\n \t\t\telse { /* hash table size to be changed (shrink or expand); rehash */ \\\n-\t\t\t\tnew_flags = (khint32_t*)xmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t));\t\\\n+\t\t\t\tALLOC_ARRAY(new_flags, __ac_fsize(new_n_buckets)); \\\n \t\t\t\tif (!new_flags) return -1;\t\t\t\t\t\t\t\t\\\n \t\t\t\tmemset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \\\n \t\t\t\tif (h->n_buckets < new_n_buckets) {\t/* expand */\t\t\\\ndiff --git a/levenshtein.c b/levenshtein.c\nindex fc28159..d263269 100644\n--- a/levenshtein.c\n+++ b/levenshtein.c\n@@ -42,11 +42,13 @@ int levenshtein(const char *string1, const char *string2,\n \t\tint w, int s, int a, int d)\n {\n \tint len1 = strlen(string1), len2 = strlen(string2);\n-\tint *row0 = xmalloc(sizeof(int) * (len2 + 1));\n-\tint *row1 = xmalloc(sizeof(int) * (len2 + 1));\n-\tint *row2 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row0, *row1, *row2;\n \tint i, j;\n \n+\tALLOC_ARRAY(row0, len2 + 1);\n+\tALLOC_ARRAY(row1, len2 + 1);\n+\tALLOC_ARRAY(row2, len2 + 1);\n+\n \tfor (j = 0; j <= len2; j++)\n \t\trow1[j] = j * a;\n \tfor (i = 0; i < len1; i++) {\ndiff --git a/line-log.c b/line-log.c\nindex af6e2f7..2f781b4 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -521,7 +521,7 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines,\n \tif (diff_populate_filespec(spec, 0))\n \t\tdie(\"Cannot read blob %s\", sha1_to_hex(spec->sha1));\n \n-\tends = xmalloc(size * sizeof(*ends));\n+\tALLOC_ARRAY(ends, size);\n \tends[cur++] = 0;\n \tdata = spec->data;\n \twhile (num < spec->size) {\n@@ -753,7 +753,7 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n \t\t\tcount++;\n \t\t\tr = r->next;\n \t\t}\n-\t\tpaths = xmalloc((count+1)*sizeof(char *));\n+\t\tALLOC_ARRAY(paths, count + 1);\n \t\tr = range;\n \t\tfor (i = 0; i < count; i++) {\n \t\t\tpaths[i] = xstrdup(r->path);\n@@ -1146,9 +1146,9 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm\n \tif (nparents > 1 && rev->first_parent_only)\n \t\tnparents = 1;\n \n-\tdiffqueues = xmalloc(nparents * sizeof(*diffqueues));\n-\tcand = xmalloc(nparents * sizeof(*cand));\n-\tparents = xmalloc(nparents * sizeof(*parents));\n+\tALLOC_ARRAY(diffqueues, nparents);\n+\tALLOC_ARRAY(cand, nparents);\n+\tALLOC_ARRAY(parents, nparents);\n \n \tp = commit->parents;\n \tfor (i = 0; i < nparents; i++) {\ndiff --git a/notes.c b/notes.c\nindex c1e5035..88cf474 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1035,7 +1035,7 @@ struct notes_tree **load_notes_trees(struct string_list *refs, int flags)\n \tstruct string_list_item *item;\n \tint counter = 0;\n \tstruct notes_tree **trees;\n-\ttrees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));\n+\tALLOC_ARRAY(trees, refs->nr + 1);\n \tfor_each_string_list_item(item, refs) {\n \t\tstruct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));\n \t\tinit_notes(t, item->string, combine_notes_ignore, flags);\ndiff --git a/pack-check.c b/pack-check.c\nindex 433bd86..1da89a4 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -89,7 +89,7 @@ static int verify_packfile(struct packed_git *p,\n \t * we do not do scan-streaming check on the pack file.\n \t */\n \tnr_objects = p->num_objects;\n-\tentries = xmalloc((nr_objects + 1) * sizeof(*entries));\n+\tALLOC_ARRAY(entries, nr_objects + 1);\n \tentries[nr_objects].offset = pack_sig_ofs;\n \t/* first sort entries by pack offset, since unpacking them is more efficient that way */\n \tfor (i = 0; i < nr_objects; i++) {\ndiff --git a/pack-revindex.c b/pack-revindex.c\nindex 155a8a3..96d51c3 100644\n--- a/pack-revindex.c\n+++ b/pack-revindex.c\n@@ -44,10 +44,14 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max)\n \t * keep track of them with alias pointers, always sorting from \"from\"\n \t * to \"to\".\n \t */\n-\tstruct revindex_entry *tmp = xmalloc(n * sizeof(*tmp));\n-\tstruct revindex_entry *from = entries, *to = tmp;\n+\tstruct revindex_entry *tmp, *from, *to;\n \tint bits;\n-\tunsigned *pos = xmalloc(BUCKETS * sizeof(*pos));\n+\tunsigned *pos;\n+\n+\tALLOC_ARRAY(pos, BUCKETS);\n+\tALLOC_ARRAY(tmp, n);\n+\tfrom = entries;\n+\tto = tmp;\n \n \t/*\n \t * If (max >> bits) is zero, then we know that the radix digit we are\n@@ -121,7 +125,7 @@ static void create_pack_revindex(struct packed_git *p)\n \tunsigned i;\n \tconst char *index = p->index_data;\n \n-\tp->revindex = xmalloc(sizeof(*p->revindex) * (num_ent + 1));\n+\tALLOC_ARRAY(p->revindex, num_ent + 1);\n \tindex += 4 * 256;\n \n \tif (p->index_version > 1) {\ndiff --git a/pathspec.c b/pathspec.c\nindex 9304ee3..c9e9b6c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -406,7 +406,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tn++;\n \n \tpathspec->nr = n;\n-\tpathspec->items = item = xmalloc(sizeof(*item) * n);\n+\tALLOC_ARRAY(pathspec->items, n);\n+\titem = pathspec->items;\n \tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n@@ -483,7 +484,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\n-\tdst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);\n+\tALLOC_ARRAY(dst->items, dst->nr);\n \tmemcpy(dst->items, src->items,\n \t       sizeof(struct pathspec_item) * dst->nr);\n }\ndiff --git a/remote-curl.c b/remote-curl.c\nindex c704857..49d8c3b 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -696,9 +696,10 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)\n static int fetch_dumb(int nr_heads, struct ref **to_fetch)\n {\n \tstruct walker *walker;\n-\tchar **targets = xmalloc(nr_heads * sizeof(char*));\n+\tchar **targets;\n \tint ret, i;\n \n+\tALLOC_ARRAY(targets, nr_heads);\n \tif (options.depth)\n \t\tdie(\"dumb http transport does not support --depth\");\n \tfor (i = 0; i < nr_heads; i++)\n@@ -845,9 +846,10 @@ static void parse_fetch(struct strbuf *buf)\n \n static int push_dav(int nr_spec, char **specs)\n {\n-\tconst char **argv = xmalloc((10 + nr_spec) * sizeof(char*));\n+\tconst char **argv;\n \tint argc = 0, i;\n \n+\tALLOC_ARRAY(argv, 10 + nr_spec);\n \targv[argc++] = \"http-push\";\n \targv[argc++] = \"--helper-status\";\n \tif (options.dry_run)\ndiff --git a/run-command.c b/run-command.c\nindex cdf0184..a8a293a 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -168,7 +168,7 @@ static const char **prepare_shell_cmd(const char **argv)\n \tfor (argc = 0; argv[argc]; argc++)\n \t\t; /* just counting */\n \t/* +1 for NULL, +3 for \"sh -c\" plus extra $0 */\n-\tnargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));\n+\tALLOC_ARRAY(nargv, argc + 1 + 3);\n \n \tif (argc < 1)\n \t\tdie(\"BUG: shell command is empty\");\ndiff --git a/sha1_file.c b/sha1_file.c\nindex aab1872..2f1c6d3 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1942,7 +1942,7 @@ static enum object_type packed_to_object_type(struct packed_git *p,\n \t\t/* Push the object we're going to leave behind */\n \t\tif (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {\n \t\t\tpoi_stack_alloc = alloc_nr(poi_stack_nr);\n-\t\t\tpoi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc);\n+\t\t\tALLOC_ARRAY(poi_stack, poi_stack_alloc);\n \t\t\tmemcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);\n \t\t} else {\n \t\t\tALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);\n@@ -2308,7 +2308,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,\n \t\tif (delta_stack_nr >= delta_stack_alloc\n \t\t    && delta_stack == small_delta_stack) {\n \t\t\tdelta_stack_alloc = alloc_nr(delta_stack_nr);\n-\t\t\tdelta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc);\n+\t\t\tALLOC_ARRAY(delta_stack, delta_stack_alloc);\n \t\t\tmemcpy(delta_stack, small_delta_stack,\n \t\t\t       sizeof(*delta_stack)*delta_stack_nr);\n \t\t} else {\ndiff --git a/shallow.c b/shallow.c\nindex 60f1505..71163bf 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -315,8 +315,8 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa)\n \tinfo->shallow = sa;\n \tif (!sa)\n \t\treturn;\n-\tinfo->ours = xmalloc(sizeof(*info->ours) * sa->nr);\n-\tinfo->theirs = xmalloc(sizeof(*info->theirs) * sa->nr);\n+\tALLOC_ARRAY(info->ours, sa->nr);\n+\tALLOC_ARRAY(info->theirs, sa->nr);\n \tfor (i = 0; i < sa->nr; i++) {\n \t\tif (has_sha1_file(sa->sha1[i])) {\n \t\t\tstruct commit_graft *graft;\n@@ -487,7 +487,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,\n \tstruct paint_info pi;\n \n \ttrace_printf_key(&trace_shallow, \"shallow: assign_shallow_commits_to_refs\\n\");\n-\tshallow = xmalloc(sizeof(*shallow) * (info->nr_ours + info->nr_theirs));\n+\tALLOC_ARRAY(shallow, info->nr_ours + info->nr_theirs);\n \tfor (i = 0; i < info->nr_ours; i++)\n \t\tshallow[nr_shallow++] = info->ours[i];\n \tfor (i = 0; i < info->nr_theirs; i++)\ndiff --git a/show-index.c b/show-index.c\nindex d9e4903..acf8d54 100644\n--- a/show-index.c\n+++ b/show-index.c\n@@ -50,7 +50,8 @@ int main(int argc, char **argv)\n \t\t\tunsigned char sha1[20];\n \t\t\tuint32_t crc;\n \t\t\tuint32_t off;\n-\t\t} *entries = xmalloc(nr * sizeof(entries[0]));\n+\t\t} *entries;\n+\t\tALLOC_ARRAY(entries, nr);\n \t\tfor (i = 0; i < nr; i++)\n \t\t\tif (fread(entries[i].sha1, 20, 1, stdin) != 1)\n \t\t\t\tdie(\"unable to read sha1 %u/%u\", i, nr);\ndiff --git a/transport.c b/transport.c\nindex 9ae7184..5c63295 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1307,7 +1307,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)\n \t\t * This condition shouldn't be met in a non-deepening fetch\n \t\t * (see builtin/fetch.c:quickfetch()).\n \t\t */\n-\t\theads = xmalloc(nr_refs * sizeof(*heads));\n+\t\tALLOC_ARRAY(heads, nr_refs);\n \t\tfor (rm = refs; rm; rm = rm->next)\n \t\t\theads[nr_heads++] = rm;\n \t}\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex cb67c1c..54236f2 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -265,7 +265,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)\n \tfor (i = 0, regs->nr = 1; value[i]; i++)\n \t\tif (value[i] == '\\n')\n \t\t\tregs->nr++;\n-\tregs->array = xmalloc(regs->nr * sizeof(struct ff_reg));\n+\tALLOC_ARRAY(regs->array, regs->nr);\n \tfor (i = 0; i < regs->nr; i++) {\n \t\tstruct ff_reg *reg = regs->array + i;\n \t\tconst char *ep = strchr(value, '\\n'), *expression;\n-- \n2.7.1.572.gf718037\n"},{"id":"278217","messageId":"20160215215222.GF10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 06/18] use xmallocz to avoid size arithmetic","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:52:22Z","receivedAt":"2016-02-15T21:52:22Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We frequently allocate strings as xmalloc(len + 1), where\nthe extra 1 is for the NUL terminator. This can be done more\nsimply with xmallocz, which also checks for integer\noverflow.\n\nThere's no case where switching xmalloc(n+1) to xmallocz(n)\nis wrong; the result is the same length, and malloc made no\nguarantees about what was in the buffer anyway. But in some\ncases, we can stop manually placing NUL at the end of the\nallocated buffer. But that's only safe if it's clear that\nthe contents will always fill the buffer.\n\nIn each case where this patch does so, I manually examined\nthe control flow, and I tried to err on the side of caution.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/check-ref-format.c | 2 +-\n builtin/merge-tree.c       | 2 +-\n builtin/worktree.c         | 2 +-\n column.c                   | 3 +--\n combine-diff.c             | 4 +---\n config.c                   | 4 +---\n dir.c                      | 2 +-\n entry.c                    | 2 +-\n grep.c                     | 3 +--\n imap-send.c                | 5 ++---\n ll-merge.c                 | 2 +-\n progress.c                 | 2 +-\n refs.c                     | 2 +-\n setup.c                    | 5 ++---\n strbuf.c                   | 2 +-\n 15 files changed, 17 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c\nindex fd915d5..eac4994 100644\n--- a/builtin/check-ref-format.c\n+++ b/builtin/check-ref-format.c\n@@ -20,7 +20,7 @@ static const char builtin_check_ref_format_usage[] =\n  */\n static char *collapse_slashes(const char *refname)\n {\n-\tchar *ret = xmalloc(strlen(refname) + 1);\n+\tchar *ret = xmallocz(strlen(refname));\n \tchar ch;\n \tchar prev = '/';\n \tchar *cp = ret;\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex d4f0cbd..ca57004 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -174,7 +174,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi\n \n static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)\n {\n-\tchar *path = xmalloc(traverse_path_len(info, n) + 1);\n+\tchar *path = xmallocz(traverse_path_len(info, n));\n \treturn make_traverse_path(path, info, n);\n }\n \ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 475b958..0a45710 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -52,7 +52,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n \t\treturn 1;\n \t}\n \tlen = st.st_size;\n-\tpath = xmalloc(len + 1);\n+\tpath = xmallocz(len);\n \tread_in_full(fd, path, len);\n \tclose(fd);\n \twhile (len && (path[len - 1] == '\\n' || path[len - 1] == '\\r'))\ndiff --git a/column.c b/column.c\nindex f9fda68..d55ead1 100644\n--- a/column.c\n+++ b/column.c\n@@ -173,9 +173,8 @@ static void display_table(const struct string_list *list,\n \tif (colopts & COL_DENSE)\n \t\tshrink_columns(&data);\n \n-\tempty_cell = xmalloc(initial_width + 1);\n+\tempty_cell = xmallocz(initial_width);\n \tmemset(empty_cell, ' ', initial_width);\n-\tempty_cell[initial_width] = '\\0';\n \tfor (y = 0; y < data.rows; y++) {\n \t\tfor (x = 0; x < data.cols; x++)\n \t\t\tif (display_cell(&data, initial_width, empty_cell, x, y))\ndiff --git a/combine-diff.c b/combine-diff.c\nindex a698016..890c415 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1043,7 +1043,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t\telem->mode = canon_mode(S_IFLNK);\n \n \t\t\tresult_size = len;\n-\t\t\tresult = xmalloc(len + 1);\n+\t\t\tresult = xmallocz(len);\n \n \t\t\tdone = read_in_full(fd, result, len);\n \t\t\tif (done < 0)\n@@ -1051,8 +1051,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\telse if (done < len)\n \t\t\t\tdie(\"early EOF '%s'\", elem->path);\n \n-\t\t\tresult[len] = 0;\n-\n \t\t\t/* If not a fake symlink, apply filters, e.g. autocrlf */\n \t\t\tif (is_file) {\n \t\t\t\tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/config.c b/config.c\nindex b95ac3a..e7b589a 100644\n--- a/config.c\n+++ b/config.c\n@@ -1902,7 +1902,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \t * Validate the key and while at it, lower case it for matching.\n \t */\n \tif (store_key)\n-\t\t*store_key = xmalloc(strlen(key) + 1);\n+\t\t*store_key = xmallocz(strlen(key));\n \n \tdot = 0;\n \tfor (i = 0; key[i]; i++) {\n@@ -1926,8 +1926,6 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \t\tif (store_key)\n \t\t\t(*store_key)[i] = c;\n \t}\n-\tif (store_key)\n-\t\t(*store_key)[i] = 0;\n \n \treturn 0;\n \ndiff --git a/dir.c b/dir.c\nindex 66c93c1..6c627d5 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -711,7 +711,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\tclose(fd);\n \t\t\treturn 0;\n \t\t}\n-\t\tbuf = xmalloc(size+1);\n+\t\tbuf = xmallocz(size);\n \t\tif (read_in_full(fd, buf, size) != size) {\n \t\t\tfree(buf);\n \t\t\tclose(fd);\ndiff --git a/entry.c b/entry.c\nindex 582c400..a410957 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -6,7 +6,7 @@\n static void create_directories(const char *path, int path_len,\n \t\t\t       const struct checkout *state)\n {\n-\tchar *buf = xmalloc(path_len + 1);\n+\tchar *buf = xmallocz(path_len);\n \tint len = 0;\n \n \twhile (len < path_len) {\ndiff --git a/grep.c b/grep.c\nindex 7b2b96a..528b652 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1741,7 +1741,7 @@ static int grep_source_load_file(struct grep_source *gs)\n \ti = open(filename, O_RDONLY);\n \tif (i < 0)\n \t\tgoto err_ret;\n-\tdata = xmalloc(size + 1);\n+\tdata = xmallocz(size);\n \tif (st.st_size != read_in_full(i, data, size)) {\n \t\terror(_(\"'%s': short read %s\"), filename, strerror(errno));\n \t\tclose(i);\n@@ -1749,7 +1749,6 @@ static int grep_source_load_file(struct grep_source *gs)\n \t\treturn -1;\n \t}\n \tclose(i);\n-\tdata[size] = 0;\n \n \tgs->buf = data;\n \tgs->size = size;\ndiff --git a/imap-send.c b/imap-send.c\nindex 4d3b773..2c52027 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -892,12 +892,11 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)\n \tresponse = xstrfmt(\"%s %s\", user, hex);\n \tresp_len = strlen(response) + 1;\n \n-\tresponse_64 = xmalloc(ENCODED_SIZE(resp_len) + 1);\n+\tresponse_64 = xmallocz(ENCODED_SIZE(resp_len));\n \tencoded_len = EVP_EncodeBlock((unsigned char *)response_64,\n \t\t\t\t      (unsigned char *)response, resp_len);\n \tif (encoded_len < 0)\n \t\tdie(\"EVP_EncodeBlock error\");\n-\tresponse_64[encoded_len] = '\\0';\n \treturn (char *)response_64;\n }\n \n@@ -1188,7 +1187,7 @@ static void lf_to_crlf(struct strbuf *msg)\n \t\tj++;\n \t}\n \n-\tnew = xmalloc(j + 1);\n+\tnew = xmallocz(j);\n \n \t/*\n \t * Second pass: write the new string.  Note that this loop is\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 0338630..ff4a43a 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -205,7 +205,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tif (fstat(fd, &st))\n \t\tgoto close_bad;\n \tresult->size = st.st_size;\n-\tresult->ptr = xmalloc(result->size + 1);\n+\tresult->ptr = xmallocz(result->size);\n \tif (read_in_full(fd, result->ptr, result->size) != result->size) {\n \t\tfree(result->ptr);\n \t\tresult->ptr = NULL;\ndiff --git a/progress.c b/progress.c\nindex 353bd37..76a88c5 100644\n--- a/progress.c\n+++ b/progress.c\n@@ -247,7 +247,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)\n \t\tsize_t len = strlen(msg) + 5;\n \t\tstruct throughput *tp = progress->throughput;\n \n-\t\tbufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);\n+\t\tbufp = (len < sizeof(buf)) ? buf : xmallocz(len);\n \t\tif (tp) {\n \t\t\tunsigned int rate = !tp->avg_misecs ? 0 :\n \t\t\t\t\ttp->avg_bytes / tp->avg_misecs;\ndiff --git a/refs.c b/refs.c\nindex e2d34b2..1d9e2a7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -124,7 +124,7 @@ int refname_is_safe(const char *refname)\n \t\tchar *buf;\n \t\tint result;\n \n-\t\tbuf = xmalloc(strlen(refname) + 1);\n+\t\tbuf = xmallocz(strlen(refname));\n \t\t/*\n \t\t * Does the refname try to escape refs/?\n \t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\ndiff --git a/setup.c b/setup.c\nindex 0deb022..ab21086 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -88,7 +88,7 @@ char *prefix_path_gently(const char *prefix, int len,\n \tconst char *orig = path;\n \tchar *sanitized;\n \tif (is_absolute_path(orig)) {\n-\t\tsanitized = xmalloc(strlen(path) + 1);\n+\t\tsanitized = xmallocz(strlen(path));\n \t\tif (remaining_prefix)\n \t\t\t*remaining_prefix = 0;\n \t\tif (normalize_path_copy_len(sanitized, path, remaining_prefix)) {\n@@ -488,14 +488,13 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)\n \t\terror_code = READ_GITFILE_ERR_OPEN_FAILED;\n \t\tgoto cleanup_return;\n \t}\n-\tbuf = xmalloc(st.st_size + 1);\n+\tbuf = xmallocz(st.st_size);\n \tlen = read_in_full(fd, buf, st.st_size);\n \tclose(fd);\n \tif (len != st.st_size) {\n \t\terror_code = READ_GITFILE_ERR_READ_FAILED;\n \t\tgoto cleanup_return;\n \t}\n-\tbuf[len] = '\\0';\n \tif (!starts_with(buf, \"gitdir: \")) {\n \t\terror_code = READ_GITFILE_ERR_INVALID_FORMAT;\n \t\tgoto cleanup_return;\ndiff --git a/strbuf.c b/strbuf.c\nindex bab316d..f60e2ee 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -718,7 +718,7 @@ char *xstrdup_tolower(const char *string)\n \tsize_t len, i;\n \n \tlen = strlen(string);\n-\tresult = xmalloc(len + 1);\n+\tresult = xmallocz(len);\n \tfor (i = 0; i < len; i++)\n \t\tresult[i] = tolower(string[i]);\n \tresult[i] = '\\0';\n-- \n2.7.1.572.gf718037\n"},{"id":"278218","messageId":"20160215215244.GG10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:52:44Z","receivedAt":"2016-02-15T21:52:44Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Using FLEX_ARRAY macros reduces the amount of manual\ncomputation size we have to do. It also ensures we don't\noverflow size_t, and it makes sure we write the same number\nof bytes that we allocated.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n attr.c               |  4 +---\n builtin/blame.c      |  4 +---\n builtin/help.c       |  9 +++------\n builtin/mktree.c     |  9 +++++----\n builtin/reflog.c     |  7 ++-----\n cache-tree.c         |  4 +---\n combine-diff.c       |  4 +---\n diff.c               |  7 ++-----\n dir.c                | 16 +++-------------\n hashmap.c            |  3 +--\n help.c               |  6 ++----\n log-tree.c           |  5 ++---\n name-hash.c          |  3 +--\n ref-filter.c         |  6 ++----\n refs.c               |  6 ++----\n refs/files-backend.c | 19 +++++--------------\n remote.c             |  5 +----\n 17 files changed, 35 insertions(+), 82 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex c83ec49..6537a43 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -93,9 +93,7 @@ static struct git_attr *git_attr_internal(const char *name, int len)\n \tif (invalid_attr_name(name, len))\n \t\treturn NULL;\n \n-\ta = xmalloc(sizeof(*a) + len + 1);\n-\tmemcpy(a->name, name, len);\n-\ta->name[len] = 0;\n+\tFLEX_ALLOC_MEM(a, name, name, len);\n \ta->h = hval;\n \ta->next = git_attr_hash[pos];\n \ta->attr_nr = attr_nr++;\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex b4ed462..e982fb8 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -466,13 +466,11 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin,\n static struct origin *make_origin(struct commit *commit, const char *path)\n {\n \tstruct origin *o;\n-\tsize_t pathlen = strlen(path) + 1;\n-\to = xcalloc(1, sizeof(*o) + pathlen);\n+\tFLEX_ALLOC_STR(o, path, path);\n \to->commit = commit;\n \to->refcnt = 1;\n \to->next = commit->util;\n \tcommit->util = o;\n-\tmemcpy(o->path, path, pathlen); /* includes NUL */\n \treturn o;\n }\n \ndiff --git a/builtin/help.c b/builtin/help.c\nindex 1cd0c1e..3c55ce4 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -171,12 +171,10 @@ static void exec_man_cmd(const char *cmd, const char *page)\n static void add_man_viewer(const char *name)\n {\n \tstruct man_viewer_list **p = &man_viewer_list;\n-\tsize_t len = strlen(name);\n \n \twhile (*p)\n \t\tp = &((*p)->next);\n-\t*p = xcalloc(1, (sizeof(**p) + len + 1));\n-\tmemcpy((*p)->name, name, len); /* NUL-terminated by xcalloc */\n+\tFLEX_ALLOC_STR(*p, name, name);\n }\n \n static int supported_man_viewer(const char *name, size_t len)\n@@ -190,9 +188,8 @@ static void do_add_man_viewer_info(const char *name,\n \t\t\t\t   size_t len,\n \t\t\t\t   const char *value)\n {\n-\tstruct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);\n-\n-\tmemcpy(new->name, name, len); /* NUL-terminated by xcalloc */\n+\tstruct man_viewer_info_list *new;\n+\tFLEX_ALLOC_MEM(new, name, name, len);\n \tnew->info = xstrdup(value);\n \tnew->next = man_viewer_info_list;\n \tman_viewer_info_list = new;\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a237caa..4282b62 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -19,16 +19,17 @@ static int alloc, used;\n static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)\n {\n \tstruct treeent *ent;\n-\tint len = strlen(path);\n+\tsize_t len = strlen(path);\n \tif (strchr(path, '/'))\n \t\tdie(\"path %s contains slash\", path);\n \n-\tALLOC_GROW(entries, used + 1, alloc);\n-\tent = entries[used++] = xmalloc(sizeof(**entries) + len + 1);\n+\tFLEX_ALLOC_MEM(ent, name, path, len);\n \tent->mode = mode;\n \tent->len = len;\n \thashcpy(ent->sha1, sha1);\n-\tmemcpy(ent->name, path, len+1);\n+\n+\tALLOC_GROW(entries, used + 1, alloc);\n+\tentries[used++] = ent;\n }\n \n static int ent_compare(const void *a_, const void *b_)\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex f39960e..7c1990f 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -382,11 +382,9 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n {\n \tstruct collected_reflog *e;\n \tstruct collect_reflog_cb *cb = cb_data;\n-\tsize_t namelen = strlen(ref);\n \n-\te = xmalloc(sizeof(*e) + namelen + 1);\n+\tFLEX_ALLOC_STR(e, reflog, ref);\n \thashcpy(e->sha1, oid->hash);\n-\tmemcpy(e->reflog, ref, namelen + 1);\n \tALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);\n \tcb->e[cb->nr++] = e;\n \treturn 0;\n@@ -412,8 +410,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\t    !memcmp(ent->pattern, pattern, len))\n \t\t\treturn ent;\n \n-\tent = xcalloc(1, (sizeof(*ent) + len));\n-\tmemcpy(ent->pattern, pattern, len);\n+\tFLEX_ALLOC_MEM(ent, pattern, pattern, len);\n \tent->len = len;\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 20ee7b5..3ebf9c3 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -79,11 +79,9 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,\n \tALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);\n \tit->subtree_nr++;\n \n-\tdown = xmalloc(sizeof(*down) + pathlen + 1);\n+\tFLEX_ALLOC_MEM(down, name, path, pathlen);\n \tdown->cache_tree = NULL;\n \tdown->namelen = pathlen;\n-\tmemcpy(down->name, path, pathlen);\n-\tdown->name[pathlen] = 0;\n \n \tif (pos < it->subtree_nr)\n \t\tmemmove(it->down + pos + 1,\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 890c415..be09a2b 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -319,7 +319,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)\n \tif (line[len-1] == '\\n')\n \t\tlen--;\n \n-\tlline = xmalloc(sizeof(*lline) + len + 1);\n+\tFLEX_ALLOC_MEM(lline, line, line, len);\n \tlline->len = len;\n \tlline->next = NULL;\n \tlline->prev = sline->plost.lost_tail;\n@@ -330,8 +330,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)\n \tsline->plost.lost_tail = lline;\n \tsline->plost.len++;\n \tlline->parent_map = this_mask;\n-\tmemcpy(lline->line, line, len);\n-\tlline->line[len] = 0;\n }\n \n struct combine_diff_state {\ndiff --git a/diff.c b/diff.c\nindex 2136b69..27d14a7 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2607,12 +2607,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,\n \n struct diff_filespec *alloc_filespec(const char *path)\n {\n-\tint namelen = strlen(path);\n-\tstruct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);\n+\tstruct diff_filespec *spec;\n \n-\tmemset(spec, 0, sizeof(*spec));\n-\tspec->path = (char *)(spec + 1);\n-\tmemcpy(spec->path, path, namelen+1);\n+\tFLEXPTR_ALLOC_STR(spec, path, path);\n \tspec->count = 1;\n \tspec->is_binary = -1;\n \treturn spec;\ndiff --git a/dir.c b/dir.c\nindex 6c627d5..f06ebb7 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -503,12 +503,7 @@ void add_exclude(const char *string, const char *base,\n \n \tparse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);\n \tif (flags & EXC_FLAG_MUSTBEDIR) {\n-\t\tchar *s;\n-\t\tx = xmalloc(sizeof(*x) + patternlen + 1);\n-\t\ts = (char *)(x+1);\n-\t\tmemcpy(s, string, patternlen);\n-\t\ts[patternlen] = '\\0';\n-\t\tx->pattern = s;\n+\t\tFLEXPTR_ALLOC_MEM(x, pattern, string, patternlen);\n \t} else {\n \t\tx = xmalloc(sizeof(*x));\n \t\tx->pattern = string;\n@@ -625,10 +620,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,\n \t}\n \n \tuc->dir_created++;\n-\td = xmalloc(sizeof(*d) + len + 1);\n-\tmemset(d, 0, sizeof(*d));\n-\tmemcpy(d->name, name, len);\n-\td->name[len] = '\\0';\n+\tFLEX_ALLOC_MEM(d, name, name, len);\n \n \tALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);\n \tmemmove(dir->dirs + first + 1, dir->dirs + first,\n@@ -1167,10 +1159,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)\n {\n \tstruct dir_entry *ent;\n \n-\tent = xmalloc(sizeof(*ent) + len + 1);\n+\tFLEX_ALLOC_MEM(ent, name, pathname, len);\n \tent->len = len;\n-\tmemcpy(ent->name, pathname, len);\n-\tent->name[len] = 0;\n \treturn ent;\n }\n \ndiff --git a/hashmap.c b/hashmap.c\nindex f693839..b10b642 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len)\n \te = hashmap_get(&map, &key, data);\n \tif (!e) {\n \t\t/* not found: create it */\n-\t\te = xmallocz(sizeof(struct pool_entry) + len);\n+\t\tFLEX_ALLOC_MEM(e, data, data, len);\n \t\thashmap_entry_init(e, key.ent.hash);\n \t\te->len = len;\n-\t\tmemcpy(e->data, data, len);\n \t\thashmap_add(&map, e);\n \t}\n \treturn e->data;\ndiff --git a/help.c b/help.c\nindex d996b34..19328ea 100644\n--- a/help.c\n+++ b/help.c\n@@ -11,11 +11,9 @@\n \n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n-\tstruct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);\n-\n+\tstruct cmdname *ent;\n+\tFLEX_ALLOC_MEM(ent, name, name, len);\n \tent->len = len;\n-\tmemcpy(ent->name, name, len);\n-\tent->name[len] = 0;\n \n \tALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);\n \tcmds->names[cmds->cnt++] = ent;\ndiff --git a/log-tree.c b/log-tree.c\nindex f70a30e..60f9839 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -77,9 +77,8 @@ int parse_decorate_color_config(const char *var, const char *slot_name, const ch\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)\n {\n-\tint nlen = strlen(name);\n-\tstruct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);\n-\tmemcpy(res->name, name, nlen + 1);\n+\tstruct name_decoration *res;\n+\tFLEX_ALLOC_STR(res, name, name);\n \tres->type = type;\n \tres->next = add_decoration(&name_decoration, obj, res);\n }\ndiff --git a/name-hash.c b/name-hash.c\nindex 332ba95..6d9f23e 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -55,10 +55,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \tdir = find_dir_entry(istate, ce->name, namelen);\n \tif (!dir) {\n \t\t/* not found, create it and add to hash table */\n-\t\tdir = xcalloc(1, sizeof(struct dir_entry) + namelen + 1);\n+\t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n \t\thashmap_entry_init(dir, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n-\t\tstrncpy(dir->name, ce->name, namelen);\n \t\thashmap_add(&istate->dir_hash, dir);\n \n \t\t/* recursively add missing parent directories */\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f097176..9ccfc51 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1255,10 +1255,8 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \t\t\t\t\t\t const unsigned char *objectname,\n \t\t\t\t\t\t int flag)\n {\n-\tsize_t len = strlen(refname);\n-\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n-\tmemcpy(ref->refname, refname, len);\n-\tref->refname[len] = '\\0';\n+\tstruct ref_array_item *ref;\n+\tFLEX_ALLOC_STR(ref, refname, refname);\n \thashcpy(ref->objectname, objectname);\n \tref->flag = flag;\n \ndiff --git a/refs.c b/refs.c\nindex 1d9e2a7..2d86445 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -761,10 +761,8 @@ void ref_transaction_free(struct ref_transaction *transaction)\n static struct ref_update *add_update(struct ref_transaction *transaction,\n \t\t\t\t     const char *refname)\n {\n-\tsize_t len = strlen(refname) + 1;\n-\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n-\n-\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n+\tstruct ref_update *update;\n+\tFLEX_ALLOC_STR(update, refname, refname);\n \tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n \ttransaction->updates[transaction->nr++] = update;\n \treturn update;\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex b569762..81f68f8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -199,17 +199,14 @@ static struct ref_entry *create_ref_entry(const char *refname,\n \t\t\t\t\t  const unsigned char *sha1, int flag,\n \t\t\t\t\t  int check_name)\n {\n-\tint len;\n \tstruct ref_entry *ref;\n \n \tif (check_name &&\n \t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))\n \t\tdie(\"Reference has invalid format: '%s'\", refname);\n-\tlen = strlen(refname) + 1;\n-\tref = xmalloc(sizeof(struct ref_entry) + len);\n+\tFLEX_ALLOC_STR(ref, name, refname);\n \thashcpy(ref->u.value.oid.hash, sha1);\n \toidclr(&ref->u.value.peeled);\n-\tmemcpy(ref->name, refname, len);\n \tref->flag = flag;\n \treturn ref;\n }\n@@ -268,9 +265,7 @@ static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n \t\t\t\t\t  int incomplete)\n {\n \tstruct ref_entry *direntry;\n-\tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n-\tmemcpy(direntry->name, dirname, len);\n-\tdirentry->name[len] = '\\0';\n+\tFLEX_ALLOC_MEM(direntry, name, dirname, len);\n \tdirentry->u.subdir.ref_cache = ref_cache;\n \tdirentry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);\n \treturn direntry;\n@@ -939,13 +934,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)\n  */\n static struct ref_cache *create_ref_cache(const char *submodule)\n {\n-\tint len;\n \tstruct ref_cache *refs;\n \tif (!submodule)\n \t\tsubmodule = \"\";\n-\tlen = strlen(submodule) + 1;\n-\trefs = xcalloc(1, sizeof(struct ref_cache) + len);\n-\tmemcpy(refs->name, submodule, len);\n+\tFLEX_ALLOC_STR(refs, name, submodule);\n \trefs->next = submodule_ref_caches;\n \tsubmodule_ref_caches = refs;\n \treturn refs;\n@@ -2197,10 +2189,9 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)\n \n \t/* Schedule the loose reference for pruning if requested. */\n \tif ((cb->flags & PACK_REFS_PRUNE)) {\n-\t\tint namelen = strlen(entry->name) + 1;\n-\t\tstruct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);\n+\t\tstruct ref_to_prune *n;\n+\t\tFLEX_ALLOC_STR(n, name, entry->name);\n \t\thashcpy(n->sha1, entry->u.value.oid.hash);\n-\t\tmemcpy(n->name, entry->name, namelen); /* includes NUL */\n \t\tn->next = cb->ref_to_prune;\n \t\tcb->ref_to_prune = n;\n \t}\ndiff --git a/remote.c b/remote.c\nindex 02e698a..25a960f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -2136,16 +2136,13 @@ static int one_local_ref(const char *refname, const struct object_id *oid,\n {\n \tstruct ref ***local_tail = cb_data;\n \tstruct ref *ref;\n-\tint len;\n \n \t/* we already know it starts with refs/ to get here */\n \tif (check_refname_format(refname + 5, 0))\n \t\treturn 0;\n \n-\tlen = strlen(refname) + 1;\n-\tref = xcalloc(1, sizeof(*ref) + len);\n+\tref = alloc_ref(refname);\n \toidcpy(&ref->new_oid, oid);\n-\tmemcpy(ref->name, refname, len);\n \t**local_tail = ref;\n \t*local_tail = &ref->next;\n \treturn 0;\n-- \n2.7.1.572.gf718037\n"},{"id":"278219","messageId":"20160215215310.GH10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 08/18] use st_add and st_mult for allocation size computation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:53:11Z","receivedAt":"2016-02-15T21:53:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"If our size computation overflows size_t, we may allocate a\nmuch smaller buffer than we expected and overflow it. It's\nprobably impossible to trigger an overflow in most of these\nsites in practice, but it is easy enough convert their\nadditions and multiplications into overflow-checking\nvariants. This may be fixing real bugs, and it makes\nauditing the code easier.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n archive.c              |  4 ++--\n builtin/apply.c        |  2 +-\n builtin/clean.c        |  2 +-\n builtin/fetch.c        |  2 +-\n builtin/index-pack.c   |  4 ++--\n builtin/merge.c        |  2 +-\n builtin/mv.c           |  4 ++--\n builtin/receive-pack.c |  2 +-\n combine-diff.c         | 14 +++++++-------\n commit.c               |  2 +-\n compat/mingw.c         |  4 ++--\n compat/qsort.c         |  2 +-\n compat/setenv.c        |  2 +-\n compat/win32/syslog.c  |  4 ++--\n diffcore-delta.c       |  6 ++++--\n diffcore-rename.c      |  2 +-\n dir.c                  |  4 ++--\n fast-import.c          |  2 +-\n refs.c                 |  2 +-\n remote.c               |  8 ++++----\n revision.c             |  2 +-\n sha1_file.c            | 20 +++++++++++---------\n sha1_name.c            |  5 ++---\n shallow.c              |  2 +-\n submodule.c            |  6 +++---\n 25 files changed, 56 insertions(+), 53 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 0687afa..5d735ae 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -171,8 +171,8 @@ static void queue_directory(const unsigned char *sha1,\n \t\tunsigned mode, int stage, struct archiver_context *c)\n {\n \tstruct directory *d;\n-\tsize_t len = base->len + 1 + strlen(filename) + 1;\n-\td = xmalloc(sizeof(*d) + len);\n+\tsize_t len = st_add4(base->len, 1, strlen(filename), 1);\n+\td = xmalloc(st_add(sizeof(*d), len));\n \td->up\t   = c->bottom;\n \td->baselen = base->len;\n \td->mode\t   = mode;\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex d61ac65..42c610e 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -2632,7 +2632,7 @@ static void update_image(struct image *img,\n \tinsert_count = postimage->len;\n \n \t/* Adjust the contents */\n-\tresult = xmalloc(img->len + insert_count - remove_count + 1);\n+\tresult = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));\n \tmemcpy(result, img->buf, applied_at);\n \tmemcpy(result + applied_at, postimage->buf, postimage->len);\n \tmemcpy(result + applied_at + postimage->len,\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 8229f7e..0371010 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -615,7 +615,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t\tnr += chosen[i];\n \t\t}\n \n-\t\tresult = xcalloc(nr + 1, sizeof(int));\n+\t\tresult = xcalloc(st_add(nr, 1), sizeof(int));\n \t\tfor (i = 0; i < stuff->nr && j < nr; i++) {\n \t\t\tif (chosen[i])\n \t\t\t\tresult[j++] = i;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8e74213..373a89d 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1110,7 +1110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)\n \tif (argc > 0) {\n \t\tint j = 0;\n \t\tint i;\n-\t\trefs = xcalloc(argc + 1, sizeof(const char *));\n+\t\trefs = xcalloc(st_add(argc, 1), sizeof(const char *));\n \t\tfor (i = 0; i < argc; i++) {\n \t\t\tif (!strcmp(argv[i], \"tag\")) {\n \t\t\t\ti++;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex a60bcfa..193908a 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1744,9 +1744,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \n \tcurr_pack = open_pack_file(pack_name);\n \tparse_pack_header();\n-\tobjects = xcalloc(nr_objects + 1, sizeof(struct object_entry));\n+\tobjects = xcalloc(st_add(nr_objects, 1), sizeof(struct object_entry));\n \tif (show_stat)\n-\t\tobj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat));\n+\t\tobj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));\n \tofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));\n \tparse_pack_objects(pack_sha1);\n \tresolve_deltas();\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex b98a348..101ffef 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -939,7 +939,7 @@ static int setup_with_upstream(const char ***argv)\n \tif (!branch->merge_nr)\n \t\tdie(_(\"No default upstream defined for the current branch.\"));\n \n-\targs = xcalloc(branch->merge_nr + 1, sizeof(char *));\n+\targs = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));\n \tfor (i = 0; i < branch->merge_nr; i++) {\n \t\tif (!branch->merge[i]->dst)\n \t\t\tdie(_(\"No remote-tracking branch for %s from %s\"),\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 9a9813a..aeae855 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -48,9 +48,9 @@ static const char **internal_copy_pathspec(const char *prefix,\n \n static const char *add_slash(const char *path)\n {\n-\tint len = strlen(path);\n+\tsize_t len = strlen(path);\n \tif (path[len - 1] != '/') {\n-\t\tchar *with_slash = xmalloc(len + 2);\n+\t\tchar *with_slash = xmalloc(st_add(len, 2));\n \t\tmemcpy(with_slash, path, len);\n \t\twith_slash[len++] = '/';\n \t\twith_slash[len] = 0;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex ad2fdaa..9b00515 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1378,7 +1378,7 @@ static struct command **queue_command(struct command **tail,\n \n \trefname = line + 82;\n \treflen = linelen - 82;\n-\tcmd = xcalloc(1, sizeof(struct command) + reflen + 1);\n+\tcmd = xcalloc(1, st_add3(sizeof(struct command), reflen, 1));\n \thashcpy(cmd->old_sha1, old_sha1);\n \thashcpy(cmd->new_sha1, new_sha1);\n \tmemcpy(cmd->ref_name, refname, reflen);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex be09a2b..0e1d4b0 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -189,11 +189,11 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,\n \t *   - Else if we have NEW, insert newend lline into base and\n \t *   consume newend\n \t */\n-\tlcs = xcalloc(origbaselen + 1, sizeof(int*));\n-\tdirections = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));\n+\tlcs = xcalloc(st_add(origbaselen, 1), sizeof(int*));\n+\tdirections = xcalloc(st_add(origbaselen, 1), sizeof(enum coalesce_direction*));\n \tfor (i = 0; i < origbaselen + 1; i++) {\n-\t\tlcs[i] = xcalloc(lennew + 1, sizeof(int));\n-\t\tdirections[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));\n+\t\tlcs[i] = xcalloc(st_add(lennew, 1), sizeof(int));\n+\t\tdirections[i] = xcalloc(st_add(lennew, 1), sizeof(enum coalesce_direction));\n \t\tdirections[i][0] = BASE;\n \t}\n \tfor (j = 1; j < lennew + 1; j++)\n@@ -1111,7 +1111,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \tif (result_size && result[result_size-1] != '\\n')\n \t\tcnt++; /* incomplete line */\n \n-\tsline = xcalloc(cnt+2, sizeof(*sline));\n+\tsline = xcalloc(st_add(cnt, 2), sizeof(*sline));\n \tsline[0].bol = result;\n \tfor (lno = 0, cp = result; cp < result + result_size; cp++) {\n \t\tif (*cp == '\\n') {\n@@ -1130,7 +1130,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t/* Even p_lno[cnt+1] is valid -- that is for the end line number\n \t * for deletion hunk at the end.\n \t */\n-\tsline[0].p_lno = xcalloc((cnt+2) * num_parent, sizeof(unsigned long));\n+\tsline[0].p_lno = xcalloc(st_mult(st_add(cnt, 2), num_parent), sizeof(unsigned long));\n \tfor (lno = 0; lno <= cnt; lno++)\n \t\tsline[lno+1].p_lno = sline[lno].p_lno + num_parent;\n \n@@ -1262,7 +1262,7 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p,\n \tstruct diff_filespec *pool;\n \n \tpair = xmalloc(sizeof(*pair));\n-\tpool = xcalloc(num_parent + 1, sizeof(struct diff_filespec));\n+\tpool = xcalloc(st_add(num_parent, 1), sizeof(struct diff_filespec));\n \tpair->one = pool + 1;\n \tpair->two = pool;\n \ndiff --git a/commit.c b/commit.c\nindex 31cd91f..3f4f371 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -147,7 +147,7 @@ struct commit_graft *read_graft_line(char *buf, int len)\n \tif ((len + 1) % entry_size)\n \t\tgoto bad_graft_data;\n \ti = (len + 1) / entry_size - 1;\n-\tgraft = xmalloc(sizeof(*graft) + GIT_SHA1_RAWSZ * i);\n+\tgraft = xmalloc(st_add(sizeof(*graft), st_mult(GIT_SHA1_RAWSZ, i)));\n \tgraft->nr_parent = i;\n \tif (get_oid_hex(buf, &graft->oid))\n \t\tgoto bad_graft_data;\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 0eabe68..60f431b 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -771,7 +771,7 @@ static const char *quote_arg(const char *arg)\n \t\treturn arg;\n \n \t/* insert \\ where necessary */\n-\td = q = xmalloc(len+n+3);\n+\td = q = xmalloc(st_add3(len, n, 3));\n \t*d++ = '\"';\n \twhile (*arg) {\n \t\tif (*arg == '\"')\n@@ -1030,7 +1030,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen\n \t\t\tfree(quoted);\n \t}\n \n-\twargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));\n+\twargs = xmalloc_array(st_add(st_mult(2, args.len), 1), sizeof(wchar_t));\n \txutftowcs(wargs, args.buf, 2 * args.len + 1);\n \tstrbuf_release(&args);\n \ndiff --git a/compat/qsort.c b/compat/qsort.c\nindex 9574d53..7d071af 100644\n--- a/compat/qsort.c\n+++ b/compat/qsort.c\n@@ -47,7 +47,7 @@ static void msort_with_tmp(void *b, size_t n, size_t s,\n void git_qsort(void *b, size_t n, size_t s,\n \t       int (*cmp)(const void *, const void *))\n {\n-\tconst size_t size = n * s;\n+\tconst size_t size = st_mult(n, s);\n \tchar buf[1024];\n \n \tif (size < sizeof(buf)) {\ndiff --git a/compat/setenv.c b/compat/setenv.c\nindex fc1439a..7849f25 100644\n--- a/compat/setenv.c\n+++ b/compat/setenv.c\n@@ -18,7 +18,7 @@ int gitsetenv(const char *name, const char *value, int replace)\n \n \tnamelen = strlen(name);\n \tvaluelen = strlen(value);\n-\tenvstr = malloc((namelen + valuelen + 2));\n+\tenvstr = malloc(st_add3(namelen, valuelen, 2));\n \tif (!envstr) {\n \t\terrno = ENOMEM;\n \t\treturn -1;\ndiff --git a/compat/win32/syslog.c b/compat/win32/syslog.c\nindex d015e43..b905aea 100644\n--- a/compat/win32/syslog.c\n+++ b/compat/win32/syslog.c\n@@ -32,7 +32,7 @@ void syslog(int priority, const char *fmt, ...)\n \t\treturn;\n \t}\n \n-\tstr = malloc(str_len + 1);\n+\tstr = malloc(st_add(str_len, 1));\n \tif (!str) {\n \t\twarning(\"malloc failed: '%s'\", strerror(errno));\n \t\treturn;\n@@ -43,7 +43,7 @@ void syslog(int priority, const char *fmt, ...)\n \tva_end(ap);\n \n \twhile ((pos = strstr(str, \"%1\")) != NULL) {\n-\t\tstr = realloc(str, ++str_len + 1);\n+\t\tstr = realloc(str, st_add(++str_len, 1));\n \t\tif (!str) {\n \t\t\twarning(\"realloc failed: '%s'\", strerror(errno));\n \t\t\treturn;\ndiff --git a/diffcore-delta.c b/diffcore-delta.c\nindex 7cf431d..4159748 100644\n--- a/diffcore-delta.c\n+++ b/diffcore-delta.c\n@@ -53,7 +53,8 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)\n \tint osz = 1 << orig->alloc_log2;\n \tint sz = osz << 1;\n \n-\tnew = xmalloc(sizeof(*orig) + sizeof(struct spanhash) * sz);\n+\tnew = xmalloc(st_add(sizeof(*orig),\n+\t\t\t     st_mult(sizeof(struct spanhash), sz)));\n \tnew->alloc_log2 = orig->alloc_log2 + 1;\n \tnew->free = INITIAL_FREE(new->alloc_log2);\n \tmemset(new->data, 0, sizeof(struct spanhash) * sz);\n@@ -130,7 +131,8 @@ static struct spanhash_top *hash_chars(struct diff_filespec *one)\n \tint is_text = !diff_filespec_is_binary(one);\n \n \ti = INITIAL_HASH_SIZE;\n-\thash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i));\n+\thash = xmalloc(st_add(sizeof(*hash),\n+\t\t\t      st_mult(sizeof(struct spanhash), 1<<i)));\n \thash->alloc_log2 = i;\n \thash->free = INITIAL_FREE(i);\n \tmemset(hash->data, 0, sizeof(struct spanhash) * (1<<i));\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex af1fe08..3b3c1ed 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -537,7 +537,7 @@ void diffcore_rename(struct diff_options *options)\n \t\t\t\trename_dst_nr * rename_src_nr, 50, 1);\n \t}\n \n-\tmx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));\n+\tmx = xcalloc(st_mult(num_create, NUM_CANDIDATE_PER_DST), sizeof(*mx));\n \tfor (dst_cnt = i = 0; i < rename_dst_nr; i++) {\n \t\tstruct diff_filespec *two = rename_dst[i].two;\n \t\tstruct diff_score *m;\ndiff --git a/dir.c b/dir.c\nindex f06ebb7..2c91541 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -689,7 +689,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\treturn 0;\n \t\t}\n \t\tif (buf[size-1] != '\\n') {\n-\t\t\tbuf = xrealloc(buf, size+1);\n+\t\t\tbuf = xrealloc(buf, st_add(size, 1));\n \t\t\tbuf[size++] = '\\n';\n \t\t}\n \t} else {\n@@ -2488,7 +2488,7 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,\n \tnext = data + len + 1;\n \tif (next > rd->end)\n \t\treturn -1;\n-\t*untracked_ = untracked = xmalloc(sizeof(*untracked) + len);\n+\t*untracked_ = untracked = xmalloc(st_add(sizeof(*untracked), len));\n \tmemcpy(untracked, &ud, sizeof(ud));\n \tmemcpy(untracked->name, data, len + 1);\n \tdata = next;\ndiff --git a/fast-import.c b/fast-import.c\nindex a6467cb..3053bb8 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -622,7 +622,7 @@ static void *pool_alloc(size_t len)\n \t\t\treturn xmalloc(len);\n \t\t}\n \t\ttotal_allocd += sizeof(struct mem_pool) + mem_pool_alloc;\n-\t\tp = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc);\n+\t\tp = xmalloc(st_add(sizeof(struct mem_pool), mem_pool_alloc));\n \t\tp->next_pool = mem_pool;\n \t\tp->next_free = (char *) p->space;\n \t\tp->end = p->next_free + mem_pool_alloc;\ndiff --git a/refs.c b/refs.c\nindex 2d86445..b0e6ece 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -906,7 +906,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n \t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n \n-\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n+\t\tscanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len));\n \n \t\toffset = 0;\n \t\tfor (i = 0; i < nr_rules; i++) {\ndiff --git a/remote.c b/remote.c\nindex 25a960f..21e4ec3 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -931,7 +931,7 @@ static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,\n \t\tconst char *name)\n {\n \tsize_t len = strlen(name);\n-\tstruct ref *ref = xcalloc(1, sizeof(struct ref) + prefixlen + len + 1);\n+\tstruct ref *ref = xcalloc(1, st_add4(sizeof(*ref), prefixlen, len, 1));\n \tmemcpy(ref->name, prefix, prefixlen);\n \tmemcpy(ref->name + prefixlen, name, len);\n \treturn ref;\n@@ -948,9 +948,9 @@ struct ref *copy_ref(const struct ref *ref)\n \tsize_t len;\n \tif (!ref)\n \t\treturn NULL;\n-\tlen = strlen(ref->name);\n-\tcpy = xmalloc(sizeof(struct ref) + len + 1);\n-\tmemcpy(cpy, ref, sizeof(struct ref) + len + 1);\n+\tlen = st_add3(sizeof(struct ref), strlen(ref->name), 1);\n+\tcpy = xmalloc(len);\n+\tmemcpy(cpy, ref, len);\n \tcpy->next = NULL;\n \tcpy->symref = xstrdup_or_null(ref->symref);\n \tcpy->remote_status = xstrdup_or_null(ref->remote_status);\ndiff --git a/revision.c b/revision.c\nindex f24ead5..d4ace60 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -540,7 +540,7 @@ struct treesame_state {\n static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)\n {\n \tunsigned n = commit_list_count(commit->parents);\n-\tstruct treesame_state *st = xcalloc(1, sizeof(*st) + n);\n+\tstruct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n));\n \tst->nparents = n;\n \tadd_decoration(&revs->treesame, &commit->object, st);\n \treturn st;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 2f1c6d3..0251700 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -253,7 +253,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,\n {\n \tstruct alternate_object_database *ent;\n \tstruct alternate_object_database *alt;\n-\tint pfxlen, entlen;\n+\tsize_t pfxlen, entlen;\n \tstruct strbuf pathbuf = STRBUF_INIT;\n \n \tif (!is_absolute_path(entry) && relative_base) {\n@@ -273,8 +273,8 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,\n \twhile (pfxlen && pathbuf.buf[pfxlen-1] == '/')\n \t\tpfxlen -= 1;\n \n-\tentlen = pfxlen + 43; /* '/' + 2 hex + '/' + 38 hex + NUL */\n-\tent = xmalloc(sizeof(*ent) + entlen);\n+\tentlen = st_add(pfxlen, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */\n+\tent = xmalloc(st_add(sizeof(*ent), entlen));\n \tmemcpy(ent->base, pathbuf.buf, pfxlen);\n \tstrbuf_release(&pathbuf);\n \n@@ -1134,7 +1134,7 @@ unsigned char *use_pack(struct packed_git *p,\n \n static struct packed_git *alloc_packed_git(int extra)\n {\n-\tstruct packed_git *p = xmalloc(sizeof(*p) + extra);\n+\tstruct packed_git *p = xmalloc(st_add(sizeof(*p), extra));\n \tmemset(p, 0, sizeof(*p));\n \tp->pack_fd = -1;\n \treturn p;\n@@ -1168,7 +1168,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)\n \t * \".pack\" is long enough to hold any suffix we're adding (and\n \t * the use xsnprintf double-checks that)\n \t */\n-\talloc = path_len + strlen(\".pack\") + 1;\n+\talloc = st_add3(path_len, strlen(\".pack\"), 1);\n \tp = alloc_packed_git(alloc);\n \tmemcpy(p->pack_name, path, path_len);\n \n@@ -1196,7 +1196,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)\n struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)\n {\n \tconst char *path = sha1_pack_name(sha1);\n-\tint alloc = strlen(path) + 1;\n+\tsize_t alloc = st_add(strlen(path), 1);\n \tstruct packed_git *p = alloc_packed_git(alloc);\n \n \tmemcpy(p->pack_name, path, alloc); /* includes NUL */\n@@ -1413,10 +1413,12 @@ static void mark_bad_packed_object(struct packed_git *p,\n {\n \tunsigned i;\n \tfor (i = 0; i < p->num_bad_objects; i++)\n-\t\tif (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))\n+\t\tif (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i))\n \t\t\treturn;\n-\tp->bad_object_sha1 = xrealloc(p->bad_object_sha1, 20 * (p->num_bad_objects + 1));\n-\thashcpy(p->bad_object_sha1 + 20 * p->num_bad_objects, sha1);\n+\tp->bad_object_sha1 = xrealloc(p->bad_object_sha1,\n+\t\t\t\t      st_mult(GIT_SHA1_RAWSZ,\n+\t\t\t\t\t      st_add(p->num_bad_objects, 1)));\n+\thashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1);\n \tp->num_bad_objects++;\n }\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex 89918ca..d14346c 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -87,9 +87,8 @@ static void find_short_object_filename(int len, const char *hex_pfx, struct disa\n \t\t * object databases including our own.\n \t\t */\n \t\tconst char *objdir = get_object_directory();\n-\t\tint objdir_len = strlen(objdir);\n-\t\tint entlen = objdir_len + 43;\n-\t\tfakeent = xmalloc(sizeof(*fakeent) + entlen);\n+\t\tsize_t objdir_len = strlen(objdir);\n+\t\tfakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43));\n \t\tmemcpy(fakeent->base, objdir, objdir_len);\n \t\tfakeent->name = fakeent->base + objdir_len + 1;\n \t\tfakeent->name[-1] = '/';\ndiff --git a/shallow.c b/shallow.c\nindex 71163bf..4d554ca 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -389,7 +389,7 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,\n \tunsigned int i, nr;\n \tstruct commit_list *head = NULL;\n \tint bitmap_nr = (info->nr_bits + 31) / 32;\n-\tint bitmap_size = bitmap_nr * sizeof(uint32_t);\n+\tsize_t bitmap_size = st_mult(bitmap_nr, sizeof(uint32_t));\n \tuint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */\n \tuint32_t *bitmap = paint_alloc(info);\n \tstruct commit *c = lookup_commit_reference_gently(sha1, 1);\ndiff --git a/submodule.c b/submodule.c\nindex b83939c..ac61c65 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -123,7 +123,7 @@ static int add_submodule_odb(const char *path)\n \tstruct strbuf objects_directory = STRBUF_INIT;\n \tstruct alternate_object_database *alt_odb;\n \tint ret = 0;\n-\tint alloc;\n+\tsize_t alloc;\n \n \tstrbuf_git_path_submodule(&objects_directory, path, \"objects/\");\n \tif (!is_directory(objects_directory.buf)) {\n@@ -138,8 +138,8 @@ static int add_submodule_odb(const char *path)\n \t\t\t\t\tobjects_directory.len))\n \t\t\tgoto done;\n \n-\talloc = objects_directory.len + 42; /* for \"12/345...\" sha1 */\n-\talt_odb = xmalloc(sizeof(*alt_odb) + alloc);\n+\talloc = st_add(objects_directory.len, 42); /* for \"12/345...\" sha1 */\n+\talt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc));\n \talt_odb->next = alt_odb_list;\n \txsnprintf(alt_odb->base, alloc, \"%s\", objects_directory.buf);\n \talt_odb->name = alt_odb->base + objects_directory.len;\n-- \n2.7.1.572.gf718037\n"},{"id":"278220","messageId":"20160215215336.GI10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 09/18] write_untracked_extension: use FLEX_ALLOC helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:53:37Z","receivedAt":"2016-02-15T21:53:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We perform unchecked additions when computing the size of a\n\"struct ondisk_untracked_cache\". This is unlikely to have an\ninteger overflow in practice, but we'd like to avoid this\ndangerous pattern to make further audits easier.\n\nNote that there's one subtlety here, though.  We protect\nourselves against a NULL exclude_per_dir entry in our\nsource, and avoid calling strlen() on it, keeping \"len\" at\n0. But later, we unconditionally memcpy \"len + 1\" bytes to\nget the trailing NUL byte. If we did have a NULL\nexclude_per_dir, we would read from bogus memory.\n\nAs it turns out, though, we always create this field\npointing to a string literal, so there's no bug. We can just\nget rid of the pointless extra conditional.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n dir.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 2c91541..a4a9d9f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2360,16 +2360,15 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra\n \tstruct ondisk_untracked_cache *ouc;\n \tstruct write_data wd;\n \tunsigned char varbuf[16];\n-\tint len = 0, varint_len;\n-\tif (untracked->exclude_per_dir)\n-\t\tlen = strlen(untracked->exclude_per_dir);\n-\touc = xmalloc(sizeof(*ouc) + len + 1);\n+\tint varint_len;\n+\tsize_t len = strlen(untracked->exclude_per_dir);\n+\n+\tFLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);\n \tstat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);\n \tstat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);\n \thashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);\n \thashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);\n \touc->dir_flags = htonl(untracked->dir_flags);\n-\tmemcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);\n \n \tvarint_len = encode_varint(untracked->ident.len, varbuf);\n \tstrbuf_add(out, varbuf, varint_len);\n-- \n2.7.1.572.gf718037\n"},{"id":"278221","messageId":"20160215215415.GJ10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 10/18] fast-import: simplify allocation in start_packfile","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:54:16Z","receivedAt":"2016-02-15T21:54:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This function allocates a packed_git flex-array, and adds a\nmysterious 2 bytes to the length of the pack_name field. One\nis for the trailing NUL, but the other has no purpose. This\nis probably cargo-culted from add_packed_git, which gets the\n\".idx\" path and needs to allocate enough space to hold the\nmatching \".pack\" (though since 48bcc1c, we calculate the\nsize there differently).\n\nThis site, however, is using the raw path of a tempfile, and\ndoes not need the extra byte. We can just replace the\nallocation with FLEX_ALLOC_STR, which handles the allocation\nand the NUL for us.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n fast-import.c | 5 +----\n 1 file changed, 1 insertion(+), 4 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 3053bb8..9fc7093 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -865,15 +865,12 @@ static void start_packfile(void)\n {\n \tstatic char tmp_file[PATH_MAX];\n \tstruct packed_git *p;\n-\tint namelen;\n \tstruct pack_header hdr;\n \tint pack_fd;\n \n \tpack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),\n \t\t\t      \"pack/tmp_pack_XXXXXX\");\n-\tnamelen = strlen(tmp_file) + 2;\n-\tp = xcalloc(1, sizeof(*p) + namelen);\n-\txsnprintf(p->pack_name, namelen, \"%s\", tmp_file);\n+\tFLEX_ALLOC_STR(p, pack_name, tmp_file);\n \tp->pack_fd = pack_fd;\n \tp->do_not_close = 1;\n \tpack_file = sha1fd(pack_fd, p->pack_name);\n-- \n2.7.1.572.gf718037\n"},{"id":"278223","messageId":"20160215215457.GK10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 11/18] fetch-pack: simplify add_sought_entry","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:54:57Z","receivedAt":"2016-02-15T21:54:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We have two variants of this function, one that takes a\nstring and one that takes a ptr/len combo. But we only call\nthe latter with the length of a NUL-terminated string, so\nour first simplification is to drop it in favor of the\nstring variant.\n\nSince we know we have a string, we can also replace the\nmanual memory computation with a call to alloc_ref().\n\nFurthermore, we can rely on get_oid_hex() to complain if it\nhits the end of the string. That means we can simplify the\ncheck for \"<sha1> <ref>\" versus just \"<ref>\". Rather than\nmanage the ptr/len pair, we can just bump the start of our\nstring forward. The original code over-allocated based on\nthe original \"namelen\" (which wasn't _wrong_, but was simply\nwasteful and confusing).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/fetch-pack.c | 27 +++++++++------------------\n 1 file changed, 9 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 9b2a514..79a611f 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -10,33 +10,24 @@ static const char fetch_pack_usage[] =\n \"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] \"\n \"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]\";\n \n-static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,\n-\t\t\t\t const char *name, int namelen)\n+static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n+\t\t\t     const char *name)\n {\n-\tstruct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);\n+\tstruct ref *ref;\n \tstruct object_id oid;\n-\tconst int chunksz = GIT_SHA1_HEXSZ + 1;\n \n-\tif (namelen > chunksz && name[chunksz - 1] == ' ' &&\n-\t\t!get_oid_hex(name, &oid)) {\n-\t\toidcpy(&ref->old_oid, &oid);\n-\t\tname += chunksz;\n-\t\tnamelen -= chunksz;\n-\t}\n+\tif (!get_oid_hex(name, &oid) && name[GIT_SHA1_HEXSZ] == ' ')\n+\t\tname += GIT_SHA1_HEXSZ + 1;\n+\telse\n+\t\toidclr(&oid);\n \n-\tmemcpy(ref->name, name, namelen);\n-\tref->name[namelen] = '\\0';\n+\tref = alloc_ref(name);\n+\toidcpy(&ref->old_oid, &oid);\n \t(*nr)++;\n \tALLOC_GROW(*sought, *nr, *alloc);\n \t(*sought)[*nr - 1] = ref;\n }\n \n-static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n-\t\t\t     const char *string)\n-{\n-\tadd_sought_entry_mem(sought, nr, alloc, string, strlen(string));\n-}\n-\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, ret;\n-- \n2.7.1.572.gf718037\n"},{"id":"278224","messageId":"20160215215533.GL10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 12/18] test-path-utils: fix normalize_path_copy output buffer size","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:55:33Z","receivedAt":"2016-02-15T21:55:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The normalize_path_copy function needs an output buffer that\nis at least as long as its input (it may shrink the path,\nbut never expand it). However, this test program feeds it\nstatic PATH_MAX-sized buffers, which have no relation to the\ninput size.\n\nIn the normalize_ceiling_entry case, we do at least check\nthe size against PATH_MAX and die(), but that case is even\nmore convoluted. We normalize into a fixed-size buffer, free\nthe original, and then replace it with a strdup'd copy of\nthe result. But normalize_path_copy explicitly allows\nnormalizing in-place, so we can simply do that.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n test-path-utils.c | 15 ++++-----------\n 1 file changed, 4 insertions(+), 11 deletions(-)\n\ndiff --git a/test-path-utils.c b/test-path-utils.c\nindex c3adcd8..0c15f18 100644\n--- a/test-path-utils.c\n+++ b/test-path-utils.c\n@@ -8,21 +8,14 @@\n  */\n static int normalize_ceiling_entry(struct string_list_item *item, void *unused)\n {\n-\tconst char *ceil = item->string;\n-\tint len = strlen(ceil);\n-\tchar buf[PATH_MAX+1];\n+\tchar *ceil = item->string;\n \n-\tif (len == 0)\n+\tif (!*ceil)\n \t\tdie(\"Empty path is not supported\");\n-\tif (len > PATH_MAX)\n-\t\tdie(\"Path \\\"%s\\\" is too long\", ceil);\n \tif (!is_absolute_path(ceil))\n \t\tdie(\"Path \\\"%s\\\" is not absolute\", ceil);\n-\tif (normalize_path_copy(buf, ceil) < 0)\n+\tif (normalize_path_copy(ceil, ceil) < 0)\n \t\tdie(\"Path \\\"%s\\\" could not be normalized\", ceil);\n-\tlen = strlen(buf);\n-\tfree(item->string);\n-\titem->string = xstrdup(buf);\n \treturn 1;\n }\n \n@@ -166,7 +159,7 @@ static struct test_data dirname_data[] = {\n int main(int argc, char **argv)\n {\n \tif (argc == 3 && !strcmp(argv[1], \"normalize_path_copy\")) {\n-\t\tchar *buf = xmalloc(PATH_MAX + 1);\n+\t\tchar *buf = xmallocz(strlen(argv[2]));\n \t\tint rv = normalize_path_copy(buf, argv[2]);\n \t\tif (rv)\n \t\t\tbuf = \"++failed++\";\n-- \n2.7.1.572.gf718037\n"},{"id":"278225","messageId":"20160215215619.GM10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 13/18] sequencer: simplify memory allocation of get_message","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:56:19Z","receivedAt":"2016-02-15T21:56:19Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"For a commit with has \"1234abcd\" and subject \"foo\", this\nfunction produces a struct with three strings:\n\n 1. \"foo\"\n\n 2. \"1234abcd... foo\"\n\n 3. \"parent of 1234abcd... foo\"\n\nIt takes advantage of the fact that these strings are\nsubsets of each other, and allocates only _one_ string, with\npointers into the various parts. Unfortunately, this makes\nthe string allocation complicated and hard to follow.\n\nSince we keep only one of these in memory at a time, we can\nafford to simply allocate three strings. This lets us build\non tools like xstrfmt and avoid manual computation.\n\nWhile we're here, we can also drop the ad-hoc\nreimplementation of get_git_commit_encoding(), and simply\ncall that function.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n sequencer.c | 29 ++++++++++-------------------\n 1 file changed, 10 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8048786..e66f2fe 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -124,42 +124,33 @@ static const char *action_name(const struct replay_opts *opts)\n \n struct commit_message {\n \tchar *parent_label;\n-\tconst char *label;\n-\tconst char *subject;\n+\tchar *label;\n+\tchar *subject;\n \tconst char *message;\n };\n \n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n-\tint abbrev_len, subject_len;\n-\tchar *q;\n-\n-\tif (!git_commit_encoding)\n-\t\tgit_commit_encoding = \"UTF-8\";\n+\tint subject_len;\n \n-\tout->message = logmsg_reencode(commit, NULL, git_commit_encoding);\n+\tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n \tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n-\tabbrev_len = strlen(abbrev);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n-\tout->parent_label = xmalloc(strlen(\"parent of \") + abbrev_len +\n-\t\t\t      strlen(\"... \") + subject_len + 1);\n-\tq = out->parent_label;\n-\tq = mempcpy(q, \"parent of \", strlen(\"parent of \"));\n-\tout->label = q;\n-\tq = mempcpy(q, abbrev, abbrev_len);\n-\tq = mempcpy(q, \"... \", strlen(\"... \"));\n-\tout->subject = q;\n-\tq = mempcpy(q, subject, subject_len);\n-\t*q = '\\0';\n+\tout->subject = xmemdupz(subject, subject_len);\n+\tout->label = xstrfmt(\"%s... %s\", abbrev, out->subject);\n+\tout->parent_label = xstrfmt(\"parent of %s\", out->label);\n+\n \treturn 0;\n }\n \n static void free_message(struct commit *commit, struct commit_message *msg)\n {\n \tfree(msg->parent_label);\n+\tfree(msg->label);\n+\tfree(msg->subject);\n \tunuse_commit_buffer(commit, msg->message);\n }\n \n-- \n2.7.1.572.gf718037\n"},{"id":"278226","messageId":"20160215215625.GN10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 14/18] git-compat-util: drop mempcpy compat code","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:56:25Z","receivedAt":"2016-02-15T21:56:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There are no callers of this left, as the last one was\ndropped in the previous patch. And there are no likely to be\nnew ones, as the function has been around since 2010 without\ngaining any new callers.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 9 ---------\n 1 file changed, 9 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 8f23801..6892e72 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -681,7 +681,6 @@ extern int git_vsnprintf(char *str, size_t maxsize,\n #ifdef __GLIBC_PREREQ\n #if __GLIBC_PREREQ(2, 1)\n #define HAVE_STRCHRNUL\n-#define HAVE_MEMPCPY\n #endif\n #endif\n \n@@ -695,14 +694,6 @@ static inline char *gitstrchrnul(const char *s, int c)\n }\n #endif\n \n-#ifndef HAVE_MEMPCPY\n-#define mempcpy gitmempcpy\n-static inline void *gitmempcpy(void *dest, const void *src, size_t n)\n-{\n-\treturn (char *)memcpy(dest, src, n) + n;\n-}\n-#endif\n-\n #ifdef NO_INET_PTON\n int inet_pton(int af, const char *src, void *dst);\n #endif\n-- \n2.7.1.572.gf718037\n"},{"id":"278227","messageId":"20160215215648.GO10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 15/18] transport_anonymize_url: use xstrfmt","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:56:48Z","receivedAt":"2016-02-15T21:56:48Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This function uses xcalloc and two memcpy calls to\nconcatenate two strings. We can do this as an xstrfmt\none-liner, and then it is more clear that we are allocating\nthe correct amount of memory.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n transport.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex 5c63295..d53e4aa 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1351,7 +1351,7 @@ int transport_disconnect(struct transport *transport)\n  */\n char *transport_anonymize_url(const char *url)\n {\n-\tchar *anon_url, *scheme_prefix, *anon_part;\n+\tchar *scheme_prefix, *anon_part;\n \tsize_t anon_len, prefix_len = 0;\n \n \tanon_part = strchr(url, '@');\n@@ -1385,10 +1385,8 @@ char *transport_anonymize_url(const char *url)\n \t\t\tgoto literal_copy;\n \t\tprefix_len = scheme_prefix - url + 3;\n \t}\n-\tanon_url = xcalloc(1, 1 + prefix_len + anon_len);\n-\tmemcpy(anon_url, url, prefix_len);\n-\tmemcpy(anon_url + prefix_len, anon_part, anon_len);\n-\treturn anon_url;\n+\treturn xstrfmt(\"%.*s%.*s\", (int)prefix_len, url,\n+\t\t       (int)anon_len, anon_part);\n literal_copy:\n \treturn xstrdup(url);\n }\n-- \n2.7.1.572.gf718037\n"},{"id":"278228","messageId":"20160215215658.GP10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 16/18] diff_populate_gitlink: use a strbuf","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:56:58Z","receivedAt":"2016-02-15T21:56:58Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We allocate 100 bytes to hold the \"Submodule commit ...\"\ntext. This is enough, but it's not immediately obvious that\nthis is the case, and we have to repeat the magic 100 twice.\n\nWe could get away with xstrfmt here, but we want to know the\nsize, as well, so let's use a real strbuf. And while we're\nhere, we can clean up the logic around size_only. It\ncurrently sets and clears the \"data\" field pointlessly, and\nleaves the \"should_free\" flag on even after we have cleared\nthe data.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 27d14a7..a70ec6e 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2704,21 +2704,21 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \n static int diff_populate_gitlink(struct diff_filespec *s, int size_only)\n {\n-\tint len;\n-\tchar *data = xmalloc(100), *dirty = \"\";\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tchar *dirty = \"\";\n \n \t/* Are we looking at the work tree? */\n \tif (s->dirty_submodule)\n \t\tdirty = \"-dirty\";\n \n-\tlen = snprintf(data, 100,\n-\t\t       \"Subproject commit %s%s\\n\", sha1_to_hex(s->sha1), dirty);\n-\ts->data = data;\n-\ts->size = len;\n-\ts->should_free = 1;\n+\tstrbuf_addf(&buf, \"Subproject commit %s%s\\n\", sha1_to_hex(s->sha1), dirty);\n+\ts->size = buf.len;\n \tif (size_only) {\n \t\ts->data = NULL;\n-\t\tfree(data);\n+\t\tstrbuf_release(&buf);\n+\t} else {\n+\t\ts->data = strbuf_detach(&buf, NULL);\n+\t\ts->should_free = 1;\n \t}\n \treturn 0;\n }\n-- \n2.7.1.572.gf718037\n"},{"id":"278229","messageId":"20160215215710.GQ10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 17/18] convert ewah/bitmap code to use xmalloc","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:57:10Z","receivedAt":"2016-02-15T21:57:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This code was originally written with the idea that it could\nbe spun off into its own ewah library, and uses the\noverrideable ewah_malloc to do allocations.\n\nWe plug in xmalloc as our ewah_malloc, of course. But over\nthe years the ewah code itself has become more entangled\nwith git, and the return value of many ewah_malloc sites is\nnot checked.\n\nLet's just drop the level of indirection and use xmalloc and\nfriends directly. This saves a few lines, and will let us\nadapt these sites to our more advanced malloc helpers.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ewah/bitmap.c      | 12 ++++++------\n ewah/ewah_bitmap.c |  9 +++------\n ewah/ewah_io.c     | 10 ++--------\n ewah/ewok.h        | 10 ----------\n 4 files changed, 11 insertions(+), 30 deletions(-)\n\ndiff --git a/ewah/bitmap.c b/ewah/bitmap.c\nindex 47ad674..c88daa0 100644\n--- a/ewah/bitmap.c\n+++ b/ewah/bitmap.c\n@@ -25,8 +25,8 @@\n \n struct bitmap *bitmap_new(void)\n {\n-\tstruct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap));\n-\tbitmap->words = ewah_calloc(32, sizeof(eword_t));\n+\tstruct bitmap *bitmap = xmalloc(sizeof(struct bitmap));\n+\tbitmap->words = xcalloc(32, sizeof(eword_t));\n \tbitmap->word_alloc = 32;\n \treturn bitmap;\n }\n@@ -38,8 +38,8 @@ void bitmap_set(struct bitmap *self, size_t pos)\n \tif (block >= self->word_alloc) {\n \t\tsize_t old_size = self->word_alloc;\n \t\tself->word_alloc = block * 2;\n-\t\tself->words = ewah_realloc(self->words,\n-\t\t\tself->word_alloc * sizeof(eword_t));\n+\t\tself->words = xrealloc(self->words,\n+\t\t\t\t      self->word_alloc * sizeof(eword_t));\n \n \t\tmemset(self->words + old_size, 0x0,\n \t\t\t(self->word_alloc - old_size) * sizeof(eword_t));\n@@ -102,7 +102,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)\n \twhile (ewah_iterator_next(&blowup, &it)) {\n \t\tif (i >= bitmap->word_alloc) {\n \t\t\tbitmap->word_alloc *= 1.5;\n-\t\t\tbitmap->words = ewah_realloc(\n+\t\t\tbitmap->words = xrealloc(\n \t\t\t\tbitmap->words, bitmap->word_alloc * sizeof(eword_t));\n \t\t}\n \n@@ -134,7 +134,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)\n \n \tif (self->word_alloc < other_final) {\n \t\tself->word_alloc = other_final;\n-\t\tself->words = ewah_realloc(self->words,\n+\t\tself->words = xrealloc(self->words,\n \t\t\tself->word_alloc * sizeof(eword_t));\n \t\tmemset(self->words + original_size, 0x0,\n \t\t\t(self->word_alloc - original_size) * sizeof(eword_t));\ndiff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c\nindex b522437..fcd465e 100644\n--- a/ewah/ewah_bitmap.c\n+++ b/ewah/ewah_bitmap.c\n@@ -39,7 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)\n \t\treturn;\n \n \tself->alloc_size = new_size;\n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \tself->rlw = self->buffer + (rlw_offset / sizeof(eword_t));\n }\n@@ -282,11 +282,8 @@ struct ewah_bitmap *ewah_new(void)\n {\n \tstruct ewah_bitmap *self;\n \n-\tself = ewah_malloc(sizeof(struct ewah_bitmap));\n-\tif (self == NULL)\n-\t\treturn NULL;\n-\n-\tself->buffer = ewah_malloc(32 * sizeof(eword_t));\n+\tself = xmalloc(sizeof(struct ewah_bitmap));\n+\tself->buffer = xmalloc(32 * sizeof(eword_t));\n \tself->alloc_size = 32;\n \n \tewah_clear(self);\ndiff --git a/ewah/ewah_io.c b/ewah/ewah_io.c\nindex 43481b9..4acff97 100644\n--- a/ewah/ewah_io.c\n+++ b/ewah/ewah_io.c\n@@ -134,12 +134,9 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)\n \tself->buffer_size = self->alloc_size = get_be32(ptr);\n \tptr += sizeof(uint32_t);\n \n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \n-\tif (!self->buffer)\n-\t\treturn -1;\n-\n \t/*\n \t * Copy the raw data for the bitmap as a whole chunk;\n \t * if we're in a little-endian platform, we'll perform\n@@ -180,12 +177,9 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)\n \t\treturn -1;\n \n \tself->buffer_size = self->alloc_size = (size_t)ntohl(word_count);\n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \n-\tif (!self->buffer)\n-\t\treturn -1;\n-\n \t/** 64 bit x N -- compressed words */\n \tbuffer = self->buffer;\n \twords_left = self->buffer_size;\ndiff --git a/ewah/ewok.h b/ewah/ewok.h\nindex 6e2c5e1..269a1a8 100644\n--- a/ewah/ewok.h\n+++ b/ewah/ewok.h\n@@ -20,16 +20,6 @@\n #ifndef __EWOK_BITMAP_H__\n #define __EWOK_BITMAP_H__\n \n-#ifndef ewah_malloc\n-#\tdefine ewah_malloc xmalloc\n-#endif\n-#ifndef ewah_realloc\n-#\tdefine ewah_realloc xrealloc\n-#endif\n-#ifndef ewah_calloc\n-#\tdefine ewah_calloc xcalloc\n-#endif\n-\n struct strbuf;\n typedef uint64_t eword_t;\n #define BITS_IN_EWORD (sizeof(eword_t) * 8)\n-- \n2.7.1.572.gf718037\n"},{"id":"278230","messageId":"20160215215717.GR10287@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH 18/18] ewah: convert to REALLOC_ARRAY, etc","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T21:57:18Z","receivedAt":"2016-02-15T21:57:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Now that we're built around xmalloc and friends, we can use\nhelpers like REALLOC_ARRAY, ALLOC_GROW, and so on to make\nthe code shorter and protect against integer overflow.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ewah/bitmap.c      | 16 ++++------------\n ewah/ewah_bitmap.c |  5 ++---\n ewah/ewah_io.c     |  6 ++----\n 3 files changed, 8 insertions(+), 19 deletions(-)\n\ndiff --git a/ewah/bitmap.c b/ewah/bitmap.c\nindex c88daa0..7103cee 100644\n--- a/ewah/bitmap.c\n+++ b/ewah/bitmap.c\n@@ -17,7 +17,7 @@\n  * along with this program; if not, write to the Free Software\n  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n  */\n-#include \"git-compat-util.h\"\n+#include \"cache.h\"\n #include \"ewok.h\"\n \n #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))\n@@ -38,9 +38,7 @@ void bitmap_set(struct bitmap *self, size_t pos)\n \tif (block >= self->word_alloc) {\n \t\tsize_t old_size = self->word_alloc;\n \t\tself->word_alloc = block * 2;\n-\t\tself->words = xrealloc(self->words,\n-\t\t\t\t      self->word_alloc * sizeof(eword_t));\n-\n+\t\tREALLOC_ARRAY(self->words, self->word_alloc);\n \t\tmemset(self->words + old_size, 0x0,\n \t\t\t(self->word_alloc - old_size) * sizeof(eword_t));\n \t}\n@@ -100,12 +98,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)\n \tewah_iterator_init(&it, ewah);\n \n \twhile (ewah_iterator_next(&blowup, &it)) {\n-\t\tif (i >= bitmap->word_alloc) {\n-\t\t\tbitmap->word_alloc *= 1.5;\n-\t\t\tbitmap->words = xrealloc(\n-\t\t\t\tbitmap->words, bitmap->word_alloc * sizeof(eword_t));\n-\t\t}\n-\n+\t\tALLOC_GROW(bitmap->words, i + 1, bitmap->word_alloc);\n \t\tbitmap->words[i++] = blowup;\n \t}\n \n@@ -134,8 +127,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)\n \n \tif (self->word_alloc < other_final) {\n \t\tself->word_alloc = other_final;\n-\t\tself->words = xrealloc(self->words,\n-\t\t\tself->word_alloc * sizeof(eword_t));\n+\t\tREALLOC_ARRAY(self->words, self->word_alloc);\n \t\tmemset(self->words + original_size, 0x0,\n \t\t\t(self->word_alloc - original_size) * sizeof(eword_t));\n \t}\ndiff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c\nindex fcd465e..2dc9c82 100644\n--- a/ewah/ewah_bitmap.c\n+++ b/ewah/ewah_bitmap.c\n@@ -39,8 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)\n \t\treturn;\n \n \tself->alloc_size = new_size;\n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \tself->rlw = self->buffer + (rlw_offset / sizeof(eword_t));\n }\n \n@@ -283,8 +282,8 @@ struct ewah_bitmap *ewah_new(void)\n \tstruct ewah_bitmap *self;\n \n \tself = xmalloc(sizeof(struct ewah_bitmap));\n-\tself->buffer = xmalloc(32 * sizeof(eword_t));\n \tself->alloc_size = 32;\n+\tALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \tewah_clear(self);\n \treturn self;\ndiff --git a/ewah/ewah_io.c b/ewah/ewah_io.c\nindex 4acff97..61f6a43 100644\n--- a/ewah/ewah_io.c\n+++ b/ewah/ewah_io.c\n@@ -134,8 +134,7 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)\n \tself->buffer_size = self->alloc_size = get_be32(ptr);\n \tptr += sizeof(uint32_t);\n \n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \t/*\n \t * Copy the raw data for the bitmap as a whole chunk;\n@@ -177,8 +176,7 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)\n \t\treturn -1;\n \n \tself->buffer_size = self->alloc_size = (size_t)ntohl(word_count);\n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \t/** 64 bit x N -- compressed words */\n \tbuffer = self->buffer;\n-- \n2.7.1.572.gf718037\n"},{"id":"278232","messageId":"20160215220212.GA10461@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"Re: [PATCH 0/18] hardening allocations against integer overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-15T22:02:13Z","receivedAt":"2016-02-15T22:02:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 04:45:16PM -0500, Jeff King wrote:\n\n> The only bug I have actually confirmed in practice here is fixed by\n> patch 2 (which is why it's at the front). There's another one in\n> path_name(), but that function is already dropped by the nearby\n> jk/lose-name-path topic.\n> \n> The rest are cleanups of spots which _might_ be buggy, but I didn't dig\n> too far to find out. As with the earlier audit, I tried to refactor\n> using helpers that make the code clearer and less error-prone. So maybe\n> they're fixing bugs or not, but they certainly make it easier to audit\n> the result for problems.\n\nAfter this, looking for /[cm]alloc.*\\+/ is pretty clean. I _didn't_ fix\nany sites in xdiff, but those are already protected by dcd1742 (xdiff:\nreject files larger than ~1GB, 2015-09-24).\n\nThat's not necessarily complete coverage, though, as you can always\nscrew up the computation outside of the xmalloc call, and pass in the\ntruncated version. E.g.:\n\n  int alloc = a + b;\n  char *foo = xmalloc(alloc);\n\nHowever, this is only a big problem if you then copy \"a\" and \"b\"\nseparately. If you use \"alloc\" later as the limit, like:\n\n  xsnprintf(foo, alloc, \"%s%s\", a, b);\n\nthat's only a minor bug (we notice the overflow and complain, rather\nthan smashing the heap).\n\n-Peff\n"},{"id":"278260","messageId":"CAPig+cQAU6y4VfGen0N6vNiDt+rjdcDM8YC+BF9HpvVj2WTUng@mail.gmail.com","threadId":"41418","inReplyTo":"20160215215054.GD10287@sigill.intra.peff.net","subject":"Re: [PATCH 04/18] add helpers for allocating flex-array structs","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T01:47:30Z","receivedAt":"2016-02-16T01:47:30Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 4:50 PM, Jeff King <peff@peff.net> wrote:\n> Allocating a struct with a flex array is pretty simple in\n> practice: you over-allocate the struct, then copy some data\n> into the over-allocation. But it can be a slight pain to\n> make sure you're allocating and copying the right amounts.\n>\n> This patch adds a few helpers to turn simple cases of into a\n\nGrammo: \"cases of into\"\n\n> one-liner that properly checks for overflow. See the\n> embedded documentation for details.\n> [...]\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> @@ -782,6 +782,68 @@ extern FILE *fopen_for_writing(const char *path);\n> + *   struct foo *f;\n> + *   FLEX_ALLOC_STR(f, name, src);\n> + *\n> + * and \"name\" will point to a block of memory after the struct, which will be\n> + * freed along with the struct (but the pointer can be repoined anywhere).\n\n\"repoined\"?\n\n> + * The *_STR variants accept a string parameter rather than a ptr/len\n> + * combination.\n"},{"id":"278261","messageId":"CAPig+cSQG7gWStpRy76D_YzuCFPsXJLBzXCjQ-X_Q3sZthx3iw@mail.gmail.com","threadId":"41418","inReplyTo":"20160215215244.GG10287@sigill.intra.peff.net","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T02:17:05Z","receivedAt":"2016-02-16T02:17:05Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 4:52 PM, Jeff King <peff@peff.net> wrote:\n> Using FLEX_ARRAY macros reduces the amount of manual\n> computation size we have to do. It also ensures we don't\n> overflow size_t, and it makes sure we write the same number\n> of bytes that we allocated.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> diff --git a/builtin/reflog.c b/builtin/reflog.c\n> @@ -412,8 +410,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n>                     !memcmp(ent->pattern, pattern, len))\n>                         return ent;\n>\n> -       ent = xcalloc(1, (sizeof(*ent) + len));\n> -       memcpy(ent->pattern, pattern, len);\n> +       FLEX_ALLOC_MEM(ent, pattern, pattern, len);\n\nDoes the incoming 'len' already account for the NUL terminator, or was\nthe original code underallocating?\n\nAnswering my own question: Looking at reflog_expire_config() and\nparse_config_key(), I gather that 'len' already accounts for the NUL,\nthus the new code is overallocating (which should not be a problem).\n\n>         ent->len = len;\n>         *reflog_expire_cfg_tail = ent;\n>         reflog_expire_cfg_tail = &(ent->next);\n> diff --git a/hashmap.c b/hashmap.c\n> @@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len)\n>         e = hashmap_get(&map, &key, data);\n>         if (!e) {\n>                 /* not found: create it */\n> -               e = xmallocz(sizeof(struct pool_entry) + len);\n> +               FLEX_ALLOC_MEM(e, data, data, len);\n\nDitto. I guess the new code is overallocating (which should be okay).\n\n>                 hashmap_entry_init(e, key.ent.hash);\n>                 e->len = len;\n> -               memcpy(e->data, data, len);\n>                 hashmap_add(&map, e);\n>         }\n>         return e->data;\n"},{"id":"278263","messageId":"20160216025201.GA13606@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cQAU6y4VfGen0N6vNiDt+rjdcDM8YC+BF9HpvVj2WTUng@mail.gmail.com","subject":"Re: [PATCH 04/18] add helpers for allocating flex-array structs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T02:52:01Z","receivedAt":"2016-02-16T02:52:01Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 08:47:30PM -0500, Eric Sunshine wrote:\n\n> > This patch adds a few helpers to turn simple cases of into a\n> \n> Grammo: \"cases of into\"\n\nOops. Cases of \"flex-array struct allocation into...\".\n\n> > + * and \"name\" will point to a block of memory after the struct, which will be\n> > + * freed along with the struct (but the pointer can be repoined anywhere).\n> \n> \"repoined\"?\n\nRepointed.\n\nFixed patch below.\n\n-- >8 --\nSubject: [PATCH] add helpers for allocating flex-array structs\n\nAllocating a struct with a flex array is pretty simple in\npractice: you over-allocate the struct, then copy some data\ninto the over-allocation. But it can be a slight pain to\nmake sure you're allocating and copying the right amounts.\n\nThis patch adds a few helpers to turn simple cases of\nflex-array struct allocation into a one-liner that properly\nchecks for overflow. See the embedded documentation for\ndetails.\n\nIdeally we could provide a more flexible version that could\nhandle multiple strings, like:\n\n  FLEX_ALLOC_FMT(ref, name, \"%s%s\", prefix, name);\n\nBut we have to implement this as a macro (because of the\noffset calculation of the flex member), which means we would\nneed all compilers to support variadic macros.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 62 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 55c073d..e71e615 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -782,6 +782,68 @@ extern FILE *fopen_for_writing(const char *path);\n #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n \n+/*\n+ * These functions help you allocate structs with flex arrays, and copy\n+ * the data directly into the array. For example, if you had:\n+ *\n+ *   struct foo {\n+ *     int bar;\n+ *     char name[FLEX_ARRAY];\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_MEM(f, name, src, len);\n+ *\n+ * to allocate a \"foo\" with the contents of \"src\" in the \"name\" field.\n+ * The resulting struct is automatically zero'd, and the flex-array field\n+ * is NUL-terminated (whether the incoming src buffer was or not).\n+ *\n+ * The FLEXPTR_* variants operate on structs that don't use flex-arrays,\n+ * but do want to store a pointer to some extra data in the same allocated\n+ * block. For example, if you have:\n+ *\n+ *   struct foo {\n+ *     char *name;\n+ *     int bar;\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_STR(f, name, src);\n+ *\n+ * and \"name\" will point to a block of memory after the struct, which will be\n+ * freed along with the struct (but the pointer can be repointed anywhere).\n+ *\n+ * The *_STR variants accept a string parameter rather than a ptr/len\n+ * combination.\n+ *\n+ * Note that these macros will evaluate the first parameter multiple\n+ * times, and it must be assignable as an lvalue.\n+ */\n+#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \\\n+\t(x) = NULL; /* silence -Wuninitialized for offset calculation */ \\\n+\t(x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \\\n+} while (0)\n+#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \\\n+\t(x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \\\n+\t(x)->ptrname = (void *)((x)+1); \\\n+} while(0)\n+#define FLEX_ALLOC_STR(x, flexname, str) \\\n+\tFLEX_ALLOC_MEM((x), flexname, (str), strlen(str))\n+#define FLEXPTR_ALLOC_STR(x, ptrname, str) \\\n+\tFLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))\n+\n+static inline void *xalloc_flex(size_t base_len, size_t offset,\n+\t\t\t\tconst void *src, size_t src_len)\n+{\n+\tunsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));\n+\tmemcpy(ret + offset, src, src_len);\n+\treturn ret;\n+}\n+\n static inline char *xstrdup_or_null(const char *str)\n {\n \treturn str ? xstrdup(str) : NULL;\n-- \n2.7.1.574.gccd43a9\n"},{"id":"278264","messageId":"20160216031554.GB13606@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cSQG7gWStpRy76D_YzuCFPsXJLBzXCjQ-X_Q3sZthx3iw@mail.gmail.com","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T03:15:54Z","receivedAt":"2016-02-16T03:15:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 09:17:05PM -0500, Eric Sunshine wrote:\n\n> > ---\n> > diff --git a/builtin/reflog.c b/builtin/reflog.c\n> > @@ -412,8 +410,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n> >                     !memcmp(ent->pattern, pattern, len))\n> >                         return ent;\n> >\n> > -       ent = xcalloc(1, (sizeof(*ent) + len));\n> > -       memcpy(ent->pattern, pattern, len);\n> > +       FLEX_ALLOC_MEM(ent, pattern, pattern, len);\n> \n> Does the incoming 'len' already account for the NUL terminator, or was\n> the original code underallocating?\n> \n> Answering my own question: Looking at reflog_expire_config() and\n> parse_config_key(), I gather that 'len' already accounts for the NUL,\n> thus the new code is overallocating (which should not be a problem).\n\nActually, I think the original underallocates. If we have\ngc.foobar.reflogExpire, then \"pattern\" will poitn to \"foobar\" and \"len\"\nwill be 6. Meaning we allocate without a trailing NUL.\n\nThat _should_ be OK, because the struct has a \"len\" field, and readers\ncan be careful not to go past it. And indeed, in the loop above, we\ncheck the length and use memcmp().\n\nBut later, in set_reflog_expiry_param(), we walk through the list and\nhand ent->pattern directly to wildmatch, which assumes a NUL-terminated\nstring. In practice, it probably works out 7 out of 8 times, because\nmalloc will align the struct, and we're on a zeroed page, so unless the\nstring is exactly 8 characters, we'll get some extra NULs afterwards.\nBut I could demonstrate it by doing:\n\n  gdb --args git -c gc.foobar12.reflogexpire=never reflog expire --all\n\nand breaking on wildmatch, which yields:\n\n  Breakpoint 1, wildmatch (pattern=0x85eb70 \"foobar12Q\", text=0x85e4d4\n\t\"refs/heads/master\", flags=0, wo=0x0)\n\nSo this is in fact fixing a bug. I can't say I'm terribly surprised\nnobody noticed it, as per-ref reflog expiration is pretty obscure.\n\nI hope this increases confidence in my patch series. Even though I\ndidn't _know_ there was a bug here, I did know that malloc computations\nare a potential source of errors. And the FLEX_ALLOC helpers are\ndesigned to remove that work and have a simple interface. We don't know\nwhether the caller will want a NUL afterwards or not, but we err on the\nside of over-allocating by a byte (just as we over-allocate\nread_sha1_file() output by a byte), because safety is better than\nsqueezing out a single byte.\n\n> > diff --git a/hashmap.c b/hashmap.c\n> > @@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len)\n> >         e = hashmap_get(&map, &key, data);\n> >         if (!e) {\n> >                 /* not found: create it */\n> > -               e = xmallocz(sizeof(struct pool_entry) + len);\n> > +               FLEX_ALLOC_MEM(e, data, data, len);\n> \n> Ditto. I guess the new code is overallocating (which should be okay).\n\nIt is, but so was the original (it used xmallocz to get an extra NUL).\n\n-Peff\n"},{"id":"278266","messageId":"20160216032626.GA19954@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160216031554.GB13606@sigill.intra.peff.net","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T03:26:27Z","receivedAt":"2016-02-16T03:26:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 10:15:54PM -0500, Jeff King wrote:\n\n> > Answering my own question: Looking at reflog_expire_config() and\n> > parse_config_key(), I gather that 'len' already accounts for the NUL,\n> > thus the new code is overallocating (which should not be a problem).\n> \n> Actually, I think the original underallocates. If we have\n> gc.foobar.reflogExpire, then \"pattern\" will poitn to \"foobar\" and \"len\"\n> will be 6. Meaning we allocate without a trailing NUL.\n> \n> That _should_ be OK, because the struct has a \"len\" field, and readers\n> can be careful not to go past it. And indeed, in the loop above, we\n> check the length and use memcmp().\n> \n> But later, in set_reflog_expiry_param(), we walk through the list and\n> hand ent->pattern directly to wildmatch, which assumes a NUL-terminated\n> string. In practice, it probably works out 7 out of 8 times, because\n> malloc will align the struct, and we're on a zeroed page, so unless the\n> string is exactly 8 characters, we'll get some extra NULs afterwards.\n> But I could demonstrate it by doing:\n> \n>   gdb --args git -c gc.foobar12.reflogexpire=never reflog expire --all\n> \n> and breaking on wildmatch, which yields:\n> \n>   Breakpoint 1, wildmatch (pattern=0x85eb70 \"foobar12Q\", text=0x85e4d4\n> \t\"refs/heads/master\", flags=0, wo=0x0)\n> \n> So this is in fact fixing a bug. I can't say I'm terribly surprised\n> nobody noticed it, as per-ref reflog expiration is pretty obscure.\n\nWe could do this on top of my series (I can also factor out the fix\nseparately to go at the beginning if we don't want to hold the bugfix\nhostage).\n\n-- >8 --\nSubject: [PATCH] reflog_expire_cfg: drop misleading \"len\" parameter\n\nYou can tweak the reflog expiration for a particular subset\nof refs by configuring gc.foo.reflogexpire. We keep a linked\nlist of reflog_expire_cfg structs, each of which holds the\npattern and a \"len\" field for the length of the pattern.\n\nHowever, we feed the pattern directly to wildmatch(), which\nmeans that it must be a NUL-terminated string. Before the\nrecent conversion to FLEX_ALLOC_MEM, we got this wrong, and\ncould feed extra garbage to wildmatch(). That's now fixed,\nbut the \"len\" parameter is simply misleading. The pattern is\na string, and we don't need to record its length.\n\nTo get rid of it, we do need to tweak the \"do we have it\nalready?\" search in find_cfg_ent(), but we can do so without\nhaving a recorded length by just using strncmp.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/reflog.c | 6 ++----\n 1 file changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 7c1990f..2d46b64 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -394,7 +394,6 @@ static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n \tunsigned long expire_total;\n \tunsigned long expire_unreachable;\n-\tsize_t len;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -406,12 +405,11 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\treflog_expire_cfg_tail = &reflog_expire_cfg;\n \n \tfor (ent = reflog_expire_cfg; ent; ent = ent->next)\n-\t\tif (ent->len == len &&\n-\t\t    !memcmp(ent->pattern, pattern, len))\n+\t\tif (!strncmp(ent->pattern, pattern, len) &&\n+\t\t    ent->pattern[len] == '\\0')\n \t\t\treturn ent;\n \n \tFLEX_ALLOC_MEM(ent, pattern, pattern, len);\n-\tent->len = len;\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\n \treturn ent;\n-- \n2.7.1.574.gccd43a9\n"},{"id":"278269","messageId":"20160216033620.GA26430@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160216032626.GA19954@sigill.intra.peff.net","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T03:36:20Z","receivedAt":"2016-02-16T03:36:20Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 10:26:26PM -0500, Jeff King wrote:\n\n> We could do this on top of my series (I can also factor out the fix\n> separately to go at the beginning if we don't want to hold the bugfix\n> hostage).\n> \n> -- >8 --\n> Subject: [PATCH] reflog_expire_cfg: drop misleading \"len\" parameter\n\nHere it is as a separate fix. Applying my series on top would need a\nminor and obvious tweak. I'll hold a re-roll for more comments, but will\notherwise plan to stick this at the front of the series.\n\n-- >8 --\nSubject: [PATCH] reflog_expire_cfg: NUL-terminate pattern field\n\nYou can tweak the reflog expiration for a particular subset\nof refs by configuring gc.foo.reflogexpire. We keep a linked\nlist of reflog_expire_cfg structs, each of which holds the\npattern and a \"len\" field for the length of the pattern. The\npattern itself is _not_ NUL-terminated.\n\nHowever, we feed the pattern directly to wildmatch(), which\nexpects a NUL-terminated string, meaning it may keep reading\nrandom junk after our struct.\n\nWe can fix this by allocating an extra byte for the NUL\n(which is already zero because we use xcalloc). Let's also\ndrop the misleading \"len\" field, which is no longer\nnecessary. The existing use of \"len\" can be converted to use\nstrncmp().\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/reflog.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex f39960e..9980731 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -396,7 +396,6 @@ static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n \tunsigned long expire_total;\n \tunsigned long expire_unreachable;\n-\tsize_t len;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -408,13 +407,12 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\treflog_expire_cfg_tail = &reflog_expire_cfg;\n \n \tfor (ent = reflog_expire_cfg; ent; ent = ent->next)\n-\t\tif (ent->len == len &&\n-\t\t    !memcmp(ent->pattern, pattern, len))\n+\t\tif (!strncmp(ent->pattern, pattern, len) &&\n+\t\t    ent->pattern[len] == '\\0')\n \t\t\treturn ent;\n \n-\tent = xcalloc(1, (sizeof(*ent) + len));\n+\tent = xcalloc(1, sizeof(*ent) + len + 1);\n \tmemcpy(ent->pattern, pattern, len);\n-\tent->len = len;\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\n \treturn ent;\n-- \n2.7.1.574.gccd43a9\n"},{"id":"278270","messageId":"CAPig+cSyz7uYeHu=nP_V+6LaaWJZ-Bv6CR=9hmF8_cf74mnuHA@mail.gmail.com","threadId":"41418","inReplyTo":"20160216031554.GB13606@sigill.intra.peff.net","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T04:10:41Z","receivedAt":"2016-02-16T04:10:41Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 10:15 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Feb 15, 2016 at 09:17:05PM -0500, Eric Sunshine wrote:\n>> > -       ent = xcalloc(1, (sizeof(*ent) + len));\n>> > -       memcpy(ent->pattern, pattern, len);\n>> > +       FLEX_ALLOC_MEM(ent, pattern, pattern, len);\n>>\n>> Does the incoming 'len' already account for the NUL terminator, or was\n>> the original code underallocating?\n>>\n>> Answering my own question: Looking at reflog_expire_config() and\n>> parse_config_key(), I gather that 'len' already accounts for the NUL,\n>> thus the new code is overallocating (which should not be a problem).\n>\n> Actually, I think the original underallocates. If we have\n> gc.foobar.reflogExpire, then \"pattern\" will poitn to \"foobar\" and \"len\"\n> will be 6. Meaning we allocate without a trailing NUL.\n\nUgh, yeah, I misread the code.\n\n> That _should_ be OK, because the struct has a \"len\" field, and readers\n> can be careful not to go past it. And indeed, in the loop above, we\n> check the length and use memcmp().\n>\n> But later, in set_reflog_expiry_param(), we walk through the list and\n> hand ent->pattern directly to wildmatch, which assumes a NUL-terminated\n> string. In practice, it probably works out 7 out of 8 times, because\n> malloc will align the struct, and we're on a zeroed page, so unless the\n> string is exactly 8 characters, we'll get some extra NULs afterwards.\n> But I could demonstrate it by doing:\n>\n>   gdb --args git -c gc.foobar12.reflogexpire=never reflog expire --all\n>\n> and breaking on wildmatch, which yields:\n>\n>   Breakpoint 1, wildmatch (pattern=0x85eb70 \"foobar12Q\", text=0x85e4d4\n>         \"refs/heads/master\", flags=0, wo=0x0)\n\nNice confirmation.\n"},{"id":"278271","messageId":"CAPig+cQOF7CsJNoiu8FAMk+csrOWG2dbEyxqfpWNwvGdUsjxcw@mail.gmail.com","threadId":"41418","inReplyTo":"20160216033620.GA26430@sigill.intra.peff.net","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T04:18:56Z","receivedAt":"2016-02-16T04:18:56Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 10:36 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Feb 15, 2016 at 10:26:26PM -0500, Jeff King wrote:\n>> We could do this on top of my series (I can also factor out the fix\n>> separately to go at the beginning if we don't want to hold the bugfix\n>> hostage).\n>>\n>> -- >8 --\n>> Subject: [PATCH] reflog_expire_cfg: drop misleading \"len\" parameter\n>\n> Here it is as a separate fix. Applying my series on top would need a\n> minor and obvious tweak. I'll hold a re-roll for more comments, but will\n> otherwise plan to stick this at the front of the series.\n\nYep, I prefer this version of the patch too, as it makes it explicit\nthat a bug is being fixed rather than it happening \"by accident\" via\nthe FLEX_ALLOC_MEM conversion, which is easily overlooked.\n\n> -- >8 --\n> Subject: [PATCH] reflog_expire_cfg: NUL-terminate pattern field\n>\n> You can tweak the reflog expiration for a particular subset\n> of refs by configuring gc.foo.reflogexpire. We keep a linked\n> list of reflog_expire_cfg structs, each of which holds the\n> pattern and a \"len\" field for the length of the pattern. The\n> pattern itself is _not_ NUL-terminated.\n>\n> However, we feed the pattern directly to wildmatch(), which\n> expects a NUL-terminated string, meaning it may keep reading\n> random junk after our struct.\n>\n> We can fix this by allocating an extra byte for the NUL\n> (which is already zero because we use xcalloc). Let's also\n> drop the misleading \"len\" field, which is no longer\n> necessary. The existing use of \"len\" can be converted to use\n> strncmp().\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> diff --git a/builtin/reflog.c b/builtin/reflog.c\n> @@ -408,13 +407,12 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n>                 reflog_expire_cfg_tail = &reflog_expire_cfg;\n>\n>         for (ent = reflog_expire_cfg; ent; ent = ent->next)\n> -               if (ent->len == len &&\n> -                   !memcmp(ent->pattern, pattern, len))\n> +               if (!strncmp(ent->pattern, pattern, len) &&\n> +                   ent->pattern[len] == '\\0')\n\nIf 'ent->pattern' is shorter than 'pattern' then the strncmp() will\nfail, thus it will short-circuit before ent->pattern[len] has a chance\nto access beyond the end of memory allocated for 'ent->pattern'. Okay,\nmakes sense.\n\n>                         return ent;\n>\n> -       ent = xcalloc(1, (sizeof(*ent) + len));\n> +       ent = xcalloc(1, sizeof(*ent) + len + 1);\n>         memcpy(ent->pattern, pattern, len);\n> -       ent->len = len;\n>         *reflog_expire_cfg_tail = ent;\n>         reflog_expire_cfg_tail = &(ent->next);\n>         return ent;\n> --\n> 2.7.1.574.gccd43a9\n"},{"id":"278272","messageId":"CAPig+cRTz4Fb10JDWLjmTEXzQ+FbvmKU51A9B3vmwBepDX+BYA@mail.gmail.com","threadId":"41418","inReplyTo":"20160215215154.GE10287@sigill.intra.peff.net","subject":"Re: [PATCH 05/18] convert trivial cases to ALLOC_ARRAY","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T04:22:12Z","receivedAt":"2016-02-16T04:22:12Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 4:51 PM, Jeff King <peff@peff.net> wrote:\n> Each of these cases can be converted to use ALLOC_ARRAY or\n> REALLOC_ARRAY, which has two advantages:\n>\n>   1. It automatically checks the array-size multiplication\n>      for overflow.\n>\n>   2. It always uses sizeof(*array) for the element-size,\n>      so that it can never go out of sync with the declared\n>      type of the array.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> diff --git a/compat/mingw.c b/compat/mingw.c\n> index 77a51d3..0eabe68 100644\n> --- a/compat/mingw.c\n> +++ b/compat/mingw.c\n> @@ -854,7 +854,7 @@ static char **get_path_split(void)\n>         if (!n)\n>                 return NULL;\n>\n> -       path = xmalloc((n+1)*sizeof(char *));\n> +       ALLOC_ARRAY(path, n+1);\n\nElsewhere in this patch, you've reformatted \"x+c\" as \"x + c\"; perhaps\ndo so here, as well.\n\n>         p = envpath;\n>         i = 0;\n>         do {\n"},{"id":"278273","messageId":"20160216042222.GA27060@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cQOF7CsJNoiu8FAMk+csrOWG2dbEyxqfpWNwvGdUsjxcw@mail.gmail.com","subject":"Re: [PATCH 07/18] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T04:22:22Z","receivedAt":"2016-02-16T04:22:22Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 11:18:56PM -0500, Eric Sunshine wrote:\n\n> > diff --git a/builtin/reflog.c b/builtin/reflog.c\n> > @@ -408,13 +407,12 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n> >                 reflog_expire_cfg_tail = &reflog_expire_cfg;\n> >\n> >         for (ent = reflog_expire_cfg; ent; ent = ent->next)\n> > -               if (ent->len == len &&\n> > -                   !memcmp(ent->pattern, pattern, len))\n> > +               if (!strncmp(ent->pattern, pattern, len) &&\n> > +                   ent->pattern[len] == '\\0')\n> \n> If 'ent->pattern' is shorter than 'pattern' then the strncmp() will\n> fail, thus it will short-circuit before ent->pattern[len] has a chance\n> to access beyond the end of memory allocated for 'ent->pattern'. Okay,\n> makes sense.\n\nYeah. It took me a minute to convince myself that this was correct. If\nyou have a shorter or more clear way of writing it, I'm open to it. The\nbest I could come up with is running an extra \"strlen\" and otherwise\nkeeping the loop as it is; the performance on that is not as good, but\nif performance is a concern, maybe something besides a linear search\nwould be in order. :)\n\n-Peff\n"},{"id":"278274","messageId":"20160216042346.GB27060@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cRTz4Fb10JDWLjmTEXzQ+FbvmKU51A9B3vmwBepDX+BYA@mail.gmail.com","subject":"Re: [PATCH 05/18] convert trivial cases to ALLOC_ARRAY","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T04:23:46Z","receivedAt":"2016-02-16T04:23:46Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 11:22:12PM -0500, Eric Sunshine wrote:\n\n> On Mon, Feb 15, 2016 at 4:51 PM, Jeff King <peff@peff.net> wrote:\n> > Each of these cases can be converted to use ALLOC_ARRAY or\n> > REALLOC_ARRAY, which has two advantages:\n> >\n> >   1. It automatically checks the array-size multiplication\n> >      for overflow.\n> >\n> >   2. It always uses sizeof(*array) for the element-size,\n> >      so that it can never go out of sync with the declared\n> >      type of the array.\n> >\n> > Signed-off-by: Jeff King <peff@peff.net>\n> > ---\n> > diff --git a/compat/mingw.c b/compat/mingw.c\n> > index 77a51d3..0eabe68 100644\n> > --- a/compat/mingw.c\n> > +++ b/compat/mingw.c\n> > @@ -854,7 +854,7 @@ static char **get_path_split(void)\n> >         if (!n)\n> >                 return NULL;\n> >\n> > -       path = xmalloc((n+1)*sizeof(char *));\n> > +       ALLOC_ARRAY(path, n+1);\n> \n> Elsewhere in this patch, you've reformatted \"x+c\" as \"x + c\"; perhaps\n> do so here, as well.\n\nWill do. I noticed while going over this before sending it out that it\nmay also be technically possible for \"n+1\" to overflow here (and I think\nin a few other places in this patch). I don't know how paranoid we want\nto be.\n\n-Peff\n"},{"id":"278275","messageId":"CAPig+cSn29QtcWKRAaKMDzObuXetEySrVtLogkzfZXKXjPeufQ@mail.gmail.com","threadId":"41418","inReplyTo":"20160216042346.GB27060@sigill.intra.peff.net","subject":"Re: [PATCH 05/18] convert trivial cases to ALLOC_ARRAY","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T04:32:25Z","receivedAt":"2016-02-16T04:32:25Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 11:23 PM, Jeff King <peff@peff.net> wrote:\n> On Mon, Feb 15, 2016 at 11:22:12PM -0500, Eric Sunshine wrote:\n>> On Mon, Feb 15, 2016 at 4:51 PM, Jeff King <peff@peff.net> wrote:\n>> > -       path = xmalloc((n+1)*sizeof(char *));\n>> > +       ALLOC_ARRAY(path, n+1);\n>>\n>> Elsewhere in this patch, you've reformatted \"x+c\" as \"x + c\"; perhaps\n>> do so here, as well.\n>\n> Will do. I noticed while going over this before sending it out that it\n> may also be technically possible for \"n+1\" to overflow here (and I think\n> in a few other places in this patch). I don't know how paranoid we want\n> to be.\n\nYes, I also noticed those and considered mentioning it. There was also\nsome multiplication which might be of concern.\n\n    ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);\n\nIt would be easy enough to manually call st_add() and st_mult() for\nthose cases, but I haven't examined them closely enough to determine\nhow likely they would be to overflow, nor do I know if the resulting\nnoisiness of code is desirable.\n"},{"id":"278277","messageId":"20160216054637.GA28237@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cSn29QtcWKRAaKMDzObuXetEySrVtLogkzfZXKXjPeufQ@mail.gmail.com","subject":"Re: [PATCH 05/18] convert trivial cases to ALLOC_ARRAY","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-16T05:46:37Z","receivedAt":"2016-02-16T05:46:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 15, 2016 at 11:32:25PM -0500, Eric Sunshine wrote:\n\n> On Mon, Feb 15, 2016 at 11:23 PM, Jeff King <peff@peff.net> wrote:\n> > On Mon, Feb 15, 2016 at 11:22:12PM -0500, Eric Sunshine wrote:\n> >> On Mon, Feb 15, 2016 at 4:51 PM, Jeff King <peff@peff.net> wrote:\n> >> > -       path = xmalloc((n+1)*sizeof(char *));\n> >> > +       ALLOC_ARRAY(path, n+1);\n> >>\n> >> Elsewhere in this patch, you've reformatted \"x+c\" as \"x + c\"; perhaps\n> >> do so here, as well.\n> >\n> > Will do. I noticed while going over this before sending it out that it\n> > may also be technically possible for \"n+1\" to overflow here (and I think\n> > in a few other places in this patch). I don't know how paranoid we want\n> > to be.\n> \n> Yes, I also noticed those and considered mentioning it. There was also\n> some multiplication which might be of concern.\n> \n>     ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);\n> \n> It would be easy enough to manually call st_add() and st_mult() for\n> those cases, but I haven't examined them closely enough to determine\n> how likely they would be to overflow, nor do I know if the resulting\n> noisiness of code is desirable.\n\nYeah, I'm quite sure that one is safe (we set column_capacity to a fixed\ninteger immediately beforehand). And many of the \"+\" ones are likely\nsafe, too.  If \"n\" is close to wrapping, then allocating \"n\" structs\nwill probably fail beforehand (though not always, if you have a ton of\nRAM and \"n\" is a signed int).\n\nBut part of the point of this series is that we shouldn't have to wonder\nif things are safe. They should just be obviously so, and we should err\non the side of caution. So I think it probably _is_ worth sprinkling\nst_add() calls in those places. I'll take a look for the re-roll.\n\n-Peff\n"},{"id":"278278","messageId":"CAPig+cT0P0noxEEM3xCLyYzSFhKXQqW42L3v8EwHraF9Y_5-dg@mail.gmail.com","threadId":"41418","inReplyTo":"20160215215310.GH10287@sigill.intra.peff.net","subject":"Re: [PATCH 08/18] use st_add and st_mult for allocation size computation","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T05:47:24Z","receivedAt":"2016-02-16T05:47:24Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 4:53 PM, Jeff King <peff@peff.net> wrote:\n> If our size computation overflows size_t, we may allocate a\n> much smaller buffer than we expected and overflow it. It's\n> probably impossible to trigger an overflow in most of these\n> sites in practice, but it is easy enough convert their\n> additions and multiplications into overflow-checking\n> variants. This may be fixing real bugs, and it makes\n> auditing the code easier.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> diff --git a/builtin/apply.c b/builtin/apply.c\n> @@ -2632,7 +2632,7 @@ static void update_image(struct image *img,\n> -       result = xmalloc(img->len + insert_count - remove_count + 1);\n> +       result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));\n\nPhew, what a mouthful, and not easy to read compared to the original.\nFortunately, the remainder of the changes in this patch are\nstraightforward and often simple.\n\n> diff --git a/sha1_name.c b/sha1_name.c\n> @@ -87,9 +87,8 @@ static void find_short_object_filename(int len, const char *hex_pfx, struct disa\n>                 const char *objdir = get_object_directory();\n> -               int objdir_len = strlen(objdir);\n> -               int entlen = objdir_len + 43;\n> -               fakeent = xmalloc(sizeof(*fakeent) + entlen);\n> +               size_t objdir_len = strlen(objdir);\n> +               fakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43));\n>                 memcpy(fakeent->base, objdir, objdir_len);\n>                 fakeent->name = fakeent->base + objdir_len + 1;\n\nIf we've gotten this far without die()ing due to overflow in st_add3()\nwhen invoking xmalloc(), then we know that this fakeent->name\ncomputation won't overflow. Okay.\n\n>                 fakeent->name[-1] = '/';\n"},{"id":"278280","messageId":"CAPig+cTLemy=YGVQFZVyA7V+EJcU_Z5KTw2nJ9LiJKa36van+A@mail.gmail.com","threadId":"41418","inReplyTo":"20160215215619.GM10287@sigill.intra.peff.net","subject":"Re: [PATCH 13/18] sequencer: simplify memory allocation of get_message","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T06:05:05Z","receivedAt":"2016-02-16T06:05:05Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 4:56 PM, Jeff King <peff@peff.net> wrote:\n> For a commit with has \"1234abcd\" and subject \"foo\", this\n\nDid you mean s/with has/which has ID/ or something?\n\n> function produces a struct with three strings:\n>\n>  1. \"foo\"\n>\n>  2. \"1234abcd... foo\"\n>\n>  3. \"parent of 1234abcd... foo\"\n>\n> It takes advantage of the fact that these strings are\n> subsets of each other, and allocates only _one_ string, with\n> pointers into the various parts. Unfortunately, this makes\n> the string allocation complicated and hard to follow.\n>\n> Since we keep only one of these in memory at a time, we can\n> afford to simply allocate three strings. This lets us build\n> on tools like xstrfmt and avoid manual computation.\n>\n> While we're here, we can also drop the ad-hoc\n> reimplementation of get_git_commit_encoding(), and simply\n> call that function.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n"},{"id":"278281","messageId":"CAPig+cTD-xbtRmt+z+CTB_-KoY9MnB2J7bhQTfYtrnTQOSOeQQ@mail.gmail.com","threadId":"41418","inReplyTo":"20160215215625.GN10287@sigill.intra.peff.net","subject":"Re: [PATCH 14/18] git-compat-util: drop mempcpy compat code","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-16T06:05:41Z","receivedAt":"2016-02-16T06:05:41Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Feb 15, 2016 at 4:56 PM, Jeff King <peff@peff.net> wrote:\n> There are no callers of this left, as the last one was\n> dropped in the previous patch. And there are no likely to be\n\ns/no/not\n\n> new ones, as the function has been around since 2010 without\n> gaining any new callers.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n"},{"id":"278637","messageId":"20160219111941.GA31906@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160215214516.GA4015@sigill.intra.peff.net","subject":"[PATCH v2 0/21] hardening allocations against integer overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:19:41Z","receivedAt":"2016-02-19T11:19:41Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Here's a re-roll of jk/tighten-alloc series from:\n\n  http://thread.gmane.org/gmane.comp.version-control.git/286253\n\nThis one fixes all of the minor typo/gramm-o problems from the first\nround. As Eric noted, the change to reflog_expire_cfg is an actual\nbug-fix. Rather than silently fixing it, I've bumped the fix out to its\nown commit at the front of the series.\n\nI also took a look at the raw computation in the ALLOC_ARRAY and\nREALLOC_ARRAY lines, as well as the ones in ALLOC_GROW. In theory\nsomething like this is dangerous:\n\n  ALLOC_GROW(foo, nr_foo + 1, alloc_foo);\n  foo[nr_foo++] = whatever;\n\nif we overflow nr_foo, which is quite often an \"int\". In practice, I\nthink we're OK, for two reasons:\n\n  1. Overflowing a signed \"int\" here is going to make it go negative\n     (technically, it invokes undefined behavior, but let's be blindly\n     pragmatic for a minute and assume twos-complement wrapping). On a\n     system with a 64-bit size_t, that will try to allocate an enormous\n     amount of memory and fail. On a 32 bit system, it will be only\n     about 2GB.  But...\n\n  2. We're talking about overflowing 2^31 counters here. And the counter\n     is multiplied by the size of each object we're storing in the\n     array. So even if we assume that foo is \"char *\", we know we've\n     allocated close to 2GB already. On a 32-bit system, the subsequent\n     2GB allocation is pretty much guaranteed to fail.\n\n     On a 64-bit system, I suspect it's possible to convince some of\n     these counters to wrap (e.g., storing an array of ints, we're\n     talking about only 8GB; that's a lot, but plenty of machines,\n     especially servers, can allocate that).\n\nSo I have a feeling we're mostly OK there, but the reasoning is\ncertainly hand-wavy and I'd like to do better. Just switching to:\n\n  ALLOC_GROW(foo, st_add(nr_foo, 1), alloc_foo);\n  foo[nr_foo++] = whatever;\n\ndoesn't quite cut it. We might succeed in the allocation, and it stays\nbig, which is good. But if nr_foo is an int, and we wrap to negative\nvalues, we'll start writing to memory before \"foo\", corrupting the heap.\n\nSo I really think we need to look at each site (and there are a lot of\nthem) and start using size_t more consistently for these. Or\nalternatively, have an int-sized version of st_add and use that, though\nit's probably just as much work to convert it to a size_t, which IMHO is\nmore correct. I really wanted to make a type-agnostic version of\nst_add(), but I don't think it's possible to do so portably. My best\nattempts needed either typeof() or compiler intrinsics.\n\nSo I've punted on that for this series, because I'm not convinced there\nare active problems, and it's quite a lot of work (and the patches will\nbe quite disruptive).\n\nWhile pondering this, I also looked at what happens if an incoming\npackfile claims to have 2^32 objects in its header. In index-pack we\nactually read this into a signed \"int\". Which is kind of bad, but in\npractice means we run into the \"whoops, I can't allocate (size_t)-1\nmemory\" problem and die. We could change this to a uint32_t (which is\nwhat the actual incoming format supports), but I have a feeling that\nmakes things worse (if we actually manage to process that many objects,\nwe then start doing some other computations based on the number of\nobjects, all using ints; so at least as it is now, we bail early).\n\nWhile peeking at some of these sites, though, I did realize that many of\nthe ones that became \"ALLOC_ARRAY(foo + 1)\" were doing so to make a\nNULL-terminated argv list. So there are two new patches in this\niteration to switch them to argv_array (one to catch the mundane cases,\nand one for a unique snowflake).\n\n  [01/21]: reflog_expire_cfg: NUL-terminate pattern field\n  [02/21]: add helpers for detecting size_t overflow\n  [03/21]: tree-diff: catch integer overflow in combine_diff_path allocation\n  [04/21]: harden REALLOC_ARRAY and xcalloc against size_t overflow\n  [05/21]: add helpers for allocating flex-array structs\n  [06/21]: convert manual allocations to argv_array\n  [07/21]: convert trivial cases to ALLOC_ARRAY\n  [08/21]: use xmallocz to avoid size arithmetic\n  [09/21]: convert trivial cases to FLEX_ARRAY macros\n  [10/21]: use st_add and st_mult for allocation size computation\n  [11/21]: prepare_{git,shell}_cmd: use argv_array\n  [12/21]: write_untracked_extension: use FLEX_ALLOC helper\n  [13/21]: fast-import: simplify allocation in start_packfile\n  [14/21]: fetch-pack: simplify add_sought_entry\n  [15/21]: test-path-utils: fix normalize_path_copy output buffer size\n  [16/21]: sequencer: simplify memory allocation of get_message\n  [17/21]: git-compat-util: drop mempcpy compat code\n  [18/21]: transport_anonymize_url: use xstrfmt\n  [19/21]: diff_populate_gitlink: use a strbuf\n  [20/21]: convert ewah/bitmap code to use xmalloc\n  [21/21]: ewah: convert to REALLOC_ARRAY, etc\n\n-Peff\n"},{"id":"278639","messageId":"20160219112108.GA9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 01/21] reflog_expire_cfg: NUL-terminate pattern field","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:21:08Z","receivedAt":"2016-02-19T11:21:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"You can tweak the reflog expiration for a particular subset\nof refs by configuring gc.foo.reflogexpire. We keep a linked\nlist of reflog_expire_cfg structs, each of which holds the\npattern and a \"len\" field for the length of the pattern. The\npattern itself is _not_ NUL-terminated.\n\nHowever, we feed the pattern directly to wildmatch(), which\nexpects a NUL-terminated string, meaning it may keep reading\nrandom junk after our struct.\n\nWe can fix this by allocating an extra byte for the NUL\n(which is already zero because we use xcalloc). Let's also\ndrop the misleading \"len\" field, which is no longer\nnecessary. The existing use of \"len\" can be converted to use\nstrncmp().\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/reflog.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex f39960e..9980731 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -396,7 +396,6 @@ static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n \tunsigned long expire_total;\n \tunsigned long expire_unreachable;\n-\tsize_t len;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -408,13 +407,12 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\treflog_expire_cfg_tail = &reflog_expire_cfg;\n \n \tfor (ent = reflog_expire_cfg; ent; ent = ent->next)\n-\t\tif (ent->len == len &&\n-\t\t    !memcmp(ent->pattern, pattern, len))\n+\t\tif (!strncmp(ent->pattern, pattern, len) &&\n+\t\t    ent->pattern[len] == '\\0')\n \t\t\treturn ent;\n \n-\tent = xcalloc(1, (sizeof(*ent) + len));\n+\tent = xcalloc(1, sizeof(*ent) + len + 1);\n \tmemcpy(ent->pattern, pattern, len);\n-\tent->len = len;\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\n \treturn ent;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278638","messageId":"20160219112119.GB9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 02/21] add helpers for detecting size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:21:19Z","receivedAt":"2016-02-19T11:21:19Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Performing computations on size_t variables that we feed to\nxmalloc and friends can be dangerous, as an integer overflow\ncan cause us to allocate a much smaller chunk than we\nrealized.\n\nWe already have unsigned_add_overflows(), but let's add\nunsigned_mult_overflows() to that. Furthermore, rather than\nhave each site manually check and die on overflow, we can\nprovide some helpers that will:\n\n  - promote the arguments to size_t, so that we know we are\n    doing our computation in the same size of integer that\n    will ultimately be fed to xmalloc\n\n  - check and die on overflow\n\n  - return the result so that computations can be done in\n    the parameter list of xmalloc.\n\nThese functions are a lot uglier to use than normal\narithmetic operators (you have to do \"st_add(foo, bar)\"\ninstead of \"foo + bar\"). To at least limit the damage, we\nalso provide multi-valued versions. So rather than:\n\n  st_add(st_add(a, b), st_add(c, d));\n\nyou can write:\n\n  st_add4(a, b, c, d);\n\nThis isn't nearly as elegant as a varargs function, but it's\na lot harder to get it wrong. You don't have to remember to\nadd a sentinel value at the end, and the compiler will\ncomplain if you get the number of arguments wrong. This\npatch adds only the numbered variants required to convert\nthe current code base; we can easily add more later if\nneeded.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 34 ++++++++++++++++++++++++++++++++++\n 1 file changed, 34 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 693a336..0c65033 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -96,6 +96,14 @@\n #define unsigned_add_overflows(a, b) \\\n     ((b) > maximum_unsigned_value_of_type(a) - (a))\n \n+/*\n+ * Returns true if the multiplication of \"a\" and \"b\" will\n+ * overflow. The types of \"a\" and \"b\" must match and must be unsigned.\n+ * Note that this macro evaluates \"a\" twice!\n+ */\n+#define unsigned_mult_overflows(a, b) \\\n+    ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))\n+\n #ifdef __GNUC__\n #define TYPEOF(x) (__typeof__(x))\n #else\n@@ -713,6 +721,32 @@ extern void release_pack_memory(size_t);\n typedef void (*try_to_free_t)(size_t);\n extern try_to_free_t set_try_to_free_routine(try_to_free_t);\n \n+static inline size_t st_add(size_t a, size_t b)\n+{\n+\tif (unsigned_add_overflows(a, b))\n+\t\tdie(\"size_t overflow: %\"PRIuMAX\" + %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a + b;\n+}\n+#define st_add3(a,b,c)   st_add((a),st_add((b),(c)))\n+#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))\n+\n+static inline size_t st_mult(size_t a, size_t b)\n+{\n+\tif (unsigned_mult_overflows(a, b))\n+\t\tdie(\"size_t overflow: %\"PRIuMAX\" * %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a * b;\n+}\n+\n+static inline size_t st_sub(size_t a, size_t b)\n+{\n+\tif (a < b)\n+\t\tdie(\"size_t underflow: %\"PRIuMAX\" - %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a - b;\n+}\n+\n #ifdef HAVE_ALLOCA_H\n # include <alloca.h>\n # define xalloca(size)      (alloca(size))\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278640","messageId":"20160219112130.GC9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 03/21] tree-diff: catch integer overflow in combine_diff_path allocation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:21:30Z","receivedAt":"2016-02-19T11:21:30Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"A combine_diff_path struct has two \"flex\" members allocated\nalongside the struct: a string to hold the pathname, and an\narray of parent pointers. We use an \"int\" to compute this,\nmeaning we may easily overflow it if the pathname is\nextremely long.\n\nWe can fix this by using size_t, and checking for overflow\nwith the st_add helper.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.h      | 4 ++--\n tree-diff.c | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/diff.h b/diff.h\nindex 70b2d70..beafbbd 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -222,8 +222,8 @@ struct combine_diff_path {\n \t} parent[FLEX_ARRAY];\n };\n #define combine_diff_path_size(n, l) \\\n-\t(sizeof(struct combine_diff_path) + \\\n-\t sizeof(struct combine_diff_parent) * (n) + (l) + 1)\n+\tst_add4(sizeof(struct combine_diff_path), (l), 1, \\\n+\t\tst_mult(sizeof(struct combine_diff_parent), (n)))\n \n extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t      int dense, struct rev_info *);\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 290a1da..4dda9a1 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -124,8 +124,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \tunsigned mode, const unsigned char *sha1)\n {\n \tstruct combine_diff_path *p;\n-\tint len = base->len + pathlen;\n-\tint alloclen = combine_diff_path_size(nparent, len);\n+\tsize_t len = st_add(base->len, pathlen);\n+\tsize_t alloclen = combine_diff_path_size(nparent, len);\n \n \t/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */\n \tp = last->next;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278641","messageId":"20160219112200.GD9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 04/21] harden REALLOC_ARRAY and xcalloc against size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:22:00Z","receivedAt":"2016-02-19T11:22:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"REALLOC_ARRAY inherently involves a multiplication which can\noverflow size_t, resulting in a much smaller buffer than we\nthink we've allocated. We can easily harden it by using\nst_mult() to check for overflow.  Likewise, we can add\nALLOC_ARRAY to do the same thing for xmalloc calls.\n\nxcalloc() should already be fine, because it takes the two\nfactors separately, assuming the system calloc actually\nchecks for overflow. However, before we even hit the system\ncalloc(), we do our memory_limit_check, which involves a\nmultiplication. Let's check for overflow ourselves so that\nthis limit cannot be bypassed.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 3 ++-\n wrapper.c         | 3 +++\n 2 files changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 0c65033..55c073d 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -779,7 +779,8 @@ extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);\n extern char *xgetcwd(void);\n extern FILE *fopen_for_writing(const char *path);\n \n-#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))\n+#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n \n static inline char *xstrdup_or_null(const char *str)\n {\ndiff --git a/wrapper.c b/wrapper.c\nindex 29a45d2..9afc1a0 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -152,6 +152,9 @@ void *xcalloc(size_t nmemb, size_t size)\n {\n \tvoid *ret;\n \n+\tif (unsigned_mult_overflows(nmemb, size))\n+\t\tdie(\"data too large to fit into virtual memory space\");\n+\n \tmemory_limit_check(size * nmemb, 0);\n \tret = calloc(nmemb, size);\n \tif (!ret && (!nmemb || !size))\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278642","messageId":"20160219112205.GE9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 05/21] add helpers for allocating flex-array structs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:22:05Z","receivedAt":"2016-02-19T11:22:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Allocating a struct with a flex array is pretty simple in\npractice: you over-allocate the struct, then copy some data\ninto the over-allocation. But it can be a slight pain to\nmake sure you're allocating and copying the right amounts.\n\nThis patch adds a few helpers to turn simple cases of\nflex-array struct allocation into a one-liner that properly\nchecks for overflow. See the embedded documentation for\ndetails.\n\nIdeally we could provide a more flexible version that could\nhandle multiple strings, like:\n\n  FLEX_ALLOC_FMT(ref, name, \"%s%s\", prefix, name);\n\nBut we have to implement this as a macro (because of the\noffset calculation of the flex member), which means we would\nneed all compilers to support variadic macros.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 62 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 55c073d..e71e615 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -782,6 +782,68 @@ extern FILE *fopen_for_writing(const char *path);\n #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n \n+/*\n+ * These functions help you allocate structs with flex arrays, and copy\n+ * the data directly into the array. For example, if you had:\n+ *\n+ *   struct foo {\n+ *     int bar;\n+ *     char name[FLEX_ARRAY];\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_MEM(f, name, src, len);\n+ *\n+ * to allocate a \"foo\" with the contents of \"src\" in the \"name\" field.\n+ * The resulting struct is automatically zero'd, and the flex-array field\n+ * is NUL-terminated (whether the incoming src buffer was or not).\n+ *\n+ * The FLEXPTR_* variants operate on structs that don't use flex-arrays,\n+ * but do want to store a pointer to some extra data in the same allocated\n+ * block. For example, if you have:\n+ *\n+ *   struct foo {\n+ *     char *name;\n+ *     int bar;\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_STR(f, name, src);\n+ *\n+ * and \"name\" will point to a block of memory after the struct, which will be\n+ * freed along with the struct (but the pointer can be repointed anywhere).\n+ *\n+ * The *_STR variants accept a string parameter rather than a ptr/len\n+ * combination.\n+ *\n+ * Note that these macros will evaluate the first parameter multiple\n+ * times, and it must be assignable as an lvalue.\n+ */\n+#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \\\n+\t(x) = NULL; /* silence -Wuninitialized for offset calculation */ \\\n+\t(x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \\\n+} while (0)\n+#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \\\n+\t(x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \\\n+\t(x)->ptrname = (void *)((x)+1); \\\n+} while(0)\n+#define FLEX_ALLOC_STR(x, flexname, str) \\\n+\tFLEX_ALLOC_MEM((x), flexname, (str), strlen(str))\n+#define FLEXPTR_ALLOC_STR(x, ptrname, str) \\\n+\tFLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))\n+\n+static inline void *xalloc_flex(size_t base_len, size_t offset,\n+\t\t\t\tconst void *src, size_t src_len)\n+{\n+\tunsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));\n+\tmemcpy(ret + offset, src, src_len);\n+\treturn ret;\n+}\n+\n static inline char *xstrdup_or_null(const char *str)\n {\n \treturn str ? xstrdup(str) : NULL;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278643","messageId":"20160219112324.GF9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 06/21] convert manual allocations to argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:23:24Z","receivedAt":"2016-02-19T11:23:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There are many manual argv allocations that predate the\nargv_array API. Switching to that API brings a few\nadvantages:\n\n  1. We no longer have to manually compute the correct final\n     array size (so it's one less thing we can screw up).\n\n  2. In many cases we had to make a separate pass to count,\n     then allocate, then fill in the array. Now we can do it\n     in one pass, making the code shorter and easier to\n     follow.\n\n  3. argv_array handles memory ownership for us, making it\n     more obvious when things should be free()d and and when\n     not.\n\nMost of these cases are pretty straightforward. In some, we\nswitch from \"run_command_v\" to \"run_command\" which lets us\ndirectly use the argv_array embedded in \"struct\nchild_process\".\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/grep.c         | 10 +++++-----\n builtin/receive-pack.c | 12 +++---------\n builtin/remote-ext.c   | 26 +++++---------------------\n daemon.c               | 12 +++++-------\n git.c                  | 14 +++++---------\n line-log.c             | 26 ++++++++++----------------\n remote-curl.c          | 23 +++++++++++------------\n 7 files changed, 44 insertions(+), 79 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 8c516a9..aa7435f 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -365,17 +365,17 @@ static void append_path(struct grep_opt *opt, const void *data, size_t len)\n static void run_pager(struct grep_opt *opt, const char *prefix)\n {\n \tstruct string_list *path_list = opt->output_priv;\n-\tconst char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));\n+\tstruct child_process child = CHILD_PROCESS_INIT;\n \tint i, status;\n \n \tfor (i = 0; i < path_list->nr; i++)\n-\t\targv[i] = path_list->items[i].string;\n-\targv[path_list->nr] = NULL;\n+\t\targv_array_push(&child.args, path_list->items[i].string);\n+\tchild.dir = prefix;\n+\tchild.use_shell = 1;\n \n-\tstatus = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, prefix, NULL);\n+\tstatus = run_command(&child);\n \tif (status)\n \t\texit(status);\n-\tfree(argv);\n }\n \n static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex f2d6761..932afab 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1031,7 +1031,6 @@ static void run_update_post_hook(struct command *commands)\n {\n \tstruct command *cmd;\n \tint argc;\n-\tconst char **argv;\n \tstruct child_process proc = CHILD_PROCESS_INIT;\n \tconst char *hook;\n \n@@ -1044,21 +1043,16 @@ static void run_update_post_hook(struct command *commands)\n \tif (!argc || !hook)\n \t\treturn;\n \n-\targv = xmalloc(sizeof(*argv) * (2 + argc));\n-\targv[0] = hook;\n-\n-\tfor (argc = 1, cmd = commands; cmd; cmd = cmd->next) {\n+\targv_array_push(&proc.args, hook);\n+\tfor (cmd = commands; cmd; cmd = cmd->next) {\n \t\tif (cmd->error_string || cmd->did_not_exist)\n \t\t\tcontinue;\n-\t\targv[argc] = xstrdup(cmd->ref_name);\n-\t\targc++;\n+\t\targv_array_push(&proc.args, cmd->ref_name);\n \t}\n-\targv[argc] = NULL;\n \n \tproc.no_stdin = 1;\n \tproc.stdout_to_stderr = 1;\n \tproc.err = use_sideband ? -1 : 0;\n-\tproc.argv = argv;\n \n \tif (!start_command(&proc)) {\n \t\tif (use_sideband)\ndiff --git a/builtin/remote-ext.c b/builtin/remote-ext.c\nindex e3cd25d..7457c74 100644\n--- a/builtin/remote-ext.c\n+++ b/builtin/remote-ext.c\n@@ -114,30 +114,14 @@ static char *strip_escapes(const char *str, const char *service,\n \t}\n }\n \n-/* Should be enough... */\n-#define MAXARGUMENTS 256\n-\n-static const char **parse_argv(const char *arg, const char *service)\n+static void parse_argv(struct argv_array *out, const char *arg, const char *service)\n {\n-\tint arguments = 0;\n-\tint i;\n-\tconst char **ret;\n-\tchar *temparray[MAXARGUMENTS + 1];\n-\n \twhile (*arg) {\n-\t\tchar *expanded;\n-\t\tif (arguments == MAXARGUMENTS)\n-\t\t\tdie(\"remote-ext command has too many arguments\");\n-\t\texpanded = strip_escapes(arg, service, &arg);\n+\t\tchar *expanded = strip_escapes(arg, service, &arg);\n \t\tif (expanded)\n-\t\t\ttemparray[arguments++] = expanded;\n+\t\t\targv_array_push(out, expanded);\n+\t\tfree(expanded);\n \t}\n-\n-\tret = xmalloc((arguments + 1) * sizeof(char *));\n-\tfor (i = 0; i < arguments; i++)\n-\t\tret[i] = temparray[i];\n-\tret[arguments] = NULL;\n-\treturn ret;\n }\n \n static void send_git_request(int stdin_fd, const char *serv, const char *repo,\n@@ -158,7 +142,7 @@ static int run_child(const char *arg, const char *service)\n \tchild.in = -1;\n \tchild.out = -1;\n \tchild.err = 0;\n-\tchild.argv = parse_argv(arg, service);\n+\tparse_argv(&child.args, arg, service);\n \n \tif (start_command(&child) < 0)\n \t\tdie(\"Can't run specified command\");\ndiff --git a/daemon.c b/daemon.c\nindex 46b411c..3f57adb 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -808,7 +808,7 @@ static void check_dead_children(void)\n \t\t\tcradle = &blanket->next;\n }\n \n-static char **cld_argv;\n+struct argv_array cld_argv = ARGV_ARRAY_INIT;\n static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)\n {\n \tstruct child_process cld = CHILD_PROCESS_INIT;\n@@ -842,7 +842,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)\n #endif\n \t}\n \n-\tcld.argv = (const char **)cld_argv;\n+\tcld.argv = cld_argv.argv;\n \tcld.in = incoming;\n \tcld.out = dup(incoming);\n \n@@ -1374,12 +1374,10 @@ int main(int argc, char **argv)\n \t\twrite_file(pid_file, \"%\"PRIuMAX, (uintmax_t) getpid());\n \n \t/* prepare argv for serving-processes */\n-\tcld_argv = xmalloc(sizeof (char *) * (argc + 2));\n-\tcld_argv[0] = argv[0];\t/* git-daemon */\n-\tcld_argv[1] = \"--serve\";\n+\targv_array_push(&cld_argv, argv[0]); /* git-daemon */\n+\targv_array_push(&cld_argv, \"--serve\");\n \tfor (i = 1; i < argc; ++i)\n-\t\tcld_argv[i+1] = argv[i];\n-\tcld_argv[argc+1] = NULL;\n+\t\targv_array_push(&cld_argv, argv[i]);\n \n \treturn serve(&listen_addr, listen_port, cred);\n }\ndiff --git a/git.c b/git.c\nindex 6c64c94..087ad31 100644\n--- a/git.c\n+++ b/git.c\n@@ -247,20 +247,16 @@ static int handle_alias(int *argcp, const char ***argv)\n \talias_string = alias_lookup(alias_command);\n \tif (alias_string) {\n \t\tif (alias_string[0] == '!') {\n-\t\t\tconst char **alias_argv;\n-\t\t\tint argc = *argcp, i;\n+\t\t\tstruct child_process child = CHILD_PROCESS_INIT;\n \n \t\t\tcommit_pager_choice();\n \t\t\trestore_env(1);\n \n-\t\t\t/* build alias_argv */\n-\t\t\talias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));\n-\t\t\talias_argv[0] = alias_string + 1;\n-\t\t\tfor (i = 1; i < argc; ++i)\n-\t\t\t\talias_argv[i] = (*argv)[i];\n-\t\t\talias_argv[argc] = NULL;\n+\t\t\tchild.use_shell = 1;\n+\t\t\targv_array_push(&child.args, alias_string + 1);\n+\t\t\targv_array_pushv(&child.args, (*argv) + 1);\n \n-\t\t\tret = run_command_v_opt(alias_argv, RUN_USING_SHELL);\n+\t\t\tret = run_command(&child);\n \t\t\tif (ret >= 0)   /* normal exit */\n \t\t\t\texit(ret);\n \ndiff --git a/line-log.c b/line-log.c\nindex af6e2f7..5942a6f 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -14,6 +14,7 @@\n #include \"graph.h\"\n #include \"userdiff.h\"\n #include \"line-log.h\"\n+#include \"argv-array.h\"\n \n static void range_set_grow(struct range_set *rs, size_t extra)\n {\n@@ -746,23 +747,16 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n \tadd_line_range(rev, commit, range);\n \n \tif (!rev->diffopt.detect_rename) {\n-\t\tint i, count = 0;\n-\t\tstruct line_log_data *r = range;\n-\t\tconst char **paths;\n-\t\twhile (r) {\n-\t\t\tcount++;\n-\t\t\tr = r->next;\n-\t\t}\n-\t\tpaths = xmalloc((count+1)*sizeof(char *));\n-\t\tr = range;\n-\t\tfor (i = 0; i < count; i++) {\n-\t\t\tpaths[i] = xstrdup(r->path);\n-\t\t\tr = r->next;\n-\t\t}\n-\t\tpaths[count] = NULL;\n+\t\tstruct line_log_data *r;\n+\t\tstruct argv_array paths = ARGV_ARRAY_INIT;\n+\n+\t\tfor (r = range; r; r = r->next)\n+\t\t\targv_array_push(&paths, r->path);\n \t\tparse_pathspec(&rev->diffopt.pathspec, 0,\n-\t\t\t       PATHSPEC_PREFER_FULL, \"\", paths);\n-\t\tfree(paths);\n+\t\t\t       PATHSPEC_PREFER_FULL, \"\", paths.argv);\n+\t\t/* argv strings are now owned by pathspec */\n+\t\tpaths.argc = 0;\n+\t\targv_array_clear(&paths);\n \t}\n }\n \ndiff --git a/remote-curl.c b/remote-curl.c\nindex c704857..42deeec 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -845,23 +845,22 @@ static void parse_fetch(struct strbuf *buf)\n \n static int push_dav(int nr_spec, char **specs)\n {\n-\tconst char **argv = xmalloc((10 + nr_spec) * sizeof(char*));\n-\tint argc = 0, i;\n+\tstruct child_process child = CHILD_PROCESS_INIT;\n+\tsize_t i;\n \n-\targv[argc++] = \"http-push\";\n-\targv[argc++] = \"--helper-status\";\n+\tchild.git_cmd = 1;\n+\targv_array_push(&child.args, \"http-push\");\n+\targv_array_push(&child.args, \"--helper-status\");\n \tif (options.dry_run)\n-\t\targv[argc++] = \"--dry-run\";\n+\t\targv_array_push(&child.args, \"--dry-run\");\n \tif (options.verbosity > 1)\n-\t\targv[argc++] = \"--verbose\";\n-\targv[argc++] = url.buf;\n+\t\targv_array_push(&child.args, \"--verbose\");\n+\targv_array_push(&child.args, url.buf);\n \tfor (i = 0; i < nr_spec; i++)\n-\t\targv[argc++] = specs[i];\n-\targv[argc++] = NULL;\n+\t\targv_array_push(&child.args, specs[i]);\n \n-\tif (run_command_v_opt(argv, RUN_GIT_CMD))\n-\t\tdie(\"git-%s failed\", argv[0]);\n-\tfree(argv);\n+\tif (run_command(&child))\n+\t\tdie(\"git-http-push failed\");\n \treturn 0;\n }\n \n-- \n2.7.1.577.gfed91b8\n"},{"id":"278645","messageId":"20160219112332.GG9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 07/21] convert trivial cases to ALLOC_ARRAY","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:23:32Z","receivedAt":"2016-02-19T11:23:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Each of these cases can be converted to use ALLOC_ARRAY or\nREALLOC_ARRAY, which has two advantages:\n\n  1. It automatically checks the array-size multiplication\n     for overflow.\n\n  2. It always uses sizeof(*array) for the element-size,\n     so that it can never go out of sync with the declared\n     type of the array.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n alias.c                  |  2 +-\n attr.c                   |  2 +-\n bisect.c                 |  4 ++--\n builtin/blame.c          |  3 ++-\n builtin/clean.c          |  2 +-\n builtin/fast-export.c    |  2 +-\n builtin/index-pack.c     |  4 ++--\n builtin/merge-base.c     |  2 +-\n builtin/mv.c             |  3 ++-\n builtin/pack-objects.c   |  7 ++++---\n builtin/pack-redundant.c |  2 +-\n builtin/receive-pack.c   |  5 ++---\n column.c                 |  2 +-\n combine-diff.c           |  4 ++--\n commit.c                 |  2 +-\n compat/mingw.c           |  6 +++---\n diffcore-order.c         |  4 ++--\n dir.c                    |  6 +++---\n fast-import.c            |  5 +++--\n fsck.c                   |  3 ++-\n graph.c                  | 10 ++++------\n khash.h                  |  2 +-\n levenshtein.c            |  8 +++++---\n line-log.c               |  8 ++++----\n notes.c                  |  2 +-\n pack-check.c             |  2 +-\n pack-revindex.c          | 12 ++++++++----\n pathspec.c               |  5 +++--\n remote-curl.c            |  3 ++-\n sha1_file.c              |  4 ++--\n shallow.c                |  6 +++---\n show-index.c             |  3 ++-\n transport.c              |  2 +-\n xdiff-interface.c        |  2 +-\n 34 files changed, 75 insertions(+), 64 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex a11229d..3b90397 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -23,7 +23,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \tint src, dst, count = 0, size = 16;\n \tchar quoted = 0;\n \n-\t*argv = xmalloc(sizeof(**argv) * size);\n+\tALLOC_ARRAY(*argv, size);\n \n \t/* split alias_string */\n \t(*argv)[count++] = cmdline;\ndiff --git a/attr.c b/attr.c\nindex 086c08d..c83ec49 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -799,7 +799,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)\n \t\t\t++count;\n \t}\n \t*num = count;\n-\t*check = xmalloc(sizeof(**check) * count);\n+\tALLOC_ARRAY(*check, count);\n \tj = 0;\n \tfor (i = 0; i < attr_nr; i++) {\n \t\tconst char *value = check_all_attr[i].value;\ndiff --git a/bisect.c b/bisect.c\nindex 06ec54e..7996c29 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -708,10 +708,10 @@ static struct commit *get_commit_reference(const unsigned char *sha1)\n \n static struct commit **get_bad_and_good_commits(int *rev_nr)\n {\n-\tint len = 1 + good_revs.nr;\n-\tstruct commit **rev = xmalloc(len * sizeof(*rev));\n+\tstruct commit **rev;\n \tint i, n = 0;\n \n+\tALLOC_ARRAY(rev, 1 + good_revs.nr);\n \trev[n++] = get_commit_reference(current_bad_oid->hash);\n \tfor (i = 0; i < good_revs.nr; i++)\n \t\trev[n++] = get_commit_reference(good_revs.sha1[i]);\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 55bf5fa..b4ed462 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2059,7 +2059,8 @@ static int prepare_lines(struct scoreboard *sb)\n \tfor (p = buf; p < end; p = get_next_line(p, end))\n \t\tnum++;\n \n-\tsb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1));\n+\tALLOC_ARRAY(sb->lineno, num + 1);\n+\tlineno = sb->lineno;\n \n \tfor (p = buf; p < end; p = get_next_line(p, end))\n \t\t*lineno++ = p - buf;\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 7b08237..8229f7e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -543,7 +543,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \tint eof = 0;\n \tint i;\n \n-\tchosen = xmalloc(sizeof(int) * stuff->nr);\n+\tALLOC_ARRAY(chosen, stuff->nr);\n \t/* set chosen as uninitialized */\n \tfor (i = 0; i < stuff->nr; i++)\n \t\tchosen[i] = -1;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 2471297..8164b58 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -1021,7 +1021,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)\n \t\tconst char **refspecs_str;\n \t\tint i;\n \n-\t\trefspecs_str = xmalloc(sizeof(*refspecs_str) * refspecs_list.nr);\n+\t\tALLOC_ARRAY(refspecs_str, refspecs_list.nr);\n \t\tfor (i = 0; i < refspecs_list.nr; i++)\n \t\t\trefspecs_str[i] = refspecs_list.items[i].string;\n \ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 6a01509..a60bcfa 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1346,7 +1346,7 @@ static void fix_unresolved_deltas(struct sha1file *f)\n \t * before deltas depending on them, a good heuristic is to start\n \t * resolving deltas in the same order as their position in the pack.\n \t */\n-\tsorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos));\n+\tALLOC_ARRAY(sorted_by_pos, nr_ref_deltas);\n \tfor (i = 0; i < nr_ref_deltas; i++)\n \t\tsorted_by_pos[i] = &ref_deltas[i];\n \tqsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare);\n@@ -1759,7 +1759,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \tif (show_stat)\n \t\tshow_pack_info(stat_only);\n \n-\tidx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));\n+\tALLOC_ARRAY(idx_objects, nr_objects);\n \tfor (i = 0; i < nr_objects; i++)\n \t\tidx_objects[i] = &objects[i].idx;\n \tcurr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex a891162..c0d1822 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -252,7 +252,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)\n \tif (argc < 2)\n \t\tusage_with_options(merge_base_usage, options);\n \n-\trev = xmalloc(argc * sizeof(*rev));\n+\tALLOC_ARRAY(rev, argc);\n \twhile (argc-- > 0)\n \t\trev[rev_nr++] = get_commit_reference(*argv++);\n \treturn show_merge_base(rev, rev_nr, show_all);\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex d1d4316..9a9813a 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -24,7 +24,8 @@ static const char **internal_copy_pathspec(const char *prefix,\n \t\t\t\t\t   int count, unsigned flags)\n {\n \tint i;\n-\tconst char **result = xmalloc((count + 1) * sizeof(const char *));\n+\tconst char **result;\n+\tALLOC_ARRAY(result, count + 1);\n \tmemcpy(result, pathspec, count * sizeof(const char *));\n \tresult[count] = NULL;\n \tfor (i = 0; i < count; i++) {\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 4dae5b1..b4f1fa6 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -624,7 +624,7 @@ static struct object_entry **compute_write_order(void)\n {\n \tunsigned int i, wo_end, last_untagged;\n \n-\tstruct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));\n+\tstruct object_entry **wo;\n \tstruct object_entry *objects = to_pack.objects;\n \n \tfor (i = 0; i < to_pack.nr_objects; i++) {\n@@ -657,6 +657,7 @@ static struct object_entry **compute_write_order(void)\n \t * Give the objects in the original recency order until\n \t * we see a tagged tip.\n \t */\n+\tALLOC_ARRAY(wo, to_pack.nr_objects);\n \tfor (i = wo_end = 0; i < to_pack.nr_objects; i++) {\n \t\tif (objects[i].tagged)\n \t\t\tbreak;\n@@ -769,7 +770,7 @@ static void write_pack_file(void)\n \n \tif (progress > pack_to_stdout)\n \t\tprogress_state = start_progress(_(\"Writing objects\"), nr_result);\n-\twritten_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));\n+\tALLOC_ARRAY(written_list, to_pack.nr_objects);\n \twrite_order = compute_write_order();\n \n \tdo {\n@@ -2129,7 +2130,7 @@ static void prepare_pack(int window, int depth)\n \tif (!to_pack.nr_objects || !window || !depth)\n \t\treturn;\n \n-\tdelta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));\n+\tALLOC_ARRAY(delta_list, to_pack.nr_objects);\n \tnr_deltas = n = 0;\n \n \tfor (i = 0; i < to_pack.nr_objects; i++) {\ndiff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c\nindex d0532f6..72c8158 100644\n--- a/builtin/pack-redundant.c\n+++ b/builtin/pack-redundant.c\n@@ -53,7 +53,7 @@ static inline struct llist_item *llist_item_get(void)\n \t\tfree_nodes = free_nodes->next;\n \t} else {\n \t\tint i = 1;\n-\t\tnew = xmalloc(sizeof(struct llist_item) * BLKSIZE);\n+\t\tALLOC_ARRAY(new, BLKSIZE);\n \t\tfor (; i < BLKSIZE; i++)\n \t\t\tllist_item_put(&new[i]);\n \t}\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 932afab..3dc3868 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1591,8 +1591,7 @@ static void prepare_shallow_update(struct command *commands,\n {\n \tint i, j, k, bitmap_size = (si->ref->nr + 31) / 32;\n \n-\tsi->used_shallow = xmalloc(sizeof(*si->used_shallow) *\n-\t\t\t\t   si->shallow->nr);\n+\tALLOC_ARRAY(si->used_shallow, si->shallow->nr);\n \tassign_shallow_commits_to_refs(si, si->used_shallow, NULL);\n \n \tsi->need_reachability_test =\n@@ -1658,7 +1657,7 @@ static void update_shallow_info(struct command *commands,\n \t\treturn;\n \t}\n \n-\tref_status = xmalloc(sizeof(*ref_status) * ref->nr);\n+\tALLOC_ARRAY(ref_status, ref->nr);\n \tassign_shallow_commits_to_refs(si, NULL, ref_status);\n \tfor (cmd = commands; cmd; cmd = cmd->next) {\n \t\tif (is_null_sha1(cmd->new_sha1))\ndiff --git a/column.c b/column.c\nindex 786abe6..f9fda68 100644\n--- a/column.c\n+++ b/column.c\n@@ -164,7 +164,7 @@ static void display_table(const struct string_list *list,\n \tdata.colopts = colopts;\n \tdata.opts = *opts;\n \n-\tdata.len = xmalloc(sizeof(*data.len) * list->nr);\n+\tALLOC_ARRAY(data.len, list->nr);\n \tfor (i = 0; i < list->nr; i++)\n \t\tdata.len[i] = item_length(colopts, list->items[i].string);\n \ndiff --git a/combine-diff.c b/combine-diff.c\nindex 5571304..a698016 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1372,7 +1372,7 @@ static struct combine_diff_path *find_paths_multitree(\n \tstruct combine_diff_path paths_head;\n \tstruct strbuf base;\n \n-\tparents_sha1 = xmalloc(nparent * sizeof(parents_sha1[0]));\n+\tALLOC_ARRAY(parents_sha1, nparent);\n \tfor (i = 0; i < nparent; i++)\n \t\tparents_sha1[i] = parents->sha1[i];\n \n@@ -1483,7 +1483,7 @@ void diff_tree_combined(const unsigned char *sha1,\n \tif (opt->orderfile && num_paths) {\n \t\tstruct obj_order *o;\n \n-\t\to = xmalloc(sizeof(*o) * num_paths);\n+\t\tALLOC_ARRAY(o, num_paths);\n \t\tfor (i = 0, p = paths; p; p = p->next, i++)\n \t\t\to[i].obj = p;\n \t\torder_objects(opt->orderfile, path_path, o, num_paths);\ndiff --git a/commit.c b/commit.c\nindex 40388d7..31cd91f 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -903,7 +903,7 @@ static int remove_redundant(struct commit **array, int cnt)\n \n \twork = xcalloc(cnt, sizeof(*work));\n \tredundant = xcalloc(cnt, 1);\n-\tfilled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));\n+\tALLOC_ARRAY(filled_index, cnt - 1);\n \n \tfor (i = 0; i < cnt; i++)\n \t\tparse_commit(array[i]);\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex fbe69b8..7803f30 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -893,7 +893,7 @@ static char **get_path_split(void)\n \tif (!n)\n \t\treturn NULL;\n \n-\tpath = xmalloc((n+1)*sizeof(char *));\n+\tALLOC_ARRAY(path, n + 1);\n \tp = envpath;\n \ti = 0;\n \tdo {\n@@ -978,7 +978,7 @@ static wchar_t *make_environment_block(char **deltaenv)\n \t\ti++;\n \n \t/* copy the environment, leaving space for changes */\n-\ttmpenv = xmalloc((size + i) * sizeof(char*));\n+\tALLOC_ARRAY(tmpenv, size + i);\n \tmemcpy(tmpenv, environ, size * sizeof(char*));\n \n \t/* merge supplied environment changes into the temporary environment */\n@@ -1168,7 +1168,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)\n \t\tint argc = 0;\n \t\tconst char **argv2;\n \t\twhile (argv[argc]) argc++;\n-\t\targv2 = xmalloc(sizeof(*argv) * (argc+1));\n+\t\tALLOC_ARRAY(argv2, argc + 1);\n \t\targv2[0] = (char *)cmd;\t/* full path to the script file */\n \t\tmemcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);\n \t\tpid = mingw_spawnv(prog, argv2, 1);\ndiff --git a/diffcore-order.c b/diffcore-order.c\nindex 97dd3d0..69d41f7 100644\n--- a/diffcore-order.c\n+++ b/diffcore-order.c\n@@ -52,7 +52,7 @@ static void prepare_order(const char *orderfile)\n \t\t}\n \t\tif (pass == 0) {\n \t\t\torder_cnt = cnt;\n-\t\t\torder = xmalloc(sizeof(*order) * cnt);\n+\t\t\tALLOC_ARRAY(order, cnt);\n \t\t}\n \t}\n }\n@@ -120,7 +120,7 @@ void diffcore_order(const char *orderfile)\n \tif (!q->nr)\n \t\treturn;\n \n-\to = xmalloc(sizeof(*o) * q->nr);\n+\tALLOC_ARRAY(o, q->nr);\n \tfor (i = 0; i < q->nr; i++)\n \t\to[i].obj = q->queue[i];\n \torder_objects(orderfile, pair_pathtwo, o, q->nr);\ndiff --git a/dir.c b/dir.c\nindex f0b6d0a..66c93c1 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2484,14 +2484,14 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,\n \tud.untracked_alloc = value;\n \tud.untracked_nr\t   = value;\n \tif (ud.untracked_nr)\n-\t\tud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);\n+\t\tALLOC_ARRAY(ud.untracked, ud.untracked_nr);\n \tdata = next;\n \n \tnext = data;\n \tud.dirs_alloc = ud.dirs_nr = decode_varint(&next);\n \tif (next > end)\n \t\treturn -1;\n-\tud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);\n+\tALLOC_ARRAY(ud.dirs, ud.dirs_nr);\n \tdata = next;\n \n \tlen = strlen((const char *)data);\n@@ -2611,7 +2611,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long\n \trd.data\t      = next;\n \trd.end\t      = end;\n \trd.index      = 0;\n-\trd.ucd        = xmalloc(sizeof(*rd.ucd) * len);\n+\tALLOC_ARRAY(rd.ucd, len);\n \n \tif (read_one_dir(&uc->root, &rd) || rd.index != len)\n \t\tgoto done;\ndiff --git a/fast-import.c b/fast-import.c\nindex bf01b34..a6467cb 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -814,7 +814,8 @@ static struct tree_entry *new_tree_entry(void)\n \tif (!avail_tree_entry) {\n \t\tunsigned int n = tree_entry_alloc;\n \t\ttotal_allocd += n * sizeof(struct tree_entry);\n-\t\tavail_tree_entry = e = xmalloc(n * sizeof(struct tree_entry));\n+\t\tALLOC_ARRAY(e, n);\n+\t\tavail_tree_entry = e;\n \t\twhile (n-- > 1) {\n \t\t\t*((void**)e) = e + 1;\n \t\t\te++;\n@@ -898,7 +899,7 @@ static const char *create_index(void)\n \tstruct object_entry_pool *o;\n \n \t/* Build the table of object IDs. */\n-\tidx = xmalloc(object_count * sizeof(*idx));\n+\tALLOC_ARRAY(idx, object_count);\n \tc = idx;\n \tfor (o = blocks; o; o = o->next_pool)\n \t\tfor (e = o->next_free; e-- != o->entries;)\ndiff --git a/fsck.c b/fsck.c\nindex c637f66..ca4c685 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -199,7 +199,8 @@ void fsck_set_msg_type(struct fsck_options *options,\n \n \tif (!options->msg_type) {\n \t\tint i;\n-\t\tint *msg_type = xmalloc(sizeof(int) * FSCK_MSG_MAX);\n+\t\tint *msg_type;\n+\t\tALLOC_ARRAY(msg_type, FSCK_MSG_MAX);\n \t\tfor (i = 0; i < FSCK_MSG_MAX; i++)\n \t\t\tmsg_type[i] = fsck_msg_type(i, options);\n \t\toptions->msg_type = msg_type;\ndiff --git a/graph.c b/graph.c\nindex c25a09a..1350bdd 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -234,12 +234,10 @@ struct git_graph *graph_init(struct rev_info *opt)\n \t * We'll automatically grow columns later if we need more room.\n \t */\n \tgraph->column_capacity = 30;\n-\tgraph->columns = xmalloc(sizeof(struct column) *\n-\t\t\t\t graph->column_capacity);\n-\tgraph->new_columns = xmalloc(sizeof(struct column) *\n-\t\t\t\t     graph->column_capacity);\n-\tgraph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n-\tgraph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n+\tALLOC_ARRAY(graph->columns, graph->column_capacity);\n+\tALLOC_ARRAY(graph->new_columns, graph->column_capacity);\n+\tALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);\n+\tALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity);\n \n \t/*\n \t * The diff output prefix callback, with this we can make\ndiff --git a/khash.h b/khash.h\nindex 376475a..c0da40d 100644\n--- a/khash.h\n+++ b/khash.h\n@@ -117,7 +117,7 @@ static const double __ac_HASH_UPPER = 0.77;\n \t\t\tif (new_n_buckets < 4) new_n_buckets = 4;\t\t\t\t\t\\\n \t\t\tif (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0;\t/* requested size is too small */ \\\n \t\t\telse { /* hash table size to be changed (shrink or expand); rehash */ \\\n-\t\t\t\tnew_flags = (khint32_t*)xmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t));\t\\\n+\t\t\t\tALLOC_ARRAY(new_flags, __ac_fsize(new_n_buckets)); \\\n \t\t\t\tif (!new_flags) return -1;\t\t\t\t\t\t\t\t\\\n \t\t\t\tmemset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \\\n \t\t\t\tif (h->n_buckets < new_n_buckets) {\t/* expand */\t\t\\\ndiff --git a/levenshtein.c b/levenshtein.c\nindex fc28159..d263269 100644\n--- a/levenshtein.c\n+++ b/levenshtein.c\n@@ -42,11 +42,13 @@ int levenshtein(const char *string1, const char *string2,\n \t\tint w, int s, int a, int d)\n {\n \tint len1 = strlen(string1), len2 = strlen(string2);\n-\tint *row0 = xmalloc(sizeof(int) * (len2 + 1));\n-\tint *row1 = xmalloc(sizeof(int) * (len2 + 1));\n-\tint *row2 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row0, *row1, *row2;\n \tint i, j;\n \n+\tALLOC_ARRAY(row0, len2 + 1);\n+\tALLOC_ARRAY(row1, len2 + 1);\n+\tALLOC_ARRAY(row2, len2 + 1);\n+\n \tfor (j = 0; j <= len2; j++)\n \t\trow1[j] = j * a;\n \tfor (i = 0; i < len1; i++) {\ndiff --git a/line-log.c b/line-log.c\nindex 5942a6f..fa095b9 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -522,7 +522,7 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines,\n \tif (diff_populate_filespec(spec, 0))\n \t\tdie(\"Cannot read blob %s\", sha1_to_hex(spec->sha1));\n \n-\tends = xmalloc(size * sizeof(*ends));\n+\tALLOC_ARRAY(ends, size);\n \tends[cur++] = 0;\n \tdata = spec->data;\n \twhile (num < spec->size) {\n@@ -1140,9 +1140,9 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm\n \tif (nparents > 1 && rev->first_parent_only)\n \t\tnparents = 1;\n \n-\tdiffqueues = xmalloc(nparents * sizeof(*diffqueues));\n-\tcand = xmalloc(nparents * sizeof(*cand));\n-\tparents = xmalloc(nparents * sizeof(*parents));\n+\tALLOC_ARRAY(diffqueues, nparents);\n+\tALLOC_ARRAY(cand, nparents);\n+\tALLOC_ARRAY(parents, nparents);\n \n \tp = commit->parents;\n \tfor (i = 0; i < nparents; i++) {\ndiff --git a/notes.c b/notes.c\nindex c1e5035..88cf474 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1035,7 +1035,7 @@ struct notes_tree **load_notes_trees(struct string_list *refs, int flags)\n \tstruct string_list_item *item;\n \tint counter = 0;\n \tstruct notes_tree **trees;\n-\ttrees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));\n+\tALLOC_ARRAY(trees, refs->nr + 1);\n \tfor_each_string_list_item(item, refs) {\n \t\tstruct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));\n \t\tinit_notes(t, item->string, combine_notes_ignore, flags);\ndiff --git a/pack-check.c b/pack-check.c\nindex 433bd86..1da89a4 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -89,7 +89,7 @@ static int verify_packfile(struct packed_git *p,\n \t * we do not do scan-streaming check on the pack file.\n \t */\n \tnr_objects = p->num_objects;\n-\tentries = xmalloc((nr_objects + 1) * sizeof(*entries));\n+\tALLOC_ARRAY(entries, nr_objects + 1);\n \tentries[nr_objects].offset = pack_sig_ofs;\n \t/* first sort entries by pack offset, since unpacking them is more efficient that way */\n \tfor (i = 0; i < nr_objects; i++) {\ndiff --git a/pack-revindex.c b/pack-revindex.c\nindex 155a8a3..96d51c3 100644\n--- a/pack-revindex.c\n+++ b/pack-revindex.c\n@@ -44,10 +44,14 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max)\n \t * keep track of them with alias pointers, always sorting from \"from\"\n \t * to \"to\".\n \t */\n-\tstruct revindex_entry *tmp = xmalloc(n * sizeof(*tmp));\n-\tstruct revindex_entry *from = entries, *to = tmp;\n+\tstruct revindex_entry *tmp, *from, *to;\n \tint bits;\n-\tunsigned *pos = xmalloc(BUCKETS * sizeof(*pos));\n+\tunsigned *pos;\n+\n+\tALLOC_ARRAY(pos, BUCKETS);\n+\tALLOC_ARRAY(tmp, n);\n+\tfrom = entries;\n+\tto = tmp;\n \n \t/*\n \t * If (max >> bits) is zero, then we know that the radix digit we are\n@@ -121,7 +125,7 @@ static void create_pack_revindex(struct packed_git *p)\n \tunsigned i;\n \tconst char *index = p->index_data;\n \n-\tp->revindex = xmalloc(sizeof(*p->revindex) * (num_ent + 1));\n+\tALLOC_ARRAY(p->revindex, num_ent + 1);\n \tindex += 4 * 256;\n \n \tif (p->index_version > 1) {\ndiff --git a/pathspec.c b/pathspec.c\nindex 9304ee3..c9e9b6c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -406,7 +406,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tn++;\n \n \tpathspec->nr = n;\n-\tpathspec->items = item = xmalloc(sizeof(*item) * n);\n+\tALLOC_ARRAY(pathspec->items, n);\n+\titem = pathspec->items;\n \tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n@@ -483,7 +484,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\n-\tdst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);\n+\tALLOC_ARRAY(dst->items, dst->nr);\n \tmemcpy(dst->items, src->items,\n \t       sizeof(struct pathspec_item) * dst->nr);\n }\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 42deeec..5259b7e 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -696,9 +696,10 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)\n static int fetch_dumb(int nr_heads, struct ref **to_fetch)\n {\n \tstruct walker *walker;\n-\tchar **targets = xmalloc(nr_heads * sizeof(char*));\n+\tchar **targets;\n \tint ret, i;\n \n+\tALLOC_ARRAY(targets, nr_heads);\n \tif (options.depth)\n \t\tdie(\"dumb http transport does not support --depth\");\n \tfor (i = 0; i < nr_heads; i++)\ndiff --git a/sha1_file.c b/sha1_file.c\nindex aab1872..2f1c6d3 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1942,7 +1942,7 @@ static enum object_type packed_to_object_type(struct packed_git *p,\n \t\t/* Push the object we're going to leave behind */\n \t\tif (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {\n \t\t\tpoi_stack_alloc = alloc_nr(poi_stack_nr);\n-\t\t\tpoi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc);\n+\t\t\tALLOC_ARRAY(poi_stack, poi_stack_alloc);\n \t\t\tmemcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);\n \t\t} else {\n \t\t\tALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);\n@@ -2308,7 +2308,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,\n \t\tif (delta_stack_nr >= delta_stack_alloc\n \t\t    && delta_stack == small_delta_stack) {\n \t\t\tdelta_stack_alloc = alloc_nr(delta_stack_nr);\n-\t\t\tdelta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc);\n+\t\t\tALLOC_ARRAY(delta_stack, delta_stack_alloc);\n \t\t\tmemcpy(delta_stack, small_delta_stack,\n \t\t\t       sizeof(*delta_stack)*delta_stack_nr);\n \t\t} else {\ndiff --git a/shallow.c b/shallow.c\nindex 60f1505..71163bf 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -315,8 +315,8 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa)\n \tinfo->shallow = sa;\n \tif (!sa)\n \t\treturn;\n-\tinfo->ours = xmalloc(sizeof(*info->ours) * sa->nr);\n-\tinfo->theirs = xmalloc(sizeof(*info->theirs) * sa->nr);\n+\tALLOC_ARRAY(info->ours, sa->nr);\n+\tALLOC_ARRAY(info->theirs, sa->nr);\n \tfor (i = 0; i < sa->nr; i++) {\n \t\tif (has_sha1_file(sa->sha1[i])) {\n \t\t\tstruct commit_graft *graft;\n@@ -487,7 +487,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,\n \tstruct paint_info pi;\n \n \ttrace_printf_key(&trace_shallow, \"shallow: assign_shallow_commits_to_refs\\n\");\n-\tshallow = xmalloc(sizeof(*shallow) * (info->nr_ours + info->nr_theirs));\n+\tALLOC_ARRAY(shallow, info->nr_ours + info->nr_theirs);\n \tfor (i = 0; i < info->nr_ours; i++)\n \t\tshallow[nr_shallow++] = info->ours[i];\n \tfor (i = 0; i < info->nr_theirs; i++)\ndiff --git a/show-index.c b/show-index.c\nindex d9e4903..acf8d54 100644\n--- a/show-index.c\n+++ b/show-index.c\n@@ -50,7 +50,8 @@ int main(int argc, char **argv)\n \t\t\tunsigned char sha1[20];\n \t\t\tuint32_t crc;\n \t\t\tuint32_t off;\n-\t\t} *entries = xmalloc(nr * sizeof(entries[0]));\n+\t\t} *entries;\n+\t\tALLOC_ARRAY(entries, nr);\n \t\tfor (i = 0; i < nr; i++)\n \t\t\tif (fread(entries[i].sha1, 20, 1, stdin) != 1)\n \t\t\t\tdie(\"unable to read sha1 %u/%u\", i, nr);\ndiff --git a/transport.c b/transport.c\nindex c92f8ae..3b4e644 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -977,7 +977,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)\n \t\t * This condition shouldn't be met in a non-deepening fetch\n \t\t * (see builtin/fetch.c:quickfetch()).\n \t\t */\n-\t\theads = xmalloc(nr_refs * sizeof(*heads));\n+\t\tALLOC_ARRAY(heads, nr_refs);\n \t\tfor (rm = refs; rm; rm = rm->next)\n \t\t\theads[nr_heads++] = rm;\n \t}\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex cb67c1c..54236f2 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -265,7 +265,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)\n \tfor (i = 0, regs->nr = 1; value[i]; i++)\n \t\tif (value[i] == '\\n')\n \t\t\tregs->nr++;\n-\tregs->array = xmalloc(regs->nr * sizeof(struct ff_reg));\n+\tALLOC_ARRAY(regs->array, regs->nr);\n \tfor (i = 0; i < regs->nr; i++) {\n \t\tstruct ff_reg *reg = regs->array + i;\n \t\tconst char *ep = strchr(value, '\\n'), *expression;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278644","messageId":"20160219112337.GH9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 08/21] use xmallocz to avoid size arithmetic","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:23:37Z","receivedAt":"2016-02-19T11:23:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We frequently allocate strings as xmalloc(len + 1), where\nthe extra 1 is for the NUL terminator. This can be done more\nsimply with xmallocz, which also checks for integer\noverflow.\n\nThere's no case where switching xmalloc(n+1) to xmallocz(n)\nis wrong; the result is the same length, and malloc made no\nguarantees about what was in the buffer anyway. But in some\ncases, we can stop manually placing NUL at the end of the\nallocated buffer. But that's only safe if it's clear that\nthe contents will always fill the buffer.\n\nIn each case where this patch does so, I manually examined\nthe control flow, and I tried to err on the side of caution.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/check-ref-format.c | 2 +-\n builtin/merge-tree.c       | 2 +-\n builtin/worktree.c         | 2 +-\n column.c                   | 3 +--\n combine-diff.c             | 4 +---\n config.c                   | 4 +---\n dir.c                      | 2 +-\n entry.c                    | 2 +-\n grep.c                     | 3 +--\n imap-send.c                | 5 ++---\n ll-merge.c                 | 2 +-\n progress.c                 | 2 +-\n refs.c                     | 2 +-\n setup.c                    | 5 ++---\n strbuf.c                   | 2 +-\n 15 files changed, 17 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c\nindex fd915d5..eac4994 100644\n--- a/builtin/check-ref-format.c\n+++ b/builtin/check-ref-format.c\n@@ -20,7 +20,7 @@ static const char builtin_check_ref_format_usage[] =\n  */\n static char *collapse_slashes(const char *refname)\n {\n-\tchar *ret = xmalloc(strlen(refname) + 1);\n+\tchar *ret = xmallocz(strlen(refname));\n \tchar ch;\n \tchar prev = '/';\n \tchar *cp = ret;\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex d4f0cbd..ca57004 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -174,7 +174,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi\n \n static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)\n {\n-\tchar *path = xmalloc(traverse_path_len(info, n) + 1);\n+\tchar *path = xmallocz(traverse_path_len(info, n));\n \treturn make_traverse_path(path, info, n);\n }\n \ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 475b958..0a45710 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -52,7 +52,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n \t\treturn 1;\n \t}\n \tlen = st.st_size;\n-\tpath = xmalloc(len + 1);\n+\tpath = xmallocz(len);\n \tread_in_full(fd, path, len);\n \tclose(fd);\n \twhile (len && (path[len - 1] == '\\n' || path[len - 1] == '\\r'))\ndiff --git a/column.c b/column.c\nindex f9fda68..d55ead1 100644\n--- a/column.c\n+++ b/column.c\n@@ -173,9 +173,8 @@ static void display_table(const struct string_list *list,\n \tif (colopts & COL_DENSE)\n \t\tshrink_columns(&data);\n \n-\tempty_cell = xmalloc(initial_width + 1);\n+\tempty_cell = xmallocz(initial_width);\n \tmemset(empty_cell, ' ', initial_width);\n-\tempty_cell[initial_width] = '\\0';\n \tfor (y = 0; y < data.rows; y++) {\n \t\tfor (x = 0; x < data.cols; x++)\n \t\t\tif (display_cell(&data, initial_width, empty_cell, x, y))\ndiff --git a/combine-diff.c b/combine-diff.c\nindex a698016..890c415 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1043,7 +1043,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t\telem->mode = canon_mode(S_IFLNK);\n \n \t\t\tresult_size = len;\n-\t\t\tresult = xmalloc(len + 1);\n+\t\t\tresult = xmallocz(len);\n \n \t\t\tdone = read_in_full(fd, result, len);\n \t\t\tif (done < 0)\n@@ -1051,8 +1051,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\telse if (done < len)\n \t\t\t\tdie(\"early EOF '%s'\", elem->path);\n \n-\t\t\tresult[len] = 0;\n-\n \t\t\t/* If not a fake symlink, apply filters, e.g. autocrlf */\n \t\t\tif (is_file) {\n \t\t\t\tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/config.c b/config.c\nindex b95ac3a..e7b589a 100644\n--- a/config.c\n+++ b/config.c\n@@ -1902,7 +1902,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \t * Validate the key and while at it, lower case it for matching.\n \t */\n \tif (store_key)\n-\t\t*store_key = xmalloc(strlen(key) + 1);\n+\t\t*store_key = xmallocz(strlen(key));\n \n \tdot = 0;\n \tfor (i = 0; key[i]; i++) {\n@@ -1926,8 +1926,6 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \t\tif (store_key)\n \t\t\t(*store_key)[i] = c;\n \t}\n-\tif (store_key)\n-\t\t(*store_key)[i] = 0;\n \n \treturn 0;\n \ndiff --git a/dir.c b/dir.c\nindex 66c93c1..6c627d5 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -711,7 +711,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\tclose(fd);\n \t\t\treturn 0;\n \t\t}\n-\t\tbuf = xmalloc(size+1);\n+\t\tbuf = xmallocz(size);\n \t\tif (read_in_full(fd, buf, size) != size) {\n \t\t\tfree(buf);\n \t\t\tclose(fd);\ndiff --git a/entry.c b/entry.c\nindex 582c400..a410957 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -6,7 +6,7 @@\n static void create_directories(const char *path, int path_len,\n \t\t\t       const struct checkout *state)\n {\n-\tchar *buf = xmalloc(path_len + 1);\n+\tchar *buf = xmallocz(path_len);\n \tint len = 0;\n \n \twhile (len < path_len) {\ndiff --git a/grep.c b/grep.c\nindex 7b2b96a..528b652 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1741,7 +1741,7 @@ static int grep_source_load_file(struct grep_source *gs)\n \ti = open(filename, O_RDONLY);\n \tif (i < 0)\n \t\tgoto err_ret;\n-\tdata = xmalloc(size + 1);\n+\tdata = xmallocz(size);\n \tif (st.st_size != read_in_full(i, data, size)) {\n \t\terror(_(\"'%s': short read %s\"), filename, strerror(errno));\n \t\tclose(i);\n@@ -1749,7 +1749,6 @@ static int grep_source_load_file(struct grep_source *gs)\n \t\treturn -1;\n \t}\n \tclose(i);\n-\tdata[size] = 0;\n \n \tgs->buf = data;\n \tgs->size = size;\ndiff --git a/imap-send.c b/imap-send.c\nindex 4d3b773..2c52027 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -892,12 +892,11 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)\n \tresponse = xstrfmt(\"%s %s\", user, hex);\n \tresp_len = strlen(response) + 1;\n \n-\tresponse_64 = xmalloc(ENCODED_SIZE(resp_len) + 1);\n+\tresponse_64 = xmallocz(ENCODED_SIZE(resp_len));\n \tencoded_len = EVP_EncodeBlock((unsigned char *)response_64,\n \t\t\t\t      (unsigned char *)response, resp_len);\n \tif (encoded_len < 0)\n \t\tdie(\"EVP_EncodeBlock error\");\n-\tresponse_64[encoded_len] = '\\0';\n \treturn (char *)response_64;\n }\n \n@@ -1188,7 +1187,7 @@ static void lf_to_crlf(struct strbuf *msg)\n \t\tj++;\n \t}\n \n-\tnew = xmalloc(j + 1);\n+\tnew = xmallocz(j);\n \n \t/*\n \t * Second pass: write the new string.  Note that this loop is\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 0338630..ff4a43a 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -205,7 +205,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tif (fstat(fd, &st))\n \t\tgoto close_bad;\n \tresult->size = st.st_size;\n-\tresult->ptr = xmalloc(result->size + 1);\n+\tresult->ptr = xmallocz(result->size);\n \tif (read_in_full(fd, result->ptr, result->size) != result->size) {\n \t\tfree(result->ptr);\n \t\tresult->ptr = NULL;\ndiff --git a/progress.c b/progress.c\nindex 353bd37..76a88c5 100644\n--- a/progress.c\n+++ b/progress.c\n@@ -247,7 +247,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)\n \t\tsize_t len = strlen(msg) + 5;\n \t\tstruct throughput *tp = progress->throughput;\n \n-\t\tbufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);\n+\t\tbufp = (len < sizeof(buf)) ? buf : xmallocz(len);\n \t\tif (tp) {\n \t\t\tunsigned int rate = !tp->avg_misecs ? 0 :\n \t\t\t\t\ttp->avg_bytes / tp->avg_misecs;\ndiff --git a/refs.c b/refs.c\nindex e2d34b2..1d9e2a7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -124,7 +124,7 @@ int refname_is_safe(const char *refname)\n \t\tchar *buf;\n \t\tint result;\n \n-\t\tbuf = xmalloc(strlen(refname) + 1);\n+\t\tbuf = xmallocz(strlen(refname));\n \t\t/*\n \t\t * Does the refname try to escape refs/?\n \t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\ndiff --git a/setup.c b/setup.c\nindex 0deb022..ab21086 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -88,7 +88,7 @@ char *prefix_path_gently(const char *prefix, int len,\n \tconst char *orig = path;\n \tchar *sanitized;\n \tif (is_absolute_path(orig)) {\n-\t\tsanitized = xmalloc(strlen(path) + 1);\n+\t\tsanitized = xmallocz(strlen(path));\n \t\tif (remaining_prefix)\n \t\t\t*remaining_prefix = 0;\n \t\tif (normalize_path_copy_len(sanitized, path, remaining_prefix)) {\n@@ -488,14 +488,13 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)\n \t\terror_code = READ_GITFILE_ERR_OPEN_FAILED;\n \t\tgoto cleanup_return;\n \t}\n-\tbuf = xmalloc(st.st_size + 1);\n+\tbuf = xmallocz(st.st_size);\n \tlen = read_in_full(fd, buf, st.st_size);\n \tclose(fd);\n \tif (len != st.st_size) {\n \t\terror_code = READ_GITFILE_ERR_READ_FAILED;\n \t\tgoto cleanup_return;\n \t}\n-\tbuf[len] = '\\0';\n \tif (!starts_with(buf, \"gitdir: \")) {\n \t\terror_code = READ_GITFILE_ERR_INVALID_FORMAT;\n \t\tgoto cleanup_return;\ndiff --git a/strbuf.c b/strbuf.c\nindex bab316d..f60e2ee 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -718,7 +718,7 @@ char *xstrdup_tolower(const char *string)\n \tsize_t len, i;\n \n \tlen = strlen(string);\n-\tresult = xmalloc(len + 1);\n+\tresult = xmallocz(len);\n \tfor (i = 0; i < len; i++)\n \t\tresult[i] = tolower(string[i]);\n \tresult[i] = '\\0';\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278647","messageId":"20160219112342.GI9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 09/21] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:23:42Z","receivedAt":"2016-02-19T11:23:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Using FLEX_ARRAY macros reduces the amount of manual\ncomputation size we have to do. It also ensures we don't\noverflow size_t, and it makes sure we write the same number\nof bytes that we allocated.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n attr.c               |  4 +---\n builtin/blame.c      |  4 +---\n builtin/help.c       |  9 +++------\n builtin/mktree.c     |  9 +++++----\n builtin/reflog.c     |  7 ++-----\n cache-tree.c         |  4 +---\n combine-diff.c       |  4 +---\n diff.c               |  7 ++-----\n dir.c                | 16 +++-------------\n hashmap.c            |  3 +--\n help.c               |  6 ++----\n log-tree.c           |  5 ++---\n name-hash.c          |  3 +--\n ref-filter.c         |  6 ++----\n refs.c               |  6 ++----\n refs/files-backend.c | 19 +++++--------------\n remote.c             |  5 +----\n 17 files changed, 35 insertions(+), 82 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex c83ec49..6537a43 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -93,9 +93,7 @@ static struct git_attr *git_attr_internal(const char *name, int len)\n \tif (invalid_attr_name(name, len))\n \t\treturn NULL;\n \n-\ta = xmalloc(sizeof(*a) + len + 1);\n-\tmemcpy(a->name, name, len);\n-\ta->name[len] = 0;\n+\tFLEX_ALLOC_MEM(a, name, name, len);\n \ta->h = hval;\n \ta->next = git_attr_hash[pos];\n \ta->attr_nr = attr_nr++;\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex b4ed462..e982fb8 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -466,13 +466,11 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin,\n static struct origin *make_origin(struct commit *commit, const char *path)\n {\n \tstruct origin *o;\n-\tsize_t pathlen = strlen(path) + 1;\n-\to = xcalloc(1, sizeof(*o) + pathlen);\n+\tFLEX_ALLOC_STR(o, path, path);\n \to->commit = commit;\n \to->refcnt = 1;\n \to->next = commit->util;\n \tcommit->util = o;\n-\tmemcpy(o->path, path, pathlen); /* includes NUL */\n \treturn o;\n }\n \ndiff --git a/builtin/help.c b/builtin/help.c\nindex 1cd0c1e..3c55ce4 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -171,12 +171,10 @@ static void exec_man_cmd(const char *cmd, const char *page)\n static void add_man_viewer(const char *name)\n {\n \tstruct man_viewer_list **p = &man_viewer_list;\n-\tsize_t len = strlen(name);\n \n \twhile (*p)\n \t\tp = &((*p)->next);\n-\t*p = xcalloc(1, (sizeof(**p) + len + 1));\n-\tmemcpy((*p)->name, name, len); /* NUL-terminated by xcalloc */\n+\tFLEX_ALLOC_STR(*p, name, name);\n }\n \n static int supported_man_viewer(const char *name, size_t len)\n@@ -190,9 +188,8 @@ static void do_add_man_viewer_info(const char *name,\n \t\t\t\t   size_t len,\n \t\t\t\t   const char *value)\n {\n-\tstruct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);\n-\n-\tmemcpy(new->name, name, len); /* NUL-terminated by xcalloc */\n+\tstruct man_viewer_info_list *new;\n+\tFLEX_ALLOC_MEM(new, name, name, len);\n \tnew->info = xstrdup(value);\n \tnew->next = man_viewer_info_list;\n \tman_viewer_info_list = new;\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a237caa..4282b62 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -19,16 +19,17 @@ static int alloc, used;\n static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)\n {\n \tstruct treeent *ent;\n-\tint len = strlen(path);\n+\tsize_t len = strlen(path);\n \tif (strchr(path, '/'))\n \t\tdie(\"path %s contains slash\", path);\n \n-\tALLOC_GROW(entries, used + 1, alloc);\n-\tent = entries[used++] = xmalloc(sizeof(**entries) + len + 1);\n+\tFLEX_ALLOC_MEM(ent, name, path, len);\n \tent->mode = mode;\n \tent->len = len;\n \thashcpy(ent->sha1, sha1);\n-\tmemcpy(ent->name, path, len+1);\n+\n+\tALLOC_GROW(entries, used + 1, alloc);\n+\tentries[used++] = ent;\n }\n \n static int ent_compare(const void *a_, const void *b_)\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 9980731..2d46b64 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -382,11 +382,9 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n {\n \tstruct collected_reflog *e;\n \tstruct collect_reflog_cb *cb = cb_data;\n-\tsize_t namelen = strlen(ref);\n \n-\te = xmalloc(sizeof(*e) + namelen + 1);\n+\tFLEX_ALLOC_STR(e, reflog, ref);\n \thashcpy(e->sha1, oid->hash);\n-\tmemcpy(e->reflog, ref, namelen + 1);\n \tALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);\n \tcb->e[cb->nr++] = e;\n \treturn 0;\n@@ -411,8 +409,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\t    ent->pattern[len] == '\\0')\n \t\t\treturn ent;\n \n-\tent = xcalloc(1, sizeof(*ent) + len + 1);\n-\tmemcpy(ent->pattern, pattern, len);\n+\tFLEX_ALLOC_MEM(ent, pattern, pattern, len);\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\n \treturn ent;\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 20ee7b5..3ebf9c3 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -79,11 +79,9 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,\n \tALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);\n \tit->subtree_nr++;\n \n-\tdown = xmalloc(sizeof(*down) + pathlen + 1);\n+\tFLEX_ALLOC_MEM(down, name, path, pathlen);\n \tdown->cache_tree = NULL;\n \tdown->namelen = pathlen;\n-\tmemcpy(down->name, path, pathlen);\n-\tdown->name[pathlen] = 0;\n \n \tif (pos < it->subtree_nr)\n \t\tmemmove(it->down + pos + 1,\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 890c415..be09a2b 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -319,7 +319,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)\n \tif (line[len-1] == '\\n')\n \t\tlen--;\n \n-\tlline = xmalloc(sizeof(*lline) + len + 1);\n+\tFLEX_ALLOC_MEM(lline, line, line, len);\n \tlline->len = len;\n \tlline->next = NULL;\n \tlline->prev = sline->plost.lost_tail;\n@@ -330,8 +330,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)\n \tsline->plost.lost_tail = lline;\n \tsline->plost.len++;\n \tlline->parent_map = this_mask;\n-\tmemcpy(lline->line, line, len);\n-\tlline->line[len] = 0;\n }\n \n struct combine_diff_state {\ndiff --git a/diff.c b/diff.c\nindex 2136b69..27d14a7 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2607,12 +2607,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,\n \n struct diff_filespec *alloc_filespec(const char *path)\n {\n-\tint namelen = strlen(path);\n-\tstruct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);\n+\tstruct diff_filespec *spec;\n \n-\tmemset(spec, 0, sizeof(*spec));\n-\tspec->path = (char *)(spec + 1);\n-\tmemcpy(spec->path, path, namelen+1);\n+\tFLEXPTR_ALLOC_STR(spec, path, path);\n \tspec->count = 1;\n \tspec->is_binary = -1;\n \treturn spec;\ndiff --git a/dir.c b/dir.c\nindex 6c627d5..f06ebb7 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -503,12 +503,7 @@ void add_exclude(const char *string, const char *base,\n \n \tparse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);\n \tif (flags & EXC_FLAG_MUSTBEDIR) {\n-\t\tchar *s;\n-\t\tx = xmalloc(sizeof(*x) + patternlen + 1);\n-\t\ts = (char *)(x+1);\n-\t\tmemcpy(s, string, patternlen);\n-\t\ts[patternlen] = '\\0';\n-\t\tx->pattern = s;\n+\t\tFLEXPTR_ALLOC_MEM(x, pattern, string, patternlen);\n \t} else {\n \t\tx = xmalloc(sizeof(*x));\n \t\tx->pattern = string;\n@@ -625,10 +620,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,\n \t}\n \n \tuc->dir_created++;\n-\td = xmalloc(sizeof(*d) + len + 1);\n-\tmemset(d, 0, sizeof(*d));\n-\tmemcpy(d->name, name, len);\n-\td->name[len] = '\\0';\n+\tFLEX_ALLOC_MEM(d, name, name, len);\n \n \tALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);\n \tmemmove(dir->dirs + first + 1, dir->dirs + first,\n@@ -1167,10 +1159,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)\n {\n \tstruct dir_entry *ent;\n \n-\tent = xmalloc(sizeof(*ent) + len + 1);\n+\tFLEX_ALLOC_MEM(ent, name, pathname, len);\n \tent->len = len;\n-\tmemcpy(ent->name, pathname, len);\n-\tent->name[len] = 0;\n \treturn ent;\n }\n \ndiff --git a/hashmap.c b/hashmap.c\nindex f693839..b10b642 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len)\n \te = hashmap_get(&map, &key, data);\n \tif (!e) {\n \t\t/* not found: create it */\n-\t\te = xmallocz(sizeof(struct pool_entry) + len);\n+\t\tFLEX_ALLOC_MEM(e, data, data, len);\n \t\thashmap_entry_init(e, key.ent.hash);\n \t\te->len = len;\n-\t\tmemcpy(e->data, data, len);\n \t\thashmap_add(&map, e);\n \t}\n \treturn e->data;\ndiff --git a/help.c b/help.c\nindex d996b34..19328ea 100644\n--- a/help.c\n+++ b/help.c\n@@ -11,11 +11,9 @@\n \n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n-\tstruct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);\n-\n+\tstruct cmdname *ent;\n+\tFLEX_ALLOC_MEM(ent, name, name, len);\n \tent->len = len;\n-\tmemcpy(ent->name, name, len);\n-\tent->name[len] = 0;\n \n \tALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);\n \tcmds->names[cmds->cnt++] = ent;\ndiff --git a/log-tree.c b/log-tree.c\nindex f70a30e..60f9839 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -77,9 +77,8 @@ int parse_decorate_color_config(const char *var, const char *slot_name, const ch\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)\n {\n-\tint nlen = strlen(name);\n-\tstruct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);\n-\tmemcpy(res->name, name, nlen + 1);\n+\tstruct name_decoration *res;\n+\tFLEX_ALLOC_STR(res, name, name);\n \tres->type = type;\n \tres->next = add_decoration(&name_decoration, obj, res);\n }\ndiff --git a/name-hash.c b/name-hash.c\nindex 332ba95..6d9f23e 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -55,10 +55,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \tdir = find_dir_entry(istate, ce->name, namelen);\n \tif (!dir) {\n \t\t/* not found, create it and add to hash table */\n-\t\tdir = xcalloc(1, sizeof(struct dir_entry) + namelen + 1);\n+\t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n \t\thashmap_entry_init(dir, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n-\t\tstrncpy(dir->name, ce->name, namelen);\n \t\thashmap_add(&istate->dir_hash, dir);\n \n \t\t/* recursively add missing parent directories */\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f097176..9ccfc51 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1255,10 +1255,8 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \t\t\t\t\t\t const unsigned char *objectname,\n \t\t\t\t\t\t int flag)\n {\n-\tsize_t len = strlen(refname);\n-\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n-\tmemcpy(ref->refname, refname, len);\n-\tref->refname[len] = '\\0';\n+\tstruct ref_array_item *ref;\n+\tFLEX_ALLOC_STR(ref, refname, refname);\n \thashcpy(ref->objectname, objectname);\n \tref->flag = flag;\n \ndiff --git a/refs.c b/refs.c\nindex 1d9e2a7..2d86445 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -761,10 +761,8 @@ void ref_transaction_free(struct ref_transaction *transaction)\n static struct ref_update *add_update(struct ref_transaction *transaction,\n \t\t\t\t     const char *refname)\n {\n-\tsize_t len = strlen(refname) + 1;\n-\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n-\n-\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n+\tstruct ref_update *update;\n+\tFLEX_ALLOC_STR(update, refname, refname);\n \tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n \ttransaction->updates[transaction->nr++] = update;\n \treturn update;\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex b569762..81f68f8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -199,17 +199,14 @@ static struct ref_entry *create_ref_entry(const char *refname,\n \t\t\t\t\t  const unsigned char *sha1, int flag,\n \t\t\t\t\t  int check_name)\n {\n-\tint len;\n \tstruct ref_entry *ref;\n \n \tif (check_name &&\n \t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))\n \t\tdie(\"Reference has invalid format: '%s'\", refname);\n-\tlen = strlen(refname) + 1;\n-\tref = xmalloc(sizeof(struct ref_entry) + len);\n+\tFLEX_ALLOC_STR(ref, name, refname);\n \thashcpy(ref->u.value.oid.hash, sha1);\n \toidclr(&ref->u.value.peeled);\n-\tmemcpy(ref->name, refname, len);\n \tref->flag = flag;\n \treturn ref;\n }\n@@ -268,9 +265,7 @@ static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n \t\t\t\t\t  int incomplete)\n {\n \tstruct ref_entry *direntry;\n-\tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n-\tmemcpy(direntry->name, dirname, len);\n-\tdirentry->name[len] = '\\0';\n+\tFLEX_ALLOC_MEM(direntry, name, dirname, len);\n \tdirentry->u.subdir.ref_cache = ref_cache;\n \tdirentry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);\n \treturn direntry;\n@@ -939,13 +934,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)\n  */\n static struct ref_cache *create_ref_cache(const char *submodule)\n {\n-\tint len;\n \tstruct ref_cache *refs;\n \tif (!submodule)\n \t\tsubmodule = \"\";\n-\tlen = strlen(submodule) + 1;\n-\trefs = xcalloc(1, sizeof(struct ref_cache) + len);\n-\tmemcpy(refs->name, submodule, len);\n+\tFLEX_ALLOC_STR(refs, name, submodule);\n \trefs->next = submodule_ref_caches;\n \tsubmodule_ref_caches = refs;\n \treturn refs;\n@@ -2197,10 +2189,9 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)\n \n \t/* Schedule the loose reference for pruning if requested. */\n \tif ((cb->flags & PACK_REFS_PRUNE)) {\n-\t\tint namelen = strlen(entry->name) + 1;\n-\t\tstruct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);\n+\t\tstruct ref_to_prune *n;\n+\t\tFLEX_ALLOC_STR(n, name, entry->name);\n \t\thashcpy(n->sha1, entry->u.value.oid.hash);\n-\t\tmemcpy(n->name, entry->name, namelen); /* includes NUL */\n \t\tn->next = cb->ref_to_prune;\n \t\tcb->ref_to_prune = n;\n \t}\ndiff --git a/remote.c b/remote.c\nindex 02e698a..25a960f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -2136,16 +2136,13 @@ static int one_local_ref(const char *refname, const struct object_id *oid,\n {\n \tstruct ref ***local_tail = cb_data;\n \tstruct ref *ref;\n-\tint len;\n \n \t/* we already know it starts with refs/ to get here */\n \tif (check_refname_format(refname + 5, 0))\n \t\treturn 0;\n \n-\tlen = strlen(refname) + 1;\n-\tref = xcalloc(1, sizeof(*ref) + len);\n+\tref = alloc_ref(refname);\n \toidcpy(&ref->new_oid, oid);\n-\tmemcpy(ref->name, refname, len);\n \t**local_tail = ref;\n \t*local_tail = &ref->next;\n \treturn 0;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278646","messageId":"20160219112349.GJ9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 10/21] use st_add and st_mult for allocation size computation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:23:50Z","receivedAt":"2016-02-19T11:23:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"If our size computation overflows size_t, we may allocate a\nmuch smaller buffer than we expected and overflow it. It's\nprobably impossible to trigger an overflow in most of these\nsites in practice, but it is easy enough convert their\nadditions and multiplications into overflow-checking\nvariants. This may be fixing real bugs, and it makes\nauditing the code easier.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n archive.c              |  4 ++--\n builtin/apply.c        |  2 +-\n builtin/clean.c        |  2 +-\n builtin/fetch.c        |  2 +-\n builtin/index-pack.c   |  4 ++--\n builtin/merge.c        |  2 +-\n builtin/mv.c           |  4 ++--\n builtin/receive-pack.c |  2 +-\n combine-diff.c         | 14 +++++++-------\n commit.c               |  2 +-\n compat/mingw.c         |  4 ++--\n compat/qsort.c         |  2 +-\n compat/setenv.c        |  2 +-\n compat/win32/syslog.c  |  4 ++--\n diffcore-delta.c       |  6 ++++--\n diffcore-rename.c      |  2 +-\n dir.c                  |  4 ++--\n fast-import.c          |  2 +-\n refs.c                 |  2 +-\n remote.c               |  8 ++++----\n revision.c             |  2 +-\n sha1_file.c            | 20 +++++++++++---------\n sha1_name.c            |  5 ++---\n shallow.c              |  2 +-\n submodule.c            |  6 +++---\n 25 files changed, 56 insertions(+), 53 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 0687afa..5d735ae 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -171,8 +171,8 @@ static void queue_directory(const unsigned char *sha1,\n \t\tunsigned mode, int stage, struct archiver_context *c)\n {\n \tstruct directory *d;\n-\tsize_t len = base->len + 1 + strlen(filename) + 1;\n-\td = xmalloc(sizeof(*d) + len);\n+\tsize_t len = st_add4(base->len, 1, strlen(filename), 1);\n+\td = xmalloc(st_add(sizeof(*d), len));\n \td->up\t   = c->bottom;\n \td->baselen = base->len;\n \td->mode\t   = mode;\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex d61ac65..42c610e 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -2632,7 +2632,7 @@ static void update_image(struct image *img,\n \tinsert_count = postimage->len;\n \n \t/* Adjust the contents */\n-\tresult = xmalloc(img->len + insert_count - remove_count + 1);\n+\tresult = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));\n \tmemcpy(result, img->buf, applied_at);\n \tmemcpy(result + applied_at, postimage->buf, postimage->len);\n \tmemcpy(result + applied_at + postimage->len,\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 8229f7e..0371010 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -615,7 +615,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t\tnr += chosen[i];\n \t\t}\n \n-\t\tresult = xcalloc(nr + 1, sizeof(int));\n+\t\tresult = xcalloc(st_add(nr, 1), sizeof(int));\n \t\tfor (i = 0; i < stuff->nr && j < nr; i++) {\n \t\t\tif (chosen[i])\n \t\t\t\tresult[j++] = i;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8e74213..373a89d 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1110,7 +1110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)\n \tif (argc > 0) {\n \t\tint j = 0;\n \t\tint i;\n-\t\trefs = xcalloc(argc + 1, sizeof(const char *));\n+\t\trefs = xcalloc(st_add(argc, 1), sizeof(const char *));\n \t\tfor (i = 0; i < argc; i++) {\n \t\t\tif (!strcmp(argv[i], \"tag\")) {\n \t\t\t\ti++;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex a60bcfa..193908a 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1744,9 +1744,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \n \tcurr_pack = open_pack_file(pack_name);\n \tparse_pack_header();\n-\tobjects = xcalloc(nr_objects + 1, sizeof(struct object_entry));\n+\tobjects = xcalloc(st_add(nr_objects, 1), sizeof(struct object_entry));\n \tif (show_stat)\n-\t\tobj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat));\n+\t\tobj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));\n \tofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));\n \tparse_pack_objects(pack_sha1);\n \tresolve_deltas();\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex b98a348..101ffef 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -939,7 +939,7 @@ static int setup_with_upstream(const char ***argv)\n \tif (!branch->merge_nr)\n \t\tdie(_(\"No default upstream defined for the current branch.\"));\n \n-\targs = xcalloc(branch->merge_nr + 1, sizeof(char *));\n+\targs = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));\n \tfor (i = 0; i < branch->merge_nr; i++) {\n \t\tif (!branch->merge[i]->dst)\n \t\t\tdie(_(\"No remote-tracking branch for %s from %s\"),\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 9a9813a..aeae855 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -48,9 +48,9 @@ static const char **internal_copy_pathspec(const char *prefix,\n \n static const char *add_slash(const char *path)\n {\n-\tint len = strlen(path);\n+\tsize_t len = strlen(path);\n \tif (path[len - 1] != '/') {\n-\t\tchar *with_slash = xmalloc(len + 2);\n+\t\tchar *with_slash = xmalloc(st_add(len, 2));\n \t\tmemcpy(with_slash, path, len);\n \t\twith_slash[len++] = '/';\n \t\twith_slash[len] = 0;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 3dc3868..c8e32b2 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1372,7 +1372,7 @@ static struct command **queue_command(struct command **tail,\n \n \trefname = line + 82;\n \treflen = linelen - 82;\n-\tcmd = xcalloc(1, sizeof(struct command) + reflen + 1);\n+\tcmd = xcalloc(1, st_add3(sizeof(struct command), reflen, 1));\n \thashcpy(cmd->old_sha1, old_sha1);\n \thashcpy(cmd->new_sha1, new_sha1);\n \tmemcpy(cmd->ref_name, refname, reflen);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex be09a2b..0e1d4b0 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -189,11 +189,11 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,\n \t *   - Else if we have NEW, insert newend lline into base and\n \t *   consume newend\n \t */\n-\tlcs = xcalloc(origbaselen + 1, sizeof(int*));\n-\tdirections = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));\n+\tlcs = xcalloc(st_add(origbaselen, 1), sizeof(int*));\n+\tdirections = xcalloc(st_add(origbaselen, 1), sizeof(enum coalesce_direction*));\n \tfor (i = 0; i < origbaselen + 1; i++) {\n-\t\tlcs[i] = xcalloc(lennew + 1, sizeof(int));\n-\t\tdirections[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));\n+\t\tlcs[i] = xcalloc(st_add(lennew, 1), sizeof(int));\n+\t\tdirections[i] = xcalloc(st_add(lennew, 1), sizeof(enum coalesce_direction));\n \t\tdirections[i][0] = BASE;\n \t}\n \tfor (j = 1; j < lennew + 1; j++)\n@@ -1111,7 +1111,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \tif (result_size && result[result_size-1] != '\\n')\n \t\tcnt++; /* incomplete line */\n \n-\tsline = xcalloc(cnt+2, sizeof(*sline));\n+\tsline = xcalloc(st_add(cnt, 2), sizeof(*sline));\n \tsline[0].bol = result;\n \tfor (lno = 0, cp = result; cp < result + result_size; cp++) {\n \t\tif (*cp == '\\n') {\n@@ -1130,7 +1130,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t/* Even p_lno[cnt+1] is valid -- that is for the end line number\n \t * for deletion hunk at the end.\n \t */\n-\tsline[0].p_lno = xcalloc((cnt+2) * num_parent, sizeof(unsigned long));\n+\tsline[0].p_lno = xcalloc(st_mult(st_add(cnt, 2), num_parent), sizeof(unsigned long));\n \tfor (lno = 0; lno <= cnt; lno++)\n \t\tsline[lno+1].p_lno = sline[lno].p_lno + num_parent;\n \n@@ -1262,7 +1262,7 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p,\n \tstruct diff_filespec *pool;\n \n \tpair = xmalloc(sizeof(*pair));\n-\tpool = xcalloc(num_parent + 1, sizeof(struct diff_filespec));\n+\tpool = xcalloc(st_add(num_parent, 1), sizeof(struct diff_filespec));\n \tpair->one = pool + 1;\n \tpair->two = pool;\n \ndiff --git a/commit.c b/commit.c\nindex 31cd91f..3f4f371 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -147,7 +147,7 @@ struct commit_graft *read_graft_line(char *buf, int len)\n \tif ((len + 1) % entry_size)\n \t\tgoto bad_graft_data;\n \ti = (len + 1) / entry_size - 1;\n-\tgraft = xmalloc(sizeof(*graft) + GIT_SHA1_RAWSZ * i);\n+\tgraft = xmalloc(st_add(sizeof(*graft), st_mult(GIT_SHA1_RAWSZ, i)));\n \tgraft->nr_parent = i;\n \tif (get_oid_hex(buf, &graft->oid))\n \t\tgoto bad_graft_data;\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 7803f30..cfedcf9 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -810,7 +810,7 @@ static const char *quote_arg(const char *arg)\n \t\treturn arg;\n \n \t/* insert \\ where necessary */\n-\td = q = xmalloc(len+n+3);\n+\td = q = xmalloc(st_add3(len, n, 3));\n \t*d++ = '\"';\n \twhile (*arg) {\n \t\tif (*arg == '\"')\n@@ -1069,7 +1069,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen\n \t\t\tfree(quoted);\n \t}\n \n-\twargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));\n+\twargs = xmalloc_array(st_add(st_mult(2, args.len), 1), sizeof(wchar_t));\n \txutftowcs(wargs, args.buf, 2 * args.len + 1);\n \tstrbuf_release(&args);\n \ndiff --git a/compat/qsort.c b/compat/qsort.c\nindex 9574d53..7d071af 100644\n--- a/compat/qsort.c\n+++ b/compat/qsort.c\n@@ -47,7 +47,7 @@ static void msort_with_tmp(void *b, size_t n, size_t s,\n void git_qsort(void *b, size_t n, size_t s,\n \t       int (*cmp)(const void *, const void *))\n {\n-\tconst size_t size = n * s;\n+\tconst size_t size = st_mult(n, s);\n \tchar buf[1024];\n \n \tif (size < sizeof(buf)) {\ndiff --git a/compat/setenv.c b/compat/setenv.c\nindex fc1439a..7849f25 100644\n--- a/compat/setenv.c\n+++ b/compat/setenv.c\n@@ -18,7 +18,7 @@ int gitsetenv(const char *name, const char *value, int replace)\n \n \tnamelen = strlen(name);\n \tvaluelen = strlen(value);\n-\tenvstr = malloc((namelen + valuelen + 2));\n+\tenvstr = malloc(st_add3(namelen, valuelen, 2));\n \tif (!envstr) {\n \t\terrno = ENOMEM;\n \t\treturn -1;\ndiff --git a/compat/win32/syslog.c b/compat/win32/syslog.c\nindex d015e43..b905aea 100644\n--- a/compat/win32/syslog.c\n+++ b/compat/win32/syslog.c\n@@ -32,7 +32,7 @@ void syslog(int priority, const char *fmt, ...)\n \t\treturn;\n \t}\n \n-\tstr = malloc(str_len + 1);\n+\tstr = malloc(st_add(str_len, 1));\n \tif (!str) {\n \t\twarning(\"malloc failed: '%s'\", strerror(errno));\n \t\treturn;\n@@ -43,7 +43,7 @@ void syslog(int priority, const char *fmt, ...)\n \tva_end(ap);\n \n \twhile ((pos = strstr(str, \"%1\")) != NULL) {\n-\t\tstr = realloc(str, ++str_len + 1);\n+\t\tstr = realloc(str, st_add(++str_len, 1));\n \t\tif (!str) {\n \t\t\twarning(\"realloc failed: '%s'\", strerror(errno));\n \t\t\treturn;\ndiff --git a/diffcore-delta.c b/diffcore-delta.c\nindex 7cf431d..4159748 100644\n--- a/diffcore-delta.c\n+++ b/diffcore-delta.c\n@@ -53,7 +53,8 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)\n \tint osz = 1 << orig->alloc_log2;\n \tint sz = osz << 1;\n \n-\tnew = xmalloc(sizeof(*orig) + sizeof(struct spanhash) * sz);\n+\tnew = xmalloc(st_add(sizeof(*orig),\n+\t\t\t     st_mult(sizeof(struct spanhash), sz)));\n \tnew->alloc_log2 = orig->alloc_log2 + 1;\n \tnew->free = INITIAL_FREE(new->alloc_log2);\n \tmemset(new->data, 0, sizeof(struct spanhash) * sz);\n@@ -130,7 +131,8 @@ static struct spanhash_top *hash_chars(struct diff_filespec *one)\n \tint is_text = !diff_filespec_is_binary(one);\n \n \ti = INITIAL_HASH_SIZE;\n-\thash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i));\n+\thash = xmalloc(st_add(sizeof(*hash),\n+\t\t\t      st_mult(sizeof(struct spanhash), 1<<i)));\n \thash->alloc_log2 = i;\n \thash->free = INITIAL_FREE(i);\n \tmemset(hash->data, 0, sizeof(struct spanhash) * (1<<i));\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex af1fe08..3b3c1ed 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -537,7 +537,7 @@ void diffcore_rename(struct diff_options *options)\n \t\t\t\trename_dst_nr * rename_src_nr, 50, 1);\n \t}\n \n-\tmx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));\n+\tmx = xcalloc(st_mult(num_create, NUM_CANDIDATE_PER_DST), sizeof(*mx));\n \tfor (dst_cnt = i = 0; i < rename_dst_nr; i++) {\n \t\tstruct diff_filespec *two = rename_dst[i].two;\n \t\tstruct diff_score *m;\ndiff --git a/dir.c b/dir.c\nindex f06ebb7..2c91541 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -689,7 +689,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\treturn 0;\n \t\t}\n \t\tif (buf[size-1] != '\\n') {\n-\t\t\tbuf = xrealloc(buf, size+1);\n+\t\t\tbuf = xrealloc(buf, st_add(size, 1));\n \t\t\tbuf[size++] = '\\n';\n \t\t}\n \t} else {\n@@ -2488,7 +2488,7 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,\n \tnext = data + len + 1;\n \tif (next > rd->end)\n \t\treturn -1;\n-\t*untracked_ = untracked = xmalloc(sizeof(*untracked) + len);\n+\t*untracked_ = untracked = xmalloc(st_add(sizeof(*untracked), len));\n \tmemcpy(untracked, &ud, sizeof(ud));\n \tmemcpy(untracked->name, data, len + 1);\n \tdata = next;\ndiff --git a/fast-import.c b/fast-import.c\nindex a6467cb..3053bb8 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -622,7 +622,7 @@ static void *pool_alloc(size_t len)\n \t\t\treturn xmalloc(len);\n \t\t}\n \t\ttotal_allocd += sizeof(struct mem_pool) + mem_pool_alloc;\n-\t\tp = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc);\n+\t\tp = xmalloc(st_add(sizeof(struct mem_pool), mem_pool_alloc));\n \t\tp->next_pool = mem_pool;\n \t\tp->next_free = (char *) p->space;\n \t\tp->end = p->next_free + mem_pool_alloc;\ndiff --git a/refs.c b/refs.c\nindex 2d86445..b0e6ece 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -906,7 +906,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n \t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n \n-\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n+\t\tscanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len));\n \n \t\toffset = 0;\n \t\tfor (i = 0; i < nr_rules; i++) {\ndiff --git a/remote.c b/remote.c\nindex 25a960f..21e4ec3 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -931,7 +931,7 @@ static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,\n \t\tconst char *name)\n {\n \tsize_t len = strlen(name);\n-\tstruct ref *ref = xcalloc(1, sizeof(struct ref) + prefixlen + len + 1);\n+\tstruct ref *ref = xcalloc(1, st_add4(sizeof(*ref), prefixlen, len, 1));\n \tmemcpy(ref->name, prefix, prefixlen);\n \tmemcpy(ref->name + prefixlen, name, len);\n \treturn ref;\n@@ -948,9 +948,9 @@ struct ref *copy_ref(const struct ref *ref)\n \tsize_t len;\n \tif (!ref)\n \t\treturn NULL;\n-\tlen = strlen(ref->name);\n-\tcpy = xmalloc(sizeof(struct ref) + len + 1);\n-\tmemcpy(cpy, ref, sizeof(struct ref) + len + 1);\n+\tlen = st_add3(sizeof(struct ref), strlen(ref->name), 1);\n+\tcpy = xmalloc(len);\n+\tmemcpy(cpy, ref, len);\n \tcpy->next = NULL;\n \tcpy->symref = xstrdup_or_null(ref->symref);\n \tcpy->remote_status = xstrdup_or_null(ref->remote_status);\ndiff --git a/revision.c b/revision.c\nindex f24ead5..d4ace60 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -540,7 +540,7 @@ struct treesame_state {\n static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)\n {\n \tunsigned n = commit_list_count(commit->parents);\n-\tstruct treesame_state *st = xcalloc(1, sizeof(*st) + n);\n+\tstruct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n));\n \tst->nparents = n;\n \tadd_decoration(&revs->treesame, &commit->object, st);\n \treturn st;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 2f1c6d3..0251700 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -253,7 +253,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,\n {\n \tstruct alternate_object_database *ent;\n \tstruct alternate_object_database *alt;\n-\tint pfxlen, entlen;\n+\tsize_t pfxlen, entlen;\n \tstruct strbuf pathbuf = STRBUF_INIT;\n \n \tif (!is_absolute_path(entry) && relative_base) {\n@@ -273,8 +273,8 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,\n \twhile (pfxlen && pathbuf.buf[pfxlen-1] == '/')\n \t\tpfxlen -= 1;\n \n-\tentlen = pfxlen + 43; /* '/' + 2 hex + '/' + 38 hex + NUL */\n-\tent = xmalloc(sizeof(*ent) + entlen);\n+\tentlen = st_add(pfxlen, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */\n+\tent = xmalloc(st_add(sizeof(*ent), entlen));\n \tmemcpy(ent->base, pathbuf.buf, pfxlen);\n \tstrbuf_release(&pathbuf);\n \n@@ -1134,7 +1134,7 @@ unsigned char *use_pack(struct packed_git *p,\n \n static struct packed_git *alloc_packed_git(int extra)\n {\n-\tstruct packed_git *p = xmalloc(sizeof(*p) + extra);\n+\tstruct packed_git *p = xmalloc(st_add(sizeof(*p), extra));\n \tmemset(p, 0, sizeof(*p));\n \tp->pack_fd = -1;\n \treturn p;\n@@ -1168,7 +1168,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)\n \t * \".pack\" is long enough to hold any suffix we're adding (and\n \t * the use xsnprintf double-checks that)\n \t */\n-\talloc = path_len + strlen(\".pack\") + 1;\n+\talloc = st_add3(path_len, strlen(\".pack\"), 1);\n \tp = alloc_packed_git(alloc);\n \tmemcpy(p->pack_name, path, path_len);\n \n@@ -1196,7 +1196,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)\n struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)\n {\n \tconst char *path = sha1_pack_name(sha1);\n-\tint alloc = strlen(path) + 1;\n+\tsize_t alloc = st_add(strlen(path), 1);\n \tstruct packed_git *p = alloc_packed_git(alloc);\n \n \tmemcpy(p->pack_name, path, alloc); /* includes NUL */\n@@ -1413,10 +1413,12 @@ static void mark_bad_packed_object(struct packed_git *p,\n {\n \tunsigned i;\n \tfor (i = 0; i < p->num_bad_objects; i++)\n-\t\tif (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))\n+\t\tif (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i))\n \t\t\treturn;\n-\tp->bad_object_sha1 = xrealloc(p->bad_object_sha1, 20 * (p->num_bad_objects + 1));\n-\thashcpy(p->bad_object_sha1 + 20 * p->num_bad_objects, sha1);\n+\tp->bad_object_sha1 = xrealloc(p->bad_object_sha1,\n+\t\t\t\t      st_mult(GIT_SHA1_RAWSZ,\n+\t\t\t\t\t      st_add(p->num_bad_objects, 1)));\n+\thashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1);\n \tp->num_bad_objects++;\n }\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex 89918ca..d14346c 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -87,9 +87,8 @@ static void find_short_object_filename(int len, const char *hex_pfx, struct disa\n \t\t * object databases including our own.\n \t\t */\n \t\tconst char *objdir = get_object_directory();\n-\t\tint objdir_len = strlen(objdir);\n-\t\tint entlen = objdir_len + 43;\n-\t\tfakeent = xmalloc(sizeof(*fakeent) + entlen);\n+\t\tsize_t objdir_len = strlen(objdir);\n+\t\tfakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43));\n \t\tmemcpy(fakeent->base, objdir, objdir_len);\n \t\tfakeent->name = fakeent->base + objdir_len + 1;\n \t\tfakeent->name[-1] = '/';\ndiff --git a/shallow.c b/shallow.c\nindex 71163bf..4d554ca 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -389,7 +389,7 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,\n \tunsigned int i, nr;\n \tstruct commit_list *head = NULL;\n \tint bitmap_nr = (info->nr_bits + 31) / 32;\n-\tint bitmap_size = bitmap_nr * sizeof(uint32_t);\n+\tsize_t bitmap_size = st_mult(bitmap_nr, sizeof(uint32_t));\n \tuint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */\n \tuint32_t *bitmap = paint_alloc(info);\n \tstruct commit *c = lookup_commit_reference_gently(sha1, 1);\ndiff --git a/submodule.c b/submodule.c\nindex b83939c..ac61c65 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -123,7 +123,7 @@ static int add_submodule_odb(const char *path)\n \tstruct strbuf objects_directory = STRBUF_INIT;\n \tstruct alternate_object_database *alt_odb;\n \tint ret = 0;\n-\tint alloc;\n+\tsize_t alloc;\n \n \tstrbuf_git_path_submodule(&objects_directory, path, \"objects/\");\n \tif (!is_directory(objects_directory.buf)) {\n@@ -138,8 +138,8 @@ static int add_submodule_odb(const char *path)\n \t\t\t\t\tobjects_directory.len))\n \t\t\tgoto done;\n \n-\talloc = objects_directory.len + 42; /* for \"12/345...\" sha1 */\n-\talt_odb = xmalloc(sizeof(*alt_odb) + alloc);\n+\talloc = st_add(objects_directory.len, 42); /* for \"12/345...\" sha1 */\n+\talt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc));\n \talt_odb->next = alt_odb_list;\n \txsnprintf(alt_odb->base, alloc, \"%s\", objects_directory.buf);\n \talt_odb->name = alt_odb->base + objects_directory.len;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278648","messageId":"20160219112438.GK9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 11/21] prepare_{git,shell}_cmd: use argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:24:38Z","receivedAt":"2016-02-19T11:24:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"These functions transform an existing argv into one suitable\nfor exec-ing or spawning via git or a shell. We can use an\nargv_array in each to avoid dealing with manual counting and\nallocation.\n\nThis also makes the memory allocation more clear and fixes\nsome leaks. In prepare_shell_cmd, we would sometimes\nallocate a new string with \"$@\" in it and sometimes not,\nmeaning the caller could not correctly free it. On the\nnon-Windows side, we are in a child process which will\nexec() or exit() immediately, so the leak isn't a big deal.\nOn Windows, though, we use spawn() from the parent process,\nand leak a string for each shell command we run. On top of\nthat, the Windows code did not free the allocated argv array\nat all (but does for the prepare_git_cmd case!).\n\nBy switching both of these functions to write into an\nargv_array, we can consistently free the result as\nappropriate.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nNote that I had to touch the Windows run-command code here, but I don't\nactually have a platform to test it on.\n\n exec_cmd.c    | 28 +++++++++++-----------------\n exec_cmd.h    |  4 +++-\n run-command.c | 60 +++++++++++++++++++++++++----------------------------------\n 3 files changed, 39 insertions(+), 53 deletions(-)\n\ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex e85f0fd..cf442a9 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"exec_cmd.h\"\n #include \"quote.h\"\n+#include \"argv-array.h\"\n #define MAX_ARGS\t32\n \n static const char *argv_exec_path;\n@@ -107,32 +108,25 @@ void setup_path(void)\n \tstrbuf_release(&new_path);\n }\n \n-const char **prepare_git_cmd(const char **argv)\n+const char **prepare_git_cmd(struct argv_array *out, const char **argv)\n {\n-\tint argc;\n-\tconst char **nargv;\n-\n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\t; /* just counting */\n-\tnargv = xmalloc(sizeof(*nargv) * (argc + 2));\n-\n-\tnargv[0] = \"git\";\n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\tnargv[argc + 1] = argv[argc];\n-\tnargv[argc + 1] = NULL;\n-\treturn nargv;\n+\targv_array_push(out, \"git\");\n+\targv_array_pushv(out, argv);\n+\treturn out->argv;\n }\n \n int execv_git_cmd(const char **argv) {\n-\tconst char **nargv = prepare_git_cmd(argv);\n-\ttrace_argv_printf(nargv, \"trace: exec:\");\n+\tstruct argv_array nargv = ARGV_ARRAY_INIT;\n+\n+\tprepare_git_cmd(&nargv, argv);\n+\ttrace_argv_printf(nargv.argv, \"trace: exec:\");\n \n \t/* execvp() can only ever return if it fails */\n-\tsane_execvp(\"git\", (char **)nargv);\n+\tsane_execvp(\"git\", (char **)nargv.argv);\n \n \ttrace_printf(\"trace: exec failed: %s\\n\", strerror(errno));\n \n-\tfree(nargv);\n+\targv_array_clear(&nargv);\n \treturn -1;\n }\n \ndiff --git a/exec_cmd.h b/exec_cmd.h\nindex 93b0c02..1f6b433 100644\n--- a/exec_cmd.h\n+++ b/exec_cmd.h\n@@ -1,11 +1,13 @@\n #ifndef GIT_EXEC_CMD_H\n #define GIT_EXEC_CMD_H\n \n+struct argv_array;\n+\n extern void git_set_argv_exec_path(const char *exec_path);\n extern const char *git_extract_argv0_path(const char *path);\n extern const char *git_exec_path(void);\n extern void setup_path(void);\n-extern const char **prepare_git_cmd(const char **argv);\n+extern const char **prepare_git_cmd(struct argv_array *out, const char **argv);\n extern int execv_git_cmd(const char **argv); /* NULL terminated */\n LAST_ARG_MUST_BE_NULL\n extern int execl_git_cmd(const char *cmd, ...);\ndiff --git a/run-command.c b/run-command.c\nindex cdf0184..019f6d1 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -160,50 +160,41 @@ int sane_execvp(const char *file, char * const argv[])\n \treturn -1;\n }\n \n-static const char **prepare_shell_cmd(const char **argv)\n+static const char **prepare_shell_cmd(struct argv_array *out, const char **argv)\n {\n-\tint argc, nargc = 0;\n-\tconst char **nargv;\n-\n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\t; /* just counting */\n-\t/* +1 for NULL, +3 for \"sh -c\" plus extra $0 */\n-\tnargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));\n-\n-\tif (argc < 1)\n+\tif (!argv[0])\n \t\tdie(\"BUG: shell command is empty\");\n \n \tif (strcspn(argv[0], \"|&;<>()$`\\\\\\\"' \\t\\n*?[#~=%\") != strlen(argv[0])) {\n #ifndef GIT_WINDOWS_NATIVE\n-\t\tnargv[nargc++] = SHELL_PATH;\n+\t\targv_array_push(out, SHELL_PATH);\n #else\n-\t\tnargv[nargc++] = \"sh\";\n+\t\targv_array_push(out, \"sh\");\n #endif\n-\t\tnargv[nargc++] = \"-c\";\n-\n-\t\tif (argc < 2)\n-\t\t\tnargv[nargc++] = argv[0];\n-\t\telse {\n-\t\t\tstruct strbuf arg0 = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&arg0, \"%s \\\"$@\\\"\", argv[0]);\n-\t\t\tnargv[nargc++] = strbuf_detach(&arg0, NULL);\n-\t\t}\n-\t}\n+\t\targv_array_push(out, \"-c\");\n \n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\tnargv[nargc++] = argv[argc];\n-\tnargv[nargc] = NULL;\n+\t\t/*\n+\t\t * If we have no extra arguments, we do not even need to\n+\t\t * bother with the \"$@\" magic.\n+\t\t */\n+\t\tif (!argv[1])\n+\t\t\targv_array_push(out, argv[0]);\n+\t\telse\n+\t\t\targv_array_pushf(out, \"%s \\\"$@\\\"\", argv[0]);\n+\t}\n \n-\treturn nargv;\n+\targv_array_pushv(out, argv);\n+\treturn out->argv;\n }\n \n #ifndef GIT_WINDOWS_NATIVE\n static int execv_shell_cmd(const char **argv)\n {\n-\tconst char **nargv = prepare_shell_cmd(argv);\n-\ttrace_argv_printf(nargv, \"trace: exec:\");\n-\tsane_execvp(nargv[0], (char **)nargv);\n-\tfree(nargv);\n+\tstruct argv_array nargv = ARGV_ARRAY_INIT;\n+\tprepare_shell_cmd(&nargv, argv);\n+\ttrace_argv_printf(nargv.argv, \"trace: exec:\");\n+\tsane_execvp(nargv.argv[0], (char **)nargv.argv);\n+\targv_array_clear(&nargv);\n \treturn -1;\n }\n #endif\n@@ -457,6 +448,7 @@ fail_pipe:\n {\n \tint fhin = 0, fhout = 1, fherr = 2;\n \tconst char **sargv = cmd->argv;\n+\tstruct argv_array nargv = ARGV_ARRAY_INIT;\n \n \tif (cmd->no_stdin)\n \t\tfhin = open(\"/dev/null\", O_RDWR);\n@@ -482,9 +474,9 @@ fail_pipe:\n \t\tfhout = dup(cmd->out);\n \n \tif (cmd->git_cmd)\n-\t\tcmd->argv = prepare_git_cmd(cmd->argv);\n+\t\tcmd->argv = prepare_git_cmd(&nargv, cmd->argv);\n \telse if (cmd->use_shell)\n-\t\tcmd->argv = prepare_shell_cmd(cmd->argv);\n+\t\tcmd->argv = prepare_shell_cmd(&nargv, cmd->argv);\n \n \tcmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,\n \t\t\tcmd->dir, fhin, fhout, fherr);\n@@ -494,9 +486,7 @@ fail_pipe:\n \tif (cmd->clean_on_exit && cmd->pid >= 0)\n \t\tmark_child_for_cleanup(cmd->pid);\n \n-\tif (cmd->git_cmd)\n-\t\tfree(cmd->argv);\n-\n+\targv_array_clear(&nargv);\n \tcmd->argv = sargv;\n \tif (fhin != 0)\n \t\tclose(fhin);\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278651","messageId":"20160219112446.GL9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 12/21] write_untracked_extension: use FLEX_ALLOC helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:24:46Z","receivedAt":"2016-02-19T11:24:46Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We perform unchecked additions when computing the size of a\n\"struct ondisk_untracked_cache\". This is unlikely to have an\ninteger overflow in practice, but we'd like to avoid this\ndangerous pattern to make further audits easier.\n\nNote that there's one subtlety here, though.  We protect\nourselves against a NULL exclude_per_dir entry in our\nsource, and avoid calling strlen() on it, keeping \"len\" at\n0. But later, we unconditionally memcpy \"len + 1\" bytes to\nget the trailing NUL byte. If we did have a NULL\nexclude_per_dir, we would read from bogus memory.\n\nAs it turns out, though, we always create this field\npointing to a string literal, so there's no bug. We can just\nget rid of the pointless extra conditional.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n dir.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 2c91541..a4a9d9f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2360,16 +2360,15 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra\n \tstruct ondisk_untracked_cache *ouc;\n \tstruct write_data wd;\n \tunsigned char varbuf[16];\n-\tint len = 0, varint_len;\n-\tif (untracked->exclude_per_dir)\n-\t\tlen = strlen(untracked->exclude_per_dir);\n-\touc = xmalloc(sizeof(*ouc) + len + 1);\n+\tint varint_len;\n+\tsize_t len = strlen(untracked->exclude_per_dir);\n+\n+\tFLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);\n \tstat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);\n \tstat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);\n \thashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);\n \thashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);\n \touc->dir_flags = htonl(untracked->dir_flags);\n-\tmemcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);\n \n \tvarint_len = encode_varint(untracked->ident.len, varbuf);\n \tstrbuf_add(out, varbuf, varint_len);\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278650","messageId":"20160219112449.GM9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 13/21] fast-import: simplify allocation in start_packfile","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:24:49Z","receivedAt":"2016-02-19T11:24:49Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This function allocate a packed_git flex-array, and adds a\nmysterious 2 bytes to the length of the pack_name field. One\nis for the trailing NUL, but the other has no purpose. This\nis probably cargo-culted from add_packed_git, which gets the\n\".idx\" path and needed to allocate enough space to hold the\nmatching \".pack\" (though since 48bcc1c, we calculate the\nsize there differently).\n\nThis site, however, is using the raw path of a tempfile, and\ndoes not need the extra byte. We can just replace the\nallocation with FLEX_ALLOC_STR, which handles the allocation\nand the NUL for us.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n fast-import.c | 5 +----\n 1 file changed, 1 insertion(+), 4 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 3053bb8..9fc7093 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -865,15 +865,12 @@ static void start_packfile(void)\n {\n \tstatic char tmp_file[PATH_MAX];\n \tstruct packed_git *p;\n-\tint namelen;\n \tstruct pack_header hdr;\n \tint pack_fd;\n \n \tpack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),\n \t\t\t      \"pack/tmp_pack_XXXXXX\");\n-\tnamelen = strlen(tmp_file) + 2;\n-\tp = xcalloc(1, sizeof(*p) + namelen);\n-\txsnprintf(p->pack_name, namelen, \"%s\", tmp_file);\n+\tFLEX_ALLOC_STR(p, pack_name, tmp_file);\n \tp->pack_fd = pack_fd;\n \tp->do_not_close = 1;\n \tpack_file = sha1fd(pack_fd, p->pack_name);\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278649","messageId":"20160219112454.GN9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 14/21] fetch-pack: simplify add_sought_entry","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:24:55Z","receivedAt":"2016-02-19T11:24:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We have two variants of this function, one that takes a\nstring and one that takes a ptr/len combo. But we only call\nthe latter with the length of a NUL-terminated string, so\nour first simplification is to drop it in favor of the\nstring variant.\n\nSince we know we have a string, we can also replace the\nmanual memory computation with a call to alloc_ref().\n\nFurthermore, we can rely on get_oid_hex() to complain if it\nhits the end of the string. That means we can simplify the\ncheck for \"<sha1> <ref>\" versus just \"<ref>\". Rather than\nmanage the ptr/len pair, we can just bump the start of our\nstring forward. The original code over-allocated based on\nthe original \"namelen\" (which wasn't _wrong_, but was simply\nwasteful and confusing).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/fetch-pack.c | 27 +++++++++------------------\n 1 file changed, 9 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 9b2a514..79a611f 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -10,33 +10,24 @@ static const char fetch_pack_usage[] =\n \"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] \"\n \"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]\";\n \n-static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,\n-\t\t\t\t const char *name, int namelen)\n+static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n+\t\t\t     const char *name)\n {\n-\tstruct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);\n+\tstruct ref *ref;\n \tstruct object_id oid;\n-\tconst int chunksz = GIT_SHA1_HEXSZ + 1;\n \n-\tif (namelen > chunksz && name[chunksz - 1] == ' ' &&\n-\t\t!get_oid_hex(name, &oid)) {\n-\t\toidcpy(&ref->old_oid, &oid);\n-\t\tname += chunksz;\n-\t\tnamelen -= chunksz;\n-\t}\n+\tif (!get_oid_hex(name, &oid) && name[GIT_SHA1_HEXSZ] == ' ')\n+\t\tname += GIT_SHA1_HEXSZ + 1;\n+\telse\n+\t\toidclr(&oid);\n \n-\tmemcpy(ref->name, name, namelen);\n-\tref->name[namelen] = '\\0';\n+\tref = alloc_ref(name);\n+\toidcpy(&ref->old_oid, &oid);\n \t(*nr)++;\n \tALLOC_GROW(*sought, *nr, *alloc);\n \t(*sought)[*nr - 1] = ref;\n }\n \n-static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n-\t\t\t     const char *string)\n-{\n-\tadd_sought_entry_mem(sought, nr, alloc, string, strlen(string));\n-}\n-\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, ret;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278652","messageId":"20160219112458.GO9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 15/21] test-path-utils: fix normalize_path_copy output buffer size","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:24:59Z","receivedAt":"2016-02-19T11:24:59Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The normalize_path_copy function needs an output buffer that\nis at least as long as its input (it may shrink the path,\nbut never expand it). However, this test program feeds it\nstatic PATH_MAX-sized buffers, which have no relation to the\ninput size.\n\nIn the normalize_ceiling_entry case, we do at least check\nthe size against PATH_MAX and die(), but that case is even\nmore convoluted. We normalize into a fixed-size buffer, free\nthe original, and then replace it with a strdup'd copy of\nthe result. But normalize_path_copy explicitly allows\nnormalizing in-place, so we can simply do that.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n test-path-utils.c | 15 ++++-----------\n 1 file changed, 4 insertions(+), 11 deletions(-)\n\ndiff --git a/test-path-utils.c b/test-path-utils.c\nindex 6232dfe..ba805b3 100644\n--- a/test-path-utils.c\n+++ b/test-path-utils.c\n@@ -8,21 +8,14 @@\n  */\n static int normalize_ceiling_entry(struct string_list_item *item, void *unused)\n {\n-\tconst char *ceil = item->string;\n-\tint len = strlen(ceil);\n-\tchar buf[PATH_MAX+1];\n+\tchar *ceil = item->string;\n \n-\tif (len == 0)\n+\tif (!*ceil)\n \t\tdie(\"Empty path is not supported\");\n-\tif (len > PATH_MAX)\n-\t\tdie(\"Path \\\"%s\\\" is too long\", ceil);\n \tif (!is_absolute_path(ceil))\n \t\tdie(\"Path \\\"%s\\\" is not absolute\", ceil);\n-\tif (normalize_path_copy(buf, ceil) < 0)\n+\tif (normalize_path_copy(ceil, ceil) < 0)\n \t\tdie(\"Path \\\"%s\\\" could not be normalized\", ceil);\n-\tlen = strlen(buf);\n-\tfree(item->string);\n-\titem->string = xstrdup(buf);\n \treturn 1;\n }\n \n@@ -166,7 +159,7 @@ static struct test_data dirname_data[] = {\n int main(int argc, char **argv)\n {\n \tif (argc == 3 && !strcmp(argv[1], \"normalize_path_copy\")) {\n-\t\tchar *buf = xmalloc(PATH_MAX + 1);\n+\t\tchar *buf = xmallocz(strlen(argv[2]));\n \t\tint rv = normalize_path_copy(buf, argv[2]);\n \t\tif (rv)\n \t\t\tbuf = \"++failed++\";\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278653","messageId":"20160219112510.GP9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 16/21] sequencer: simplify memory allocation of get_message","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:25:10Z","receivedAt":"2016-02-19T11:25:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"For a commit with sha1 \"1234abcd\" and subject \"foo\", this\nfunction produces a struct with three strings:\n\n 1. \"foo\"\n\n 2. \"1234abcd... foo\"\n\n 3. \"parent of 1234abcd... foo\"\n\nIt takes advantage of the fact that these strings are\nsubsets of each other, and allocates only _one_ string, with\npointers into the various parts. Unfortunately, this makes\nthe string allocation complicated and hard to follow.\n\nSince we keep only one of these in memory at a time, we can\nafford to simply allocate three strings. This lets us build\non tools like xstrfmt and avoid manual computation.\n\nWhile we're here, we can also drop the ad-hoc\nreimplementation of get_git_commit_encoding(), and simply\ncall that function.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n sequencer.c | 29 ++++++++++-------------------\n 1 file changed, 10 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8048786..e66f2fe 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -124,42 +124,33 @@ static const char *action_name(const struct replay_opts *opts)\n \n struct commit_message {\n \tchar *parent_label;\n-\tconst char *label;\n-\tconst char *subject;\n+\tchar *label;\n+\tchar *subject;\n \tconst char *message;\n };\n \n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n-\tint abbrev_len, subject_len;\n-\tchar *q;\n-\n-\tif (!git_commit_encoding)\n-\t\tgit_commit_encoding = \"UTF-8\";\n+\tint subject_len;\n \n-\tout->message = logmsg_reencode(commit, NULL, git_commit_encoding);\n+\tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n \tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n-\tabbrev_len = strlen(abbrev);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n-\tout->parent_label = xmalloc(strlen(\"parent of \") + abbrev_len +\n-\t\t\t      strlen(\"... \") + subject_len + 1);\n-\tq = out->parent_label;\n-\tq = mempcpy(q, \"parent of \", strlen(\"parent of \"));\n-\tout->label = q;\n-\tq = mempcpy(q, abbrev, abbrev_len);\n-\tq = mempcpy(q, \"... \", strlen(\"... \"));\n-\tout->subject = q;\n-\tq = mempcpy(q, subject, subject_len);\n-\t*q = '\\0';\n+\tout->subject = xmemdupz(subject, subject_len);\n+\tout->label = xstrfmt(\"%s... %s\", abbrev, out->subject);\n+\tout->parent_label = xstrfmt(\"parent of %s\", out->label);\n+\n \treturn 0;\n }\n \n static void free_message(struct commit *commit, struct commit_message *msg)\n {\n \tfree(msg->parent_label);\n+\tfree(msg->label);\n+\tfree(msg->subject);\n \tunuse_commit_buffer(commit, msg->message);\n }\n \n-- \n2.7.1.577.gfed91b8\n"},{"id":"278654","messageId":"20160219112514.GQ9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 17/21] git-compat-util: drop mempcpy compat code","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:25:15Z","receivedAt":"2016-02-19T11:25:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There are no callers of this left, as the last one was\ndropped in the previous patch. And there are not likely to\nbe new ones, as the function has been around since 2010\nwithout gaining any new callers.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 9 ---------\n 1 file changed, 9 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex e71e615..8f0e76b 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -681,7 +681,6 @@ extern int git_vsnprintf(char *str, size_t maxsize,\n #ifdef __GLIBC_PREREQ\n #if __GLIBC_PREREQ(2, 1)\n #define HAVE_STRCHRNUL\n-#define HAVE_MEMPCPY\n #endif\n #endif\n \n@@ -695,14 +694,6 @@ static inline char *gitstrchrnul(const char *s, int c)\n }\n #endif\n \n-#ifndef HAVE_MEMPCPY\n-#define mempcpy gitmempcpy\n-static inline void *gitmempcpy(void *dest, const void *src, size_t n)\n-{\n-\treturn (char *)memcpy(dest, src, n) + n;\n-}\n-#endif\n-\n #ifdef NO_INET_PTON\n int inet_pton(int af, const char *src, void *dst);\n #endif\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278656","messageId":"20160219112518.GR9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 18/21] transport_anonymize_url: use xstrfmt","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:25:18Z","receivedAt":"2016-02-19T11:25:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This function uses xcalloc and two memcpy calls to\nconcatenate two strings. We can do this as an xstrfmt\none-liner, and then it is more clear that we are allocating\nthe correct amount of memory.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n transport.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex 3b4e644..ac857a9 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1021,7 +1021,7 @@ int transport_disconnect(struct transport *transport)\n  */\n char *transport_anonymize_url(const char *url)\n {\n-\tchar *anon_url, *scheme_prefix, *anon_part;\n+\tchar *scheme_prefix, *anon_part;\n \tsize_t anon_len, prefix_len = 0;\n \n \tanon_part = strchr(url, '@');\n@@ -1055,10 +1055,8 @@ char *transport_anonymize_url(const char *url)\n \t\t\tgoto literal_copy;\n \t\tprefix_len = scheme_prefix - url + 3;\n \t}\n-\tanon_url = xcalloc(1, 1 + prefix_len + anon_len);\n-\tmemcpy(anon_url, url, prefix_len);\n-\tmemcpy(anon_url + prefix_len, anon_part, anon_len);\n-\treturn anon_url;\n+\treturn xstrfmt(\"%.*s%.*s\", (int)prefix_len, url,\n+\t\t       (int)anon_len, anon_part);\n literal_copy:\n \treturn xstrdup(url);\n }\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278655","messageId":"20160219112523.GS9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 19/21] diff_populate_gitlink: use a strbuf","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:25:23Z","receivedAt":"2016-02-19T11:25:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We allocate 100 bytes to hold the \"Submodule commit ...\"\ntext. This is enough, but it's not immediately obvious that\nthis is the case, and we have to repeat the magic 100 twice.\n\nWe could get away with xstrfmt here, but we want to know the\nsize, as well, so let's use a real strbuf. And while we're\nhere, we can clean up the logic around size_only. It\ncurrently sets and clears the \"data\" field pointlessly, and\nleaves the \"should_free\" flag on even after we have cleared\nthe data.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 27d14a7..a70ec6e 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2704,21 +2704,21 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \n static int diff_populate_gitlink(struct diff_filespec *s, int size_only)\n {\n-\tint len;\n-\tchar *data = xmalloc(100), *dirty = \"\";\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tchar *dirty = \"\";\n \n \t/* Are we looking at the work tree? */\n \tif (s->dirty_submodule)\n \t\tdirty = \"-dirty\";\n \n-\tlen = snprintf(data, 100,\n-\t\t       \"Subproject commit %s%s\\n\", sha1_to_hex(s->sha1), dirty);\n-\ts->data = data;\n-\ts->size = len;\n-\ts->should_free = 1;\n+\tstrbuf_addf(&buf, \"Subproject commit %s%s\\n\", sha1_to_hex(s->sha1), dirty);\n+\ts->size = buf.len;\n \tif (size_only) {\n \t\ts->data = NULL;\n-\t\tfree(data);\n+\t\tstrbuf_release(&buf);\n+\t} else {\n+\t\ts->data = strbuf_detach(&buf, NULL);\n+\t\ts->should_free = 1;\n \t}\n \treturn 0;\n }\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278657","messageId":"20160219112529.GT9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 20/21] convert ewah/bitmap code to use xmalloc","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:25:29Z","receivedAt":"2016-02-19T11:25:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This code was originally written with the idea that it could\nbe spun off into its own ewah library, and uses the\noverrideable ewah_malloc to do allocations.\n\nWe plug in xmalloc as our ewah_malloc, of course. But over\nthe years the ewah code itself has become more entangled\nwith git, and the return value of many ewah_malloc sites is\nnot checked.\n\nLet's just drop the level of indirection and use xmalloc and\nfriends directly. This saves a few lines, and will let us\nadapt these sites to our more advanced malloc helpers.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ewah/bitmap.c      | 12 ++++++------\n ewah/ewah_bitmap.c |  9 +++------\n ewah/ewah_io.c     | 10 ++--------\n ewah/ewok.h        | 10 ----------\n 4 files changed, 11 insertions(+), 30 deletions(-)\n\ndiff --git a/ewah/bitmap.c b/ewah/bitmap.c\nindex 47ad674..c88daa0 100644\n--- a/ewah/bitmap.c\n+++ b/ewah/bitmap.c\n@@ -25,8 +25,8 @@\n \n struct bitmap *bitmap_new(void)\n {\n-\tstruct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap));\n-\tbitmap->words = ewah_calloc(32, sizeof(eword_t));\n+\tstruct bitmap *bitmap = xmalloc(sizeof(struct bitmap));\n+\tbitmap->words = xcalloc(32, sizeof(eword_t));\n \tbitmap->word_alloc = 32;\n \treturn bitmap;\n }\n@@ -38,8 +38,8 @@ void bitmap_set(struct bitmap *self, size_t pos)\n \tif (block >= self->word_alloc) {\n \t\tsize_t old_size = self->word_alloc;\n \t\tself->word_alloc = block * 2;\n-\t\tself->words = ewah_realloc(self->words,\n-\t\t\tself->word_alloc * sizeof(eword_t));\n+\t\tself->words = xrealloc(self->words,\n+\t\t\t\t      self->word_alloc * sizeof(eword_t));\n \n \t\tmemset(self->words + old_size, 0x0,\n \t\t\t(self->word_alloc - old_size) * sizeof(eword_t));\n@@ -102,7 +102,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)\n \twhile (ewah_iterator_next(&blowup, &it)) {\n \t\tif (i >= bitmap->word_alloc) {\n \t\t\tbitmap->word_alloc *= 1.5;\n-\t\t\tbitmap->words = ewah_realloc(\n+\t\t\tbitmap->words = xrealloc(\n \t\t\t\tbitmap->words, bitmap->word_alloc * sizeof(eword_t));\n \t\t}\n \n@@ -134,7 +134,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)\n \n \tif (self->word_alloc < other_final) {\n \t\tself->word_alloc = other_final;\n-\t\tself->words = ewah_realloc(self->words,\n+\t\tself->words = xrealloc(self->words,\n \t\t\tself->word_alloc * sizeof(eword_t));\n \t\tmemset(self->words + original_size, 0x0,\n \t\t\t(self->word_alloc - original_size) * sizeof(eword_t));\ndiff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c\nindex b522437..fcd465e 100644\n--- a/ewah/ewah_bitmap.c\n+++ b/ewah/ewah_bitmap.c\n@@ -39,7 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)\n \t\treturn;\n \n \tself->alloc_size = new_size;\n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \tself->rlw = self->buffer + (rlw_offset / sizeof(eword_t));\n }\n@@ -282,11 +282,8 @@ struct ewah_bitmap *ewah_new(void)\n {\n \tstruct ewah_bitmap *self;\n \n-\tself = ewah_malloc(sizeof(struct ewah_bitmap));\n-\tif (self == NULL)\n-\t\treturn NULL;\n-\n-\tself->buffer = ewah_malloc(32 * sizeof(eword_t));\n+\tself = xmalloc(sizeof(struct ewah_bitmap));\n+\tself->buffer = xmalloc(32 * sizeof(eword_t));\n \tself->alloc_size = 32;\n \n \tewah_clear(self);\ndiff --git a/ewah/ewah_io.c b/ewah/ewah_io.c\nindex 43481b9..4acff97 100644\n--- a/ewah/ewah_io.c\n+++ b/ewah/ewah_io.c\n@@ -134,12 +134,9 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)\n \tself->buffer_size = self->alloc_size = get_be32(ptr);\n \tptr += sizeof(uint32_t);\n \n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \n-\tif (!self->buffer)\n-\t\treturn -1;\n-\n \t/*\n \t * Copy the raw data for the bitmap as a whole chunk;\n \t * if we're in a little-endian platform, we'll perform\n@@ -180,12 +177,9 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)\n \t\treturn -1;\n \n \tself->buffer_size = self->alloc_size = (size_t)ntohl(word_count);\n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \n-\tif (!self->buffer)\n-\t\treturn -1;\n-\n \t/** 64 bit x N -- compressed words */\n \tbuffer = self->buffer;\n \twords_left = self->buffer_size;\ndiff --git a/ewah/ewok.h b/ewah/ewok.h\nindex 6e2c5e1..269a1a8 100644\n--- a/ewah/ewok.h\n+++ b/ewah/ewok.h\n@@ -20,16 +20,6 @@\n #ifndef __EWOK_BITMAP_H__\n #define __EWOK_BITMAP_H__\n \n-#ifndef ewah_malloc\n-#\tdefine ewah_malloc xmalloc\n-#endif\n-#ifndef ewah_realloc\n-#\tdefine ewah_realloc xrealloc\n-#endif\n-#ifndef ewah_calloc\n-#\tdefine ewah_calloc xcalloc\n-#endif\n-\n struct strbuf;\n typedef uint64_t eword_t;\n #define BITS_IN_EWORD (sizeof(eword_t) * 8)\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278658","messageId":"20160219112533.GU9319@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH 21/21] ewah: convert to REALLOC_ARRAY, etc","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T11:25:33Z","receivedAt":"2016-02-19T11:25:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Now that we're built around xmalloc and friends, we can use\nhelpers like REALLOC_ARRAY, ALLOC_GROW, and so on to make\nthe code shorter and protect against integer overflow.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ewah/bitmap.c      | 16 ++++------------\n ewah/ewah_bitmap.c |  5 ++---\n ewah/ewah_io.c     |  6 ++----\n 3 files changed, 8 insertions(+), 19 deletions(-)\n\ndiff --git a/ewah/bitmap.c b/ewah/bitmap.c\nindex c88daa0..7103cee 100644\n--- a/ewah/bitmap.c\n+++ b/ewah/bitmap.c\n@@ -17,7 +17,7 @@\n  * along with this program; if not, write to the Free Software\n  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n  */\n-#include \"git-compat-util.h\"\n+#include \"cache.h\"\n #include \"ewok.h\"\n \n #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))\n@@ -38,9 +38,7 @@ void bitmap_set(struct bitmap *self, size_t pos)\n \tif (block >= self->word_alloc) {\n \t\tsize_t old_size = self->word_alloc;\n \t\tself->word_alloc = block * 2;\n-\t\tself->words = xrealloc(self->words,\n-\t\t\t\t      self->word_alloc * sizeof(eword_t));\n-\n+\t\tREALLOC_ARRAY(self->words, self->word_alloc);\n \t\tmemset(self->words + old_size, 0x0,\n \t\t\t(self->word_alloc - old_size) * sizeof(eword_t));\n \t}\n@@ -100,12 +98,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)\n \tewah_iterator_init(&it, ewah);\n \n \twhile (ewah_iterator_next(&blowup, &it)) {\n-\t\tif (i >= bitmap->word_alloc) {\n-\t\t\tbitmap->word_alloc *= 1.5;\n-\t\t\tbitmap->words = xrealloc(\n-\t\t\t\tbitmap->words, bitmap->word_alloc * sizeof(eword_t));\n-\t\t}\n-\n+\t\tALLOC_GROW(bitmap->words, i + 1, bitmap->word_alloc);\n \t\tbitmap->words[i++] = blowup;\n \t}\n \n@@ -134,8 +127,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)\n \n \tif (self->word_alloc < other_final) {\n \t\tself->word_alloc = other_final;\n-\t\tself->words = xrealloc(self->words,\n-\t\t\tself->word_alloc * sizeof(eword_t));\n+\t\tREALLOC_ARRAY(self->words, self->word_alloc);\n \t\tmemset(self->words + original_size, 0x0,\n \t\t\t(self->word_alloc - original_size) * sizeof(eword_t));\n \t}\ndiff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c\nindex fcd465e..2dc9c82 100644\n--- a/ewah/ewah_bitmap.c\n+++ b/ewah/ewah_bitmap.c\n@@ -39,8 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)\n \t\treturn;\n \n \tself->alloc_size = new_size;\n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \tself->rlw = self->buffer + (rlw_offset / sizeof(eword_t));\n }\n \n@@ -283,8 +282,8 @@ struct ewah_bitmap *ewah_new(void)\n \tstruct ewah_bitmap *self;\n \n \tself = xmalloc(sizeof(struct ewah_bitmap));\n-\tself->buffer = xmalloc(32 * sizeof(eword_t));\n \tself->alloc_size = 32;\n+\tALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \tewah_clear(self);\n \treturn self;\ndiff --git a/ewah/ewah_io.c b/ewah/ewah_io.c\nindex 4acff97..61f6a43 100644\n--- a/ewah/ewah_io.c\n+++ b/ewah/ewah_io.c\n@@ -134,8 +134,7 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)\n \tself->buffer_size = self->alloc_size = get_be32(ptr);\n \tptr += sizeof(uint32_t);\n \n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \t/*\n \t * Copy the raw data for the bitmap as a whole chunk;\n@@ -177,8 +176,7 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)\n \t\treturn -1;\n \n \tself->buffer_size = self->alloc_size = (size_t)ntohl(word_count);\n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \t/** 64 bit x N -- compressed words */\n \tbuffer = self->buffer;\n-- \n2.7.1.577.gfed91b8\n"},{"id":"278677","messageId":"xmqqio1kd20p.fsf@gitster.mtv.corp.google.com","threadId":"41418","inReplyTo":"20160219112449.GM9319@sigill.intra.peff.net","subject":"Re: [PATCH 13/21] fast-import: simplify allocation in start_packfile","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-02-19T17:48:54Z","receivedAt":"2016-02-19T17:48:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> This function allocate a packed_git flex-array, and adds a\n\ns/allocate/&s/, right?\n\n> mysterious 2 bytes to the length of the pack_name field. One\n> is for the trailing NUL, but the other has no purpose. This\n> is probably cargo-culted from add_packed_git, which gets the\n> \".idx\" path and needed to allocate enough space to hold the\n> matching \".pack\" (though since 48bcc1c, we calculate the\n> size there differently).\n>\n> This site, however, is using the raw path of a tempfile, and\n> does not need the extra byte. We can just replace the\n> allocation with FLEX_ALLOC_STR, which handles the allocation\n> and the NUL for us.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>  fast-import.c | 5 +----\n>  1 file changed, 1 insertion(+), 4 deletions(-)\n>\n> diff --git a/fast-import.c b/fast-import.c\n> index 3053bb8..9fc7093 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -865,15 +865,12 @@ static void start_packfile(void)\n>  {\n>  \tstatic char tmp_file[PATH_MAX];\n>  \tstruct packed_git *p;\n> -\tint namelen;\n>  \tstruct pack_header hdr;\n>  \tint pack_fd;\n>  \n>  \tpack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),\n>  \t\t\t      \"pack/tmp_pack_XXXXXX\");\n> -\tnamelen = strlen(tmp_file) + 2;\n> -\tp = xcalloc(1, sizeof(*p) + namelen);\n> -\txsnprintf(p->pack_name, namelen, \"%s\", tmp_file);\n> +\tFLEX_ALLOC_STR(p, pack_name, tmp_file);\n>  \tp->pack_fd = pack_fd;\n>  \tp->do_not_close = 1;\n>  \tpack_file = sha1fd(pack_fd, p->pack_name);\n"},{"id":"278696","messageId":"20160219191204.GC777@sigill.intra.peff.net","threadId":"41418","inReplyTo":"xmqqio1kd20p.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 13/21] fast-import: simplify allocation in start_packfile","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-19T19:12:04Z","receivedAt":"2016-02-19T19:12:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Feb 19, 2016 at 09:48:54AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > This function allocate a packed_git flex-array, and adds a\n> \n> s/allocate/&s/, right?\n\nYes, thanks.\n\n-Peff\n"},{"id":"278718","messageId":"CAPig+cQsFAd4WEoHP-eoz9HCcVzY2uVcDH+_rvkoNjSe-Fg0oA@mail.gmail.com","threadId":"41418","inReplyTo":"20160219112324.GF9319@sigill.intra.peff.net","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-20T08:07:00Z","receivedAt":"2016-02-20T08:07:00Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Feb 19, 2016 at 6:23 AM, Jeff King <peff@peff.net> wrote:\n> There are many manual argv allocations that predate the\n> argv_array API. Switching to that API brings a few\n> advantages:\n>\n>   1. We no longer have to manually compute the correct final\n>      array size (so it's one less thing we can screw up).\n>\n>   2. In many cases we had to make a separate pass to count,\n>      then allocate, then fill in the array. Now we can do it\n>      in one pass, making the code shorter and easier to\n>      follow.\n>\n>   3. argv_array handles memory ownership for us, making it\n>      more obvious when things should be free()d and and when\n>      not.\n>\n> Most of these cases are pretty straightforward. In some, we\n> switch from \"run_command_v\" to \"run_command\" which lets us\n> directly use the argv_array embedded in \"struct\n> child_process\".\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> diff --git a/line-log.c b/line-log.c\n> @@ -746,23 +747,16 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n>         if (!rev->diffopt.detect_rename) {\n> -               int i, count = 0;\n> -               struct line_log_data *r = range;\n> -               const char **paths;\n> -               while (r) {\n> -                       count++;\n> -                       r = r->next;\n> -               }\n> -               paths = xmalloc((count+1)*sizeof(char *));\n> -               r = range;\n> -               for (i = 0; i < count; i++) {\n> -                       paths[i] = xstrdup(r->path);\n> -                       r = r->next;\n> -               }\n> -               paths[count] = NULL;\n> +               struct line_log_data *r;\n> +               struct argv_array paths = ARGV_ARRAY_INIT;\n> +\n> +               for (r = range; r; r = r->next)\n> +                       argv_array_push(&paths, r->path);\n>                 parse_pathspec(&rev->diffopt.pathspec, 0,\n> -                              PATHSPEC_PREFER_FULL, \"\", paths);\n> -               free(paths);\n> +                              PATHSPEC_PREFER_FULL, \"\", paths.argv);\n> +               /* argv strings are now owned by pathspec */\n> +               paths.argc = 0;\n> +               argv_array_clear(&paths);\n\nThis overly intimate knowledge of the internal implementation of\nargv_array_clear() is rather ugly.\n\n>         }\n>  }\n"},{"id":"278719","messageId":"20160220081010.GA16722@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cQsFAd4WEoHP-eoz9HCcVzY2uVcDH+_rvkoNjSe-Fg0oA@mail.gmail.com","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-20T08:10:11Z","receivedAt":"2016-02-20T08:10:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote:\n\n> > diff --git a/line-log.c b/line-log.c\n> > @@ -746,23 +747,16 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n> >         if (!rev->diffopt.detect_rename) {\n> > -               int i, count = 0;\n> > -               struct line_log_data *r = range;\n> > -               const char **paths;\n> > -               while (r) {\n> > -                       count++;\n> > -                       r = r->next;\n> > -               }\n> > -               paths = xmalloc((count+1)*sizeof(char *));\n> > -               r = range;\n> > -               for (i = 0; i < count; i++) {\n> > -                       paths[i] = xstrdup(r->path);\n> > -                       r = r->next;\n> > -               }\n> > -               paths[count] = NULL;\n> > +               struct line_log_data *r;\n> > +               struct argv_array paths = ARGV_ARRAY_INIT;\n> > +\n> > +               for (r = range; r; r = r->next)\n> > +                       argv_array_push(&paths, r->path);\n> >                 parse_pathspec(&rev->diffopt.pathspec, 0,\n> > -                              PATHSPEC_PREFER_FULL, \"\", paths);\n> > -               free(paths);\n> > +                              PATHSPEC_PREFER_FULL, \"\", paths.argv);\n> > +               /* argv strings are now owned by pathspec */\n> > +               paths.argc = 0;\n> > +               argv_array_clear(&paths);\n> \n> This overly intimate knowledge of the internal implementation of\n> argv_array_clear() is rather ugly.\n\nYep, I agree. Suggestions?\n\nWe can just leak the array of \"char *\". This function is called only\nonce per program invocation, and that's unlikely to change.\n\nI guess we can make an argv_array_detach_strings() function. Or maybe\neven just argv_array_detach() would be less gross, and then this\nfunction could manually free the array but not the strings themselves.\n\n-Peff\n"},{"id":"278721","messageId":"CAPig+cTACku01im72Cd7LxYopwwFaXtKYXkxi53GMrTRyZpFGQ@mail.gmail.com","threadId":"41418","inReplyTo":"20160220081010.GA16722@sigill.intra.peff.net","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-20T08:29:29Z","receivedAt":"2016-02-20T08:29:29Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Feb 20, 2016 at 3:10 AM, Jeff King <peff@peff.net> wrote:\n> On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote:\n>> > +               /* argv strings are now owned by pathspec */\n>> > +               paths.argc = 0;\n>> > +               argv_array_clear(&paths);\n>>\n>> This overly intimate knowledge of the internal implementation of\n>> argv_array_clear() is rather ugly.\n>\n> Yep, I agree. Suggestions?\n>\n> We can just leak the array of \"char *\". This function is called only\n> once per program invocation, and that's unlikely to change.\n>\n> I guess we can make an argv_array_detach_strings() function. Or maybe\n> even just argv_array_detach() would be less gross, and then this\n> function could manually free the array but not the strings themselves.\n\nThe latter is what I was thinking, and I agree that\nargv_array_detach() would be less gross than\nargv_array_detach_strings(), however, it also feels a bit wrong since\nthis sort of ownership transfer is kind of out of scope for\nargv_array.\n\nI wonder if a simple \"dup'ing\" string_list would be more suitable for\nthis case. You'd have to append the NULL item manually with\nstring_list_append_nodup(), and string_list_clear() would then be the\ncorrect way to dispose of the list without intimate knowledge of its\nimplementation and no need for an API extension.\n"},{"id":"278722","messageId":"20160220083426.GA17171@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cTACku01im72Cd7LxYopwwFaXtKYXkxi53GMrTRyZpFGQ@mail.gmail.com","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-20T08:34:26Z","receivedAt":"2016-02-20T08:34:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Feb 20, 2016 at 03:29:29AM -0500, Eric Sunshine wrote:\n\n> On Sat, Feb 20, 2016 at 3:10 AM, Jeff King <peff@peff.net> wrote:\n> > On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote:\n> >> > +               /* argv strings are now owned by pathspec */\n> >> > +               paths.argc = 0;\n> >> > +               argv_array_clear(&paths);\n> >>\n> >> This overly intimate knowledge of the internal implementation of\n> >> argv_array_clear() is rather ugly.\n> >\n> > Yep, I agree. Suggestions?\n> >\n> > We can just leak the array of \"char *\". This function is called only\n> > once per program invocation, and that's unlikely to change.\n> >\n> > I guess we can make an argv_array_detach_strings() function. Or maybe\n> > even just argv_array_detach() would be less gross, and then this\n> > function could manually free the array but not the strings themselves.\n> \n> The latter is what I was thinking, and I agree that\n> argv_array_detach() would be less gross than\n> argv_array_detach_strings(), however, it also feels a bit wrong since\n> this sort of ownership transfer is kind of out of scope for\n> argv_array.\n> \n> I wonder if a simple \"dup'ing\" string_list would be more suitable for\n> this case. You'd have to append the NULL item manually with\n> string_list_append_nodup(), and string_list_clear() would then be the\n> correct way to dispose of the list without intimate knowledge of its\n> implementation and no need for an API extension.\n\nA string_list doesn't just store pointers; it's a struct with a util\nfield. So you can't pass it to things expecting a \"const char **\".\n\nI think argv_array_detach() is the least-bad thing here. It matches\nstrbuf_detach() to say \"you now own the storage\" (as opposed to just\npeeking at argv.argv, which we should do only in a read-only way).\n\n-Peff\n"},{"id":"278723","messageId":"CAPig+cQK15OoNdG0zyCC0eZJ1XeidD7sOU8BggnNN7k=Zi9zdw@mail.gmail.com","threadId":"41418","inReplyTo":"20160220083426.GA17171@sigill.intra.peff.net","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-20T08:39:36Z","receivedAt":"2016-02-20T08:39:36Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Feb 20, 2016 at 3:34 AM, Jeff King <peff@peff.net> wrote:\n> On Sat, Feb 20, 2016 at 03:29:29AM -0500, Eric Sunshine wrote:\n>> On Sat, Feb 20, 2016 at 3:10 AM, Jeff King <peff@peff.net> wrote:\n>> > On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote:\n>> >> > +               /* argv strings are now owned by pathspec */\n>> >> > +               paths.argc = 0;\n>> >> > +               argv_array_clear(&paths);\n>> >>\n>> >> This overly intimate knowledge of the internal implementation of\n>> >> argv_array_clear() is rather ugly.\n>> >\n>> > Yep, I agree. Suggestions?\n>> > [...]\n>> >\n>> > I guess we can make an argv_array_detach_strings() function. Or maybe\n>> > even just argv_array_detach() would be less gross, and then this\n>> > function could manually free the array but not the strings themselves.\n>>\n>> [...]\n>> I wonder if a simple \"dup'ing\" string_list would be more suitable for\n>> this case. You'd have to append the NULL item manually with\n>> string_list_append_nodup(), and string_list_clear() would then be the\n>> correct way to dispose of the list without intimate knowledge of its\n>> implementation and no need for an API extension.\n>\n> A string_list doesn't just store pointers; it's a struct with a util\n> field. So you can't pass it to things expecting a \"const char **\".\n\nYep, I knew that but wasn't thinking straight.\n\n> I think argv_array_detach() is the least-bad thing here. It matches\n> strbuf_detach() to say \"you now own the storage\" (as opposed to just\n> peeking at argv.argv, which we should do only in a read-only way).\n\nI also had made the strbuf_detach() analogy in my response but deleted\nit before sending; I do think it's a reasonable API template to mirror\nvia new argv_array_detach().\n"},{"id":"278725","messageId":"20160220085740.GC17171@sigill.intra.peff.net","threadId":"41418","inReplyTo":"CAPig+cQK15OoNdG0zyCC0eZJ1XeidD7sOU8BggnNN7k=Zi9zdw@mail.gmail.com","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-20T08:57:40Z","receivedAt":"2016-02-20T08:57:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Feb 20, 2016 at 03:39:36AM -0500, Eric Sunshine wrote:\n\n> I also had made the strbuf_detach() analogy in my response but deleted\n> it before sending; I do think it's a reasonable API template to mirror\n> via new argv_array_detach().\n\nThat would look like this, which I think is not too bad (on top of my\nseries for now; I'd do the API function as a separate patch at the\nbeginning and then use it immediately).\n\ndiff --git a/argv-array.c b/argv-array.c\nindex eaed477..5d370fa 100644\n--- a/argv-array.c\n+++ b/argv-array.c\n@@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array)\n \t}\n \targv_array_init(array);\n }\n+\n+const char **argv_array_detach(struct argv_array *array)\n+{\n+\tif (array->argv == empty_argv)\n+\t\treturn xcalloc(1, sizeof(const char *));\n+\telse {\n+\t\tconst char **ret = array->argv;\n+\t\targv_array_init(array);\n+\t\treturn ret;\n+\t}\n+}\ndiff --git a/argv-array.h b/argv-array.h\nindex a2fa0aa..29056e4 100644\n--- a/argv-array.h\n+++ b/argv-array.h\n@@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...);\n void argv_array_pushv(struct argv_array *, const char **);\n void argv_array_pop(struct argv_array *);\n void argv_array_clear(struct argv_array *);\n+const char **argv_array_detach(struct argv_array *);\n \n #endif /* ARGV_ARRAY_H */\ndiff --git a/line-log.c b/line-log.c\nindex fa095b9..bbe31ed 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -748,15 +748,17 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n \n \tif (!rev->diffopt.detect_rename) {\n \t\tstruct line_log_data *r;\n-\t\tstruct argv_array paths = ARGV_ARRAY_INIT;\n+\t\tstruct argv_array array = ARGV_ARRAY_INIT;\n+\t\tconst char **paths;\n \n \t\tfor (r = range; r; r = r->next)\n-\t\t\targv_array_push(&paths, r->path);\n+\t\t\targv_array_push(&array, r->path);\n+\t\tpaths = argv_array_detach(&array);\n+\n \t\tparse_pathspec(&rev->diffopt.pathspec, 0,\n-\t\t\t       PATHSPEC_PREFER_FULL, \"\", paths.argv);\n-\t\t/* argv strings are now owned by pathspec */\n-\t\tpaths.argc = 0;\n-\t\targv_array_clear(&paths);\n+\t\t\t       PATHSPEC_PREFER_FULL, \"\", paths);\n+\t\t/* strings are now owned by pathspec */\n+\t\tfree(paths);\n \t}\n }\n \n"},{"id":"278727","messageId":"CAPig+cSaZv9XHO+BezAJxjh-i_LiBfLxhkKr3u=p8V8zCFnjDw@mail.gmail.com","threadId":"41418","inReplyTo":"20160220085740.GC17171@sigill.intra.peff.net","subject":"Re: [PATCH 06/21] convert manual allocations to argv_array","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-02-20T09:04:41Z","receivedAt":"2016-02-20T09:04:41Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Feb 20, 2016 at 3:57 AM, Jeff King <peff@peff.net> wrote:\n> On Sat, Feb 20, 2016 at 03:39:36AM -0500, Eric Sunshine wrote:\n>> I also had made the strbuf_detach() analogy in my response but deleted\n>> it before sending; I do think it's a reasonable API template to mirror\n>> via new argv_array_detach().\n>\n> That would look like this, which I think is not too bad (on top of my\n> series for now; I'd do the API function as a separate patch at the\n> beginning and then use it immediately).\n\nLooks reasonable.\n\n> diff --git a/argv-array.c b/argv-array.c\n> index eaed477..5d370fa 100644\n> --- a/argv-array.c\n> +++ b/argv-array.c\n> @@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array)\n>         }\n>         argv_array_init(array);\n>  }\n> +\n> +const char **argv_array_detach(struct argv_array *array)\n> +{\n> +       if (array->argv == empty_argv)\n> +               return xcalloc(1, sizeof(const char *));\n> +       else {\n> +               const char **ret = array->argv;\n> +               argv_array_init(array);\n> +               return ret;\n> +       }\n> +}\n> diff --git a/argv-array.h b/argv-array.h\n> index a2fa0aa..29056e4 100644\n> --- a/argv-array.h\n> +++ b/argv-array.h\n> @@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...);\n>  void argv_array_pushv(struct argv_array *, const char **);\n>  void argv_array_pop(struct argv_array *);\n>  void argv_array_clear(struct argv_array *);\n> +const char **argv_array_detach(struct argv_array *);\n>\n>  #endif /* ARGV_ARRAY_H */\n> diff --git a/line-log.c b/line-log.c\n> index fa095b9..bbe31ed 100644\n> --- a/line-log.c\n> +++ b/line-log.c\n> @@ -748,15 +748,17 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n>\n>         if (!rev->diffopt.detect_rename) {\n>                 struct line_log_data *r;\n> -               struct argv_array paths = ARGV_ARRAY_INIT;\n> +               struct argv_array array = ARGV_ARRAY_INIT;\n> +               const char **paths;\n>\n>                 for (r = range; r; r = r->next)\n> -                       argv_array_push(&paths, r->path);\n> +                       argv_array_push(&array, r->path);\n> +               paths = argv_array_detach(&array);\n> +\n>                 parse_pathspec(&rev->diffopt.pathspec, 0,\n> -                              PATHSPEC_PREFER_FULL, \"\", paths.argv);\n> -               /* argv strings are now owned by pathspec */\n> -               paths.argc = 0;\n> -               argv_array_clear(&paths);\n> +                              PATHSPEC_PREFER_FULL, \"\", paths);\n> +               /* strings are now owned by pathspec */\n> +               free(paths);\n>         }\n>  }\n"},{"id":"278739","messageId":"56C8DB50.7070606@web.de","threadId":"41418","inReplyTo":"20160219112200.GD9319@sigill.intra.peff.net","subject":"Re: [PATCH 04/21] harden REALLOC_ARRAY and xcalloc against size_t overflow","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2016-02-20T21:32:00Z","receivedAt":"2016-02-20T21:32:00Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 19.02.2016 um 12:22 schrieb Jeff King:\n> REALLOC_ARRAY inherently involves a multiplication which can\n> overflow size_t, resulting in a much smaller buffer than we\n> think we've allocated. We can easily harden it by using\n> st_mult() to check for overflow.  Likewise, we can add\n> ALLOC_ARRAY to do the same thing for xmalloc calls.\n\nGood idea!\n\n> xcalloc() should already be fine, because it takes the two\n> factors separately, assuming the system calloc actually\n> checks for overflow. However, before we even hit the system\n> calloc(), we do our memory_limit_check, which involves a\n> multiplication. Let's check for overflow ourselves so that\n> this limit cannot be bypassed.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>   git-compat-util.h | 3 ++-\n>   wrapper.c         | 3 +++\n>   2 files changed, 5 insertions(+), 1 deletion(-)\n>\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 0c65033..55c073d 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -779,7 +779,8 @@ extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);\n>   extern char *xgetcwd(void);\n>   extern FILE *fopen_for_writing(const char *path);\n>\n> -#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))\n> +#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n> +#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n\nst_mult(x, y) calls unsigned_mult_overflows(x, y), which divides by x. \nThis division can be done at compile time if x is a constant.  This can \nbe guaranteed for all users of the two macros above by reversing the \narguments of st_mult(), so that sizeof comes first.  Probably not a big \nwin, but why not do it if it's that easy?\n\nOr perhaps a macro like this could help here and in other places which \nuse st_mult with sizeof:\n\n   #define SIZEOF_MULT(x, n) st_mult(sizeof(x), (n))\n\n(I'd call it ARRAY_SIZE, but that name is already taken. :)\n\nRené\n"},{"id":"278795","messageId":"20160221233029.GC4094@sigill.intra.peff.net","threadId":"41418","inReplyTo":"56C8DB50.7070606@web.de","subject":"Re: [PATCH 04/21] harden REALLOC_ARRAY and xcalloc against size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-21T23:30:29Z","receivedAt":"2016-02-21T23:30:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Feb 20, 2016 at 10:32:00PM +0100, René Scharfe wrote:\n\n> >-#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))\n> >+#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult((alloc), sizeof(*(x))))\n> >+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult((alloc), sizeof(*(x))))\n> \n> st_mult(x, y) calls unsigned_mult_overflows(x, y), which divides by x. This\n> division can be done at compile time if x is a constant.  This can be\n> guaranteed for all users of the two macros above by reversing the arguments\n> of st_mult(), so that sizeof comes first.  Probably not a big win, but why\n> not do it if it's that easy?\n\nI doubt it's even measurable, but as you say, it's easy enough to do, so\nwhy not.\n\nIf we really care about optimizing, I suspect that something like:\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 5cbdd2e..1d53328 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -662,10 +662,12 @@ static inline size_t st_add(size_t a, size_t b)\n \n static inline size_t st_mult(size_t a, size_t b)\n {\n-\tif (unsigned_mult_overflows(a, b))\n+\tsize_t ret;\n+\n+\tif (__builtin_mul_overflow(a, b, &ret))\n \t\tdie(\"size_t overflow: %\"PRIuMAX\" * %\"PRIuMAX,\n \t\t    (uintmax_t)a, (uintmax_t)b);\n-\treturn a * b;\n+\treturn ret;\n }\n \n static inline size_t st_sub(size_t a, size_t b)\n\n\nwould do a lot more. But it needs #ifdefs for compilers besides gcc and\nclang.\n\n> Or perhaps a macro like this could help here and in other places which use\n> st_mult with sizeof:\n> \n>   #define SIZEOF_MULT(x, n) st_mult(sizeof(x), (n))\n> \n> (I'd call it ARRAY_SIZE, but that name is already taken. :)\n\nI don't think we need that; we're really only checking allocations,\nwhich means ALLOC_ARRAY() and friends cover all the uses of sizeof (we\nmight still use st_mult() for _another_ part of the computation, but it\nwon't usually be a sizeof then).\n\nWe also may do follow-up multiplications, like:\n\n  ALLOC_ARRAY(foo, nr);\n  memset(foo, 0, nr * sizeof(*foo));\n\nbut I didn't bother doing overflow checks for those. We know that they\nshould be fine if the original allocation was successful (though of\ncourse, just using xcalloc here would be better still).\n\n-Peff\n"},{"id":"278921","messageId":"20160222224059.GA3857@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160219111941.GA31906@sigill.intra.peff.net","subject":"[PATCH v3 0/22] hardening allocations against integer overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:41:00Z","receivedAt":"2016-02-22T22:41:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Feb 19, 2016 at 06:19:41AM -0500, Jeff King wrote:\n\n> Here's a re-roll of jk/tighten-alloc series from:\n> \n>   http://thread.gmane.org/gmane.comp.version-control.git/286253\n\nAnd here's v3. The changes this time (and philosophical rationalization\nof changes I didn't make) are pretty small:\n\n  - flip the order of arguments to st_mult() in ALLOC_ARRAY, et al, to\n    get a probably-irrelevant-but-so-easy-why-not optimization\n\n  - mark new global var in daemon.c as static\n\n  - add argv_array_detach (new patch 6) to avoid gross memory management\n    when converting line-log to use argv_array in the subsequent patch\n\nSo I hope this one is ready for 'next'.  Thanks René, Ramsay, and Eric\nfor reviewing.\n\n  [01/22]: reflog_expire_cfg: NUL-terminate pattern field\n  [02/22]: add helpers for detecting size_t overflow\n  [03/22]: tree-diff: catch integer overflow in combine_diff_path allocation\n  [04/22]: harden REALLOC_ARRAY and xcalloc against size_t overflow\n  [05/22]: add helpers for allocating flex-array structs\n  [06/22]: argv-array: add detach function\n  [07/22]: convert manual allocations to argv_array\n  [08/22]: convert trivial cases to ALLOC_ARRAY\n  [09/22]: use xmallocz to avoid size arithmetic\n  [10/22]: convert trivial cases to FLEX_ARRAY macros\n  [11/22]: use st_add and st_mult for allocation size computation\n  [12/22]: prepare_{git,shell}_cmd: use argv_array\n  [13/22]: write_untracked_extension: use FLEX_ALLOC helper\n  [14/22]: fast-import: simplify allocation in start_packfile\n  [15/22]: fetch-pack: simplify add_sought_entry\n  [16/22]: test-path-utils: fix normalize_path_copy output buffer size\n  [17/22]: sequencer: simplify memory allocation of get_message\n  [18/22]: git-compat-util: drop mempcpy compat code\n  [19/22]: transport_anonymize_url: use xstrfmt\n  [20/22]: diff_populate_gitlink: use a strbuf\n  [21/22]: convert ewah/bitmap code to use xmalloc\n  [22/22]: ewah: convert to REALLOC_ARRAY, etc\n\n-Peff\n"},{"id":"278922","messageId":"20160222224306.GA10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 01/22] reflog_expire_cfg: NUL-terminate pattern field","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:43:06Z","receivedAt":"2016-02-22T22:43:06Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"You can tweak the reflog expiration for a particular subset\nof refs by configuring gc.foo.reflogexpire. We keep a linked\nlist of reflog_expire_cfg structs, each of which holds the\npattern and a \"len\" field for the length of the pattern. The\npattern itself is _not_ NUL-terminated.\n\nHowever, we feed the pattern directly to wildmatch(), which\nexpects a NUL-terminated string, meaning it may keep reading\nrandom junk after our struct.\n\nWe can fix this by allocating an extra byte for the NUL\n(which is already zero because we use xcalloc). Let's also\ndrop the misleading \"len\" field, which is no longer\nnecessary. The existing use of \"len\" can be converted to use\nstrncmp().\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/reflog.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex f39960e..9980731 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -396,7 +396,6 @@ static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n \tunsigned long expire_total;\n \tunsigned long expire_unreachable;\n-\tsize_t len;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -408,13 +407,12 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\treflog_expire_cfg_tail = &reflog_expire_cfg;\n \n \tfor (ent = reflog_expire_cfg; ent; ent = ent->next)\n-\t\tif (ent->len == len &&\n-\t\t    !memcmp(ent->pattern, pattern, len))\n+\t\tif (!strncmp(ent->pattern, pattern, len) &&\n+\t\t    ent->pattern[len] == '\\0')\n \t\t\treturn ent;\n \n-\tent = xcalloc(1, (sizeof(*ent) + len));\n+\tent = xcalloc(1, sizeof(*ent) + len + 1);\n \tmemcpy(ent->pattern, pattern, len);\n-\tent->len = len;\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\n \treturn ent;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278923","messageId":"20160222224310.GB10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 02/22] add helpers for detecting size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:43:11Z","receivedAt":"2016-02-22T22:43:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Performing computations on size_t variables that we feed to\nxmalloc and friends can be dangerous, as an integer overflow\ncan cause us to allocate a much smaller chunk than we\nrealized.\n\nWe already have unsigned_add_overflows(), but let's add\nunsigned_mult_overflows() to that. Furthermore, rather than\nhave each site manually check and die on overflow, we can\nprovide some helpers that will:\n\n  - promote the arguments to size_t, so that we know we are\n    doing our computation in the same size of integer that\n    will ultimately be fed to xmalloc\n\n  - check and die on overflow\n\n  - return the result so that computations can be done in\n    the parameter list of xmalloc.\n\nThese functions are a lot uglier to use than normal\narithmetic operators (you have to do \"st_add(foo, bar)\"\ninstead of \"foo + bar\"). To at least limit the damage, we\nalso provide multi-valued versions. So rather than:\n\n  st_add(st_add(a, b), st_add(c, d));\n\nyou can write:\n\n  st_add4(a, b, c, d);\n\nThis isn't nearly as elegant as a varargs function, but it's\na lot harder to get it wrong. You don't have to remember to\nadd a sentinel value at the end, and the compiler will\ncomplain if you get the number of arguments wrong. This\npatch adds only the numbered variants required to convert\nthe current code base; we can easily add more later if\nneeded.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 34 ++++++++++++++++++++++++++++++++++\n 1 file changed, 34 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 693a336..0c65033 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -96,6 +96,14 @@\n #define unsigned_add_overflows(a, b) \\\n     ((b) > maximum_unsigned_value_of_type(a) - (a))\n \n+/*\n+ * Returns true if the multiplication of \"a\" and \"b\" will\n+ * overflow. The types of \"a\" and \"b\" must match and must be unsigned.\n+ * Note that this macro evaluates \"a\" twice!\n+ */\n+#define unsigned_mult_overflows(a, b) \\\n+    ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))\n+\n #ifdef __GNUC__\n #define TYPEOF(x) (__typeof__(x))\n #else\n@@ -713,6 +721,32 @@ extern void release_pack_memory(size_t);\n typedef void (*try_to_free_t)(size_t);\n extern try_to_free_t set_try_to_free_routine(try_to_free_t);\n \n+static inline size_t st_add(size_t a, size_t b)\n+{\n+\tif (unsigned_add_overflows(a, b))\n+\t\tdie(\"size_t overflow: %\"PRIuMAX\" + %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a + b;\n+}\n+#define st_add3(a,b,c)   st_add((a),st_add((b),(c)))\n+#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))\n+\n+static inline size_t st_mult(size_t a, size_t b)\n+{\n+\tif (unsigned_mult_overflows(a, b))\n+\t\tdie(\"size_t overflow: %\"PRIuMAX\" * %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a * b;\n+}\n+\n+static inline size_t st_sub(size_t a, size_t b)\n+{\n+\tif (a < b)\n+\t\tdie(\"size_t underflow: %\"PRIuMAX\" - %\"PRIuMAX,\n+\t\t    (uintmax_t)a, (uintmax_t)b);\n+\treturn a - b;\n+}\n+\n #ifdef HAVE_ALLOCA_H\n # include <alloca.h>\n # define xalloca(size)      (alloca(size))\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278926","messageId":"20160222224314.GC10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 03/22] tree-diff: catch integer overflow in combine_diff_path allocation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:43:15Z","receivedAt":"2016-02-22T22:43:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"A combine_diff_path struct has two \"flex\" members allocated\nalongside the struct: a string to hold the pathname, and an\narray of parent pointers. We use an \"int\" to compute this,\nmeaning we may easily overflow it if the pathname is\nextremely long.\n\nWe can fix this by using size_t, and checking for overflow\nwith the st_add helper.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.h      | 4 ++--\n tree-diff.c | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/diff.h b/diff.h\nindex 70b2d70..beafbbd 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -222,8 +222,8 @@ struct combine_diff_path {\n \t} parent[FLEX_ARRAY];\n };\n #define combine_diff_path_size(n, l) \\\n-\t(sizeof(struct combine_diff_path) + \\\n-\t sizeof(struct combine_diff_parent) * (n) + (l) + 1)\n+\tst_add4(sizeof(struct combine_diff_path), (l), 1, \\\n+\t\tst_mult(sizeof(struct combine_diff_parent), (n)))\n \n extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t      int dense, struct rev_info *);\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 290a1da..4dda9a1 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -124,8 +124,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \tunsigned mode, const unsigned char *sha1)\n {\n \tstruct combine_diff_path *p;\n-\tint len = base->len + pathlen;\n-\tint alloclen = combine_diff_path_size(nparent, len);\n+\tsize_t len = st_add(base->len, pathlen);\n+\tsize_t alloclen = combine_diff_path_size(nparent, len);\n \n \t/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */\n \tp = last->next;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278925","messageId":"20160222224318.GD10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 04/22] harden REALLOC_ARRAY and xcalloc against size_t overflow","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:43:18Z","receivedAt":"2016-02-22T22:43:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"REALLOC_ARRAY inherently involves a multiplication which can\noverflow size_t, resulting in a much smaller buffer than we\nthink we've allocated. We can easily harden it by using\nst_mult() to check for overflow.  Likewise, we can add\nALLOC_ARRAY to do the same thing for xmalloc calls.\n\nxcalloc() should already be fine, because it takes the two\nfactors separately, assuming the system calloc actually\nchecks for overflow. However, before we even hit the system\ncalloc(), we do our memory_limit_check, which involves a\nmultiplication. Let's check for overflow ourselves so that\nthis limit cannot be bypassed.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 3 ++-\n wrapper.c         | 3 +++\n 2 files changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 0c65033..81f2347 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -779,7 +779,8 @@ extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);\n extern char *xgetcwd(void);\n extern FILE *fopen_for_writing(const char *path);\n \n-#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))\n+#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))\n+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))\n \n static inline char *xstrdup_or_null(const char *str)\n {\ndiff --git a/wrapper.c b/wrapper.c\nindex 29a45d2..9afc1a0 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -152,6 +152,9 @@ void *xcalloc(size_t nmemb, size_t size)\n {\n \tvoid *ret;\n \n+\tif (unsigned_mult_overflows(nmemb, size))\n+\t\tdie(\"data too large to fit into virtual memory space\");\n+\n \tmemory_limit_check(size * nmemb, 0);\n \tret = calloc(nmemb, size);\n \tif (!ret && (!nmemb || !size))\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278924","messageId":"20160222224324.GE10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 05/22] add helpers for allocating flex-array structs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:43:25Z","receivedAt":"2016-02-22T22:43:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Allocating a struct with a flex array is pretty simple in\npractice: you over-allocate the struct, then copy some data\ninto the over-allocation. But it can be a slight pain to\nmake sure you're allocating and copying the right amounts.\n\nThis patch adds a few helpers to turn simple cases of\nflex-array struct allocation into a one-liner that properly\nchecks for overflow. See the embedded documentation for\ndetails.\n\nIdeally we could provide a more flexible version that could\nhandle multiple strings, like:\n\n  FLEX_ALLOC_FMT(ref, name, \"%s%s\", prefix, name);\n\nBut we have to implement this as a macro (because of the\noffset calculation of the flex member), which means we would\nneed all compilers to support variadic macros.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 62 insertions(+)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 81f2347..57ff9fb 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -782,6 +782,68 @@ extern FILE *fopen_for_writing(const char *path);\n #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))\n #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))\n \n+/*\n+ * These functions help you allocate structs with flex arrays, and copy\n+ * the data directly into the array. For example, if you had:\n+ *\n+ *   struct foo {\n+ *     int bar;\n+ *     char name[FLEX_ARRAY];\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_MEM(f, name, src, len);\n+ *\n+ * to allocate a \"foo\" with the contents of \"src\" in the \"name\" field.\n+ * The resulting struct is automatically zero'd, and the flex-array field\n+ * is NUL-terminated (whether the incoming src buffer was or not).\n+ *\n+ * The FLEXPTR_* variants operate on structs that don't use flex-arrays,\n+ * but do want to store a pointer to some extra data in the same allocated\n+ * block. For example, if you have:\n+ *\n+ *   struct foo {\n+ *     char *name;\n+ *     int bar;\n+ *   };\n+ *\n+ * you can do:\n+ *\n+ *   struct foo *f;\n+ *   FLEX_ALLOC_STR(f, name, src);\n+ *\n+ * and \"name\" will point to a block of memory after the struct, which will be\n+ * freed along with the struct (but the pointer can be repointed anywhere).\n+ *\n+ * The *_STR variants accept a string parameter rather than a ptr/len\n+ * combination.\n+ *\n+ * Note that these macros will evaluate the first parameter multiple\n+ * times, and it must be assignable as an lvalue.\n+ */\n+#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \\\n+\t(x) = NULL; /* silence -Wuninitialized for offset calculation */ \\\n+\t(x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \\\n+} while (0)\n+#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \\\n+\t(x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \\\n+\t(x)->ptrname = (void *)((x)+1); \\\n+} while(0)\n+#define FLEX_ALLOC_STR(x, flexname, str) \\\n+\tFLEX_ALLOC_MEM((x), flexname, (str), strlen(str))\n+#define FLEXPTR_ALLOC_STR(x, ptrname, str) \\\n+\tFLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))\n+\n+static inline void *xalloc_flex(size_t base_len, size_t offset,\n+\t\t\t\tconst void *src, size_t src_len)\n+{\n+\tunsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));\n+\tmemcpy(ret + offset, src, src_len);\n+\treturn ret;\n+}\n+\n static inline char *xstrdup_or_null(const char *str)\n {\n \treturn str ? xstrdup(str) : NULL;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278927","messageId":"20160222224414.GF10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 06/22] argv-array: add detach function","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:15Z","receivedAt":"2016-02-22T22:44:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The usual pattern for an argv array is to initialize it,\npush in some strings, and then clear it when done. Very\noccasionally, though, we must do other exotic things with\nthe memory, like freeing the list but keeping the strings.\nLet's provide a detach function so that callers can make use\nof our API to build up the array, and then take ownership of\nit.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n Documentation/technical/api-argv-array.txt |  7 +++++++\n argv-array.c                               | 11 +++++++++++\n argv-array.h                               |  1 +\n 3 files changed, 19 insertions(+)\n\ndiff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt\nindex 8076172..cfc0630 100644\n--- a/Documentation/technical/api-argv-array.txt\n+++ b/Documentation/technical/api-argv-array.txt\n@@ -56,3 +56,10 @@ Functions\n `argv_array_clear`::\n \tFree all memory associated with the array and return it to the\n \tinitial, empty state.\n+\n+`argv_array_detach`::\n+\tDisconnect the `argv` member from the `argv_array` struct and\n+\treturn it. The caller is responsible for freeing the memory used\n+\tby the array, and by the strings it references. After detaching,\n+\tthe `argv_array` is in a reinitialized state and can be pushed\n+\tinto again.\ndiff --git a/argv-array.c b/argv-array.c\nindex eaed477..5d370fa 100644\n--- a/argv-array.c\n+++ b/argv-array.c\n@@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array)\n \t}\n \targv_array_init(array);\n }\n+\n+const char **argv_array_detach(struct argv_array *array)\n+{\n+\tif (array->argv == empty_argv)\n+\t\treturn xcalloc(1, sizeof(const char *));\n+\telse {\n+\t\tconst char **ret = array->argv;\n+\t\targv_array_init(array);\n+\t\treturn ret;\n+\t}\n+}\ndiff --git a/argv-array.h b/argv-array.h\nindex a2fa0aa..29056e4 100644\n--- a/argv-array.h\n+++ b/argv-array.h\n@@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...);\n void argv_array_pushv(struct argv_array *, const char **);\n void argv_array_pop(struct argv_array *);\n void argv_array_clear(struct argv_array *);\n+const char **argv_array_detach(struct argv_array *);\n \n #endif /* ARGV_ARRAY_H */\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278928","messageId":"20160222224421.GG10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 07/22] convert manual allocations to argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:21Z","receivedAt":"2016-02-22T22:44:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There are many manual argv allocations that predate the\nargv_array API. Switching to that API brings a few\nadvantages:\n\n  1. We no longer have to manually compute the correct final\n     array size (so it's one less thing we can screw up).\n\n  2. In many cases we had to make a separate pass to count,\n     then allocate, then fill in the array. Now we can do it\n     in one pass, making the code shorter and easier to\n     follow.\n\n  3. argv_array handles memory ownership for us, making it\n     more obvious when things should be free()d and and when\n     not.\n\nMost of these cases are pretty straightforward. In some, we\nswitch from \"run_command_v\" to \"run_command\" which lets us\ndirectly use the argv_array embedded in \"struct\nchild_process\".\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/grep.c         | 10 +++++-----\n builtin/receive-pack.c | 12 +++---------\n builtin/remote-ext.c   | 26 +++++---------------------\n daemon.c               | 12 +++++-------\n git.c                  | 14 +++++---------\n line-log.c             | 22 +++++++++-------------\n remote-curl.c          | 23 +++++++++++------------\n 7 files changed, 43 insertions(+), 76 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 8c516a9..aa7435f 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -365,17 +365,17 @@ static void append_path(struct grep_opt *opt, const void *data, size_t len)\n static void run_pager(struct grep_opt *opt, const char *prefix)\n {\n \tstruct string_list *path_list = opt->output_priv;\n-\tconst char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));\n+\tstruct child_process child = CHILD_PROCESS_INIT;\n \tint i, status;\n \n \tfor (i = 0; i < path_list->nr; i++)\n-\t\targv[i] = path_list->items[i].string;\n-\targv[path_list->nr] = NULL;\n+\t\targv_array_push(&child.args, path_list->items[i].string);\n+\tchild.dir = prefix;\n+\tchild.use_shell = 1;\n \n-\tstatus = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, prefix, NULL);\n+\tstatus = run_command(&child);\n \tif (status)\n \t\texit(status);\n-\tfree(argv);\n }\n \n static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex f2d6761..932afab 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1031,7 +1031,6 @@ static void run_update_post_hook(struct command *commands)\n {\n \tstruct command *cmd;\n \tint argc;\n-\tconst char **argv;\n \tstruct child_process proc = CHILD_PROCESS_INIT;\n \tconst char *hook;\n \n@@ -1044,21 +1043,16 @@ static void run_update_post_hook(struct command *commands)\n \tif (!argc || !hook)\n \t\treturn;\n \n-\targv = xmalloc(sizeof(*argv) * (2 + argc));\n-\targv[0] = hook;\n-\n-\tfor (argc = 1, cmd = commands; cmd; cmd = cmd->next) {\n+\targv_array_push(&proc.args, hook);\n+\tfor (cmd = commands; cmd; cmd = cmd->next) {\n \t\tif (cmd->error_string || cmd->did_not_exist)\n \t\t\tcontinue;\n-\t\targv[argc] = xstrdup(cmd->ref_name);\n-\t\targc++;\n+\t\targv_array_push(&proc.args, cmd->ref_name);\n \t}\n-\targv[argc] = NULL;\n \n \tproc.no_stdin = 1;\n \tproc.stdout_to_stderr = 1;\n \tproc.err = use_sideband ? -1 : 0;\n-\tproc.argv = argv;\n \n \tif (!start_command(&proc)) {\n \t\tif (use_sideband)\ndiff --git a/builtin/remote-ext.c b/builtin/remote-ext.c\nindex e3cd25d..7457c74 100644\n--- a/builtin/remote-ext.c\n+++ b/builtin/remote-ext.c\n@@ -114,30 +114,14 @@ static char *strip_escapes(const char *str, const char *service,\n \t}\n }\n \n-/* Should be enough... */\n-#define MAXARGUMENTS 256\n-\n-static const char **parse_argv(const char *arg, const char *service)\n+static void parse_argv(struct argv_array *out, const char *arg, const char *service)\n {\n-\tint arguments = 0;\n-\tint i;\n-\tconst char **ret;\n-\tchar *temparray[MAXARGUMENTS + 1];\n-\n \twhile (*arg) {\n-\t\tchar *expanded;\n-\t\tif (arguments == MAXARGUMENTS)\n-\t\t\tdie(\"remote-ext command has too many arguments\");\n-\t\texpanded = strip_escapes(arg, service, &arg);\n+\t\tchar *expanded = strip_escapes(arg, service, &arg);\n \t\tif (expanded)\n-\t\t\ttemparray[arguments++] = expanded;\n+\t\t\targv_array_push(out, expanded);\n+\t\tfree(expanded);\n \t}\n-\n-\tret = xmalloc((arguments + 1) * sizeof(char *));\n-\tfor (i = 0; i < arguments; i++)\n-\t\tret[i] = temparray[i];\n-\tret[arguments] = NULL;\n-\treturn ret;\n }\n \n static void send_git_request(int stdin_fd, const char *serv, const char *repo,\n@@ -158,7 +142,7 @@ static int run_child(const char *arg, const char *service)\n \tchild.in = -1;\n \tchild.out = -1;\n \tchild.err = 0;\n-\tchild.argv = parse_argv(arg, service);\n+\tparse_argv(&child.args, arg, service);\n \n \tif (start_command(&child) < 0)\n \t\tdie(\"Can't run specified command\");\ndiff --git a/daemon.c b/daemon.c\nindex 46b411c..8d45c33 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -808,7 +808,7 @@ static void check_dead_children(void)\n \t\t\tcradle = &blanket->next;\n }\n \n-static char **cld_argv;\n+static struct argv_array cld_argv = ARGV_ARRAY_INIT;\n static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)\n {\n \tstruct child_process cld = CHILD_PROCESS_INIT;\n@@ -842,7 +842,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)\n #endif\n \t}\n \n-\tcld.argv = (const char **)cld_argv;\n+\tcld.argv = cld_argv.argv;\n \tcld.in = incoming;\n \tcld.out = dup(incoming);\n \n@@ -1374,12 +1374,10 @@ int main(int argc, char **argv)\n \t\twrite_file(pid_file, \"%\"PRIuMAX, (uintmax_t) getpid());\n \n \t/* prepare argv for serving-processes */\n-\tcld_argv = xmalloc(sizeof (char *) * (argc + 2));\n-\tcld_argv[0] = argv[0];\t/* git-daemon */\n-\tcld_argv[1] = \"--serve\";\n+\targv_array_push(&cld_argv, argv[0]); /* git-daemon */\n+\targv_array_push(&cld_argv, \"--serve\");\n \tfor (i = 1; i < argc; ++i)\n-\t\tcld_argv[i+1] = argv[i];\n-\tcld_argv[argc+1] = NULL;\n+\t\targv_array_push(&cld_argv, argv[i]);\n \n \treturn serve(&listen_addr, listen_port, cred);\n }\ndiff --git a/git.c b/git.c\nindex 6c64c94..087ad31 100644\n--- a/git.c\n+++ b/git.c\n@@ -247,20 +247,16 @@ static int handle_alias(int *argcp, const char ***argv)\n \talias_string = alias_lookup(alias_command);\n \tif (alias_string) {\n \t\tif (alias_string[0] == '!') {\n-\t\t\tconst char **alias_argv;\n-\t\t\tint argc = *argcp, i;\n+\t\t\tstruct child_process child = CHILD_PROCESS_INIT;\n \n \t\t\tcommit_pager_choice();\n \t\t\trestore_env(1);\n \n-\t\t\t/* build alias_argv */\n-\t\t\talias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));\n-\t\t\talias_argv[0] = alias_string + 1;\n-\t\t\tfor (i = 1; i < argc; ++i)\n-\t\t\t\talias_argv[i] = (*argv)[i];\n-\t\t\talias_argv[argc] = NULL;\n+\t\t\tchild.use_shell = 1;\n+\t\t\targv_array_push(&child.args, alias_string + 1);\n+\t\t\targv_array_pushv(&child.args, (*argv) + 1);\n \n-\t\t\tret = run_command_v_opt(alias_argv, RUN_USING_SHELL);\n+\t\t\tret = run_command(&child);\n \t\t\tif (ret >= 0)   /* normal exit */\n \t\t\t\texit(ret);\n \ndiff --git a/line-log.c b/line-log.c\nindex af6e2f7..5877986 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -14,6 +14,7 @@\n #include \"graph.h\"\n #include \"userdiff.h\"\n #include \"line-log.h\"\n+#include \"argv-array.h\"\n \n static void range_set_grow(struct range_set *rs, size_t extra)\n {\n@@ -746,22 +747,17 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list\n \tadd_line_range(rev, commit, range);\n \n \tif (!rev->diffopt.detect_rename) {\n-\t\tint i, count = 0;\n-\t\tstruct line_log_data *r = range;\n+\t\tstruct line_log_data *r;\n+\t\tstruct argv_array array = ARGV_ARRAY_INIT;\n \t\tconst char **paths;\n-\t\twhile (r) {\n-\t\t\tcount++;\n-\t\t\tr = r->next;\n-\t\t}\n-\t\tpaths = xmalloc((count+1)*sizeof(char *));\n-\t\tr = range;\n-\t\tfor (i = 0; i < count; i++) {\n-\t\t\tpaths[i] = xstrdup(r->path);\n-\t\t\tr = r->next;\n-\t\t}\n-\t\tpaths[count] = NULL;\n+\n+\t\tfor (r = range; r; r = r->next)\n+\t\t\targv_array_push(&array, r->path);\n+\t\tpaths = argv_array_detach(&array);\n+\n \t\tparse_pathspec(&rev->diffopt.pathspec, 0,\n \t\t\t       PATHSPEC_PREFER_FULL, \"\", paths);\n+\t\t/* strings are now owned by pathspec */\n \t\tfree(paths);\n \t}\n }\ndiff --git a/remote-curl.c b/remote-curl.c\nindex c704857..42deeec 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -845,23 +845,22 @@ static void parse_fetch(struct strbuf *buf)\n \n static int push_dav(int nr_spec, char **specs)\n {\n-\tconst char **argv = xmalloc((10 + nr_spec) * sizeof(char*));\n-\tint argc = 0, i;\n+\tstruct child_process child = CHILD_PROCESS_INIT;\n+\tsize_t i;\n \n-\targv[argc++] = \"http-push\";\n-\targv[argc++] = \"--helper-status\";\n+\tchild.git_cmd = 1;\n+\targv_array_push(&child.args, \"http-push\");\n+\targv_array_push(&child.args, \"--helper-status\");\n \tif (options.dry_run)\n-\t\targv[argc++] = \"--dry-run\";\n+\t\targv_array_push(&child.args, \"--dry-run\");\n \tif (options.verbosity > 1)\n-\t\targv[argc++] = \"--verbose\";\n-\targv[argc++] = url.buf;\n+\t\targv_array_push(&child.args, \"--verbose\");\n+\targv_array_push(&child.args, url.buf);\n \tfor (i = 0; i < nr_spec; i++)\n-\t\targv[argc++] = specs[i];\n-\targv[argc++] = NULL;\n+\t\targv_array_push(&child.args, specs[i]);\n \n-\tif (run_command_v_opt(argv, RUN_GIT_CMD))\n-\t\tdie(\"git-%s failed\", argv[0]);\n-\tfree(argv);\n+\tif (run_command(&child))\n+\t\tdie(\"git-http-push failed\");\n \treturn 0;\n }\n \n-- \n2.7.2.645.g4e1306c\n"},{"id":"278930","messageId":"20160222224425.GH10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 08/22] convert trivial cases to ALLOC_ARRAY","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:25Z","receivedAt":"2016-02-22T22:44:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Each of these cases can be converted to use ALLOC_ARRAY or\nREALLOC_ARRAY, which has two advantages:\n\n  1. It automatically checks the array-size multiplication\n     for overflow.\n\n  2. It always uses sizeof(*array) for the element-size,\n     so that it can never go out of sync with the declared\n     type of the array.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n alias.c                  |  2 +-\n attr.c                   |  2 +-\n bisect.c                 |  4 ++--\n builtin/blame.c          |  3 ++-\n builtin/clean.c          |  2 +-\n builtin/fast-export.c    |  2 +-\n builtin/index-pack.c     |  4 ++--\n builtin/merge-base.c     |  2 +-\n builtin/mv.c             |  3 ++-\n builtin/pack-objects.c   |  7 ++++---\n builtin/pack-redundant.c |  2 +-\n builtin/receive-pack.c   |  5 ++---\n column.c                 |  2 +-\n combine-diff.c           |  4 ++--\n commit.c                 |  2 +-\n compat/mingw.c           |  6 +++---\n diffcore-order.c         |  4 ++--\n dir.c                    |  6 +++---\n fast-import.c            |  5 +++--\n fsck.c                   |  3 ++-\n graph.c                  | 10 ++++------\n khash.h                  |  2 +-\n levenshtein.c            |  8 +++++---\n line-log.c               |  8 ++++----\n notes.c                  |  2 +-\n pack-check.c             |  2 +-\n pack-revindex.c          | 12 ++++++++----\n pathspec.c               |  5 +++--\n remote-curl.c            |  3 ++-\n sha1_file.c              |  4 ++--\n shallow.c                |  6 +++---\n show-index.c             |  3 ++-\n transport.c              |  2 +-\n xdiff-interface.c        |  2 +-\n 34 files changed, 75 insertions(+), 64 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex a11229d..3b90397 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -23,7 +23,7 @@ int split_cmdline(char *cmdline, const char ***argv)\n \tint src, dst, count = 0, size = 16;\n \tchar quoted = 0;\n \n-\t*argv = xmalloc(sizeof(**argv) * size);\n+\tALLOC_ARRAY(*argv, size);\n \n \t/* split alias_string */\n \t(*argv)[count++] = cmdline;\ndiff --git a/attr.c b/attr.c\nindex 086c08d..c83ec49 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -799,7 +799,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)\n \t\t\t++count;\n \t}\n \t*num = count;\n-\t*check = xmalloc(sizeof(**check) * count);\n+\tALLOC_ARRAY(*check, count);\n \tj = 0;\n \tfor (i = 0; i < attr_nr; i++) {\n \t\tconst char *value = check_all_attr[i].value;\ndiff --git a/bisect.c b/bisect.c\nindex 06ec54e..7996c29 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -708,10 +708,10 @@ static struct commit *get_commit_reference(const unsigned char *sha1)\n \n static struct commit **get_bad_and_good_commits(int *rev_nr)\n {\n-\tint len = 1 + good_revs.nr;\n-\tstruct commit **rev = xmalloc(len * sizeof(*rev));\n+\tstruct commit **rev;\n \tint i, n = 0;\n \n+\tALLOC_ARRAY(rev, 1 + good_revs.nr);\n \trev[n++] = get_commit_reference(current_bad_oid->hash);\n \tfor (i = 0; i < good_revs.nr; i++)\n \t\trev[n++] = get_commit_reference(good_revs.sha1[i]);\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 55bf5fa..b4ed462 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2059,7 +2059,8 @@ static int prepare_lines(struct scoreboard *sb)\n \tfor (p = buf; p < end; p = get_next_line(p, end))\n \t\tnum++;\n \n-\tsb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1));\n+\tALLOC_ARRAY(sb->lineno, num + 1);\n+\tlineno = sb->lineno;\n \n \tfor (p = buf; p < end; p = get_next_line(p, end))\n \t\t*lineno++ = p - buf;\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 7b08237..8229f7e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -543,7 +543,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \tint eof = 0;\n \tint i;\n \n-\tchosen = xmalloc(sizeof(int) * stuff->nr);\n+\tALLOC_ARRAY(chosen, stuff->nr);\n \t/* set chosen as uninitialized */\n \tfor (i = 0; i < stuff->nr; i++)\n \t\tchosen[i] = -1;\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 2471297..8164b58 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -1021,7 +1021,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)\n \t\tconst char **refspecs_str;\n \t\tint i;\n \n-\t\trefspecs_str = xmalloc(sizeof(*refspecs_str) * refspecs_list.nr);\n+\t\tALLOC_ARRAY(refspecs_str, refspecs_list.nr);\n \t\tfor (i = 0; i < refspecs_list.nr; i++)\n \t\t\trefspecs_str[i] = refspecs_list.items[i].string;\n \ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 6a01509..a60bcfa 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1346,7 +1346,7 @@ static void fix_unresolved_deltas(struct sha1file *f)\n \t * before deltas depending on them, a good heuristic is to start\n \t * resolving deltas in the same order as their position in the pack.\n \t */\n-\tsorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos));\n+\tALLOC_ARRAY(sorted_by_pos, nr_ref_deltas);\n \tfor (i = 0; i < nr_ref_deltas; i++)\n \t\tsorted_by_pos[i] = &ref_deltas[i];\n \tqsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare);\n@@ -1759,7 +1759,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \tif (show_stat)\n \t\tshow_pack_info(stat_only);\n \n-\tidx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));\n+\tALLOC_ARRAY(idx_objects, nr_objects);\n \tfor (i = 0; i < nr_objects; i++)\n \t\tidx_objects[i] = &objects[i].idx;\n \tcurr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex a891162..c0d1822 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -252,7 +252,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)\n \tif (argc < 2)\n \t\tusage_with_options(merge_base_usage, options);\n \n-\trev = xmalloc(argc * sizeof(*rev));\n+\tALLOC_ARRAY(rev, argc);\n \twhile (argc-- > 0)\n \t\trev[rev_nr++] = get_commit_reference(*argv++);\n \treturn show_merge_base(rev, rev_nr, show_all);\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex d1d4316..9a9813a 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -24,7 +24,8 @@ static const char **internal_copy_pathspec(const char *prefix,\n \t\t\t\t\t   int count, unsigned flags)\n {\n \tint i;\n-\tconst char **result = xmalloc((count + 1) * sizeof(const char *));\n+\tconst char **result;\n+\tALLOC_ARRAY(result, count + 1);\n \tmemcpy(result, pathspec, count * sizeof(const char *));\n \tresult[count] = NULL;\n \tfor (i = 0; i < count; i++) {\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 4dae5b1..b4f1fa6 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -624,7 +624,7 @@ static struct object_entry **compute_write_order(void)\n {\n \tunsigned int i, wo_end, last_untagged;\n \n-\tstruct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));\n+\tstruct object_entry **wo;\n \tstruct object_entry *objects = to_pack.objects;\n \n \tfor (i = 0; i < to_pack.nr_objects; i++) {\n@@ -657,6 +657,7 @@ static struct object_entry **compute_write_order(void)\n \t * Give the objects in the original recency order until\n \t * we see a tagged tip.\n \t */\n+\tALLOC_ARRAY(wo, to_pack.nr_objects);\n \tfor (i = wo_end = 0; i < to_pack.nr_objects; i++) {\n \t\tif (objects[i].tagged)\n \t\t\tbreak;\n@@ -769,7 +770,7 @@ static void write_pack_file(void)\n \n \tif (progress > pack_to_stdout)\n \t\tprogress_state = start_progress(_(\"Writing objects\"), nr_result);\n-\twritten_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));\n+\tALLOC_ARRAY(written_list, to_pack.nr_objects);\n \twrite_order = compute_write_order();\n \n \tdo {\n@@ -2129,7 +2130,7 @@ static void prepare_pack(int window, int depth)\n \tif (!to_pack.nr_objects || !window || !depth)\n \t\treturn;\n \n-\tdelta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));\n+\tALLOC_ARRAY(delta_list, to_pack.nr_objects);\n \tnr_deltas = n = 0;\n \n \tfor (i = 0; i < to_pack.nr_objects; i++) {\ndiff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c\nindex d0532f6..72c8158 100644\n--- a/builtin/pack-redundant.c\n+++ b/builtin/pack-redundant.c\n@@ -53,7 +53,7 @@ static inline struct llist_item *llist_item_get(void)\n \t\tfree_nodes = free_nodes->next;\n \t} else {\n \t\tint i = 1;\n-\t\tnew = xmalloc(sizeof(struct llist_item) * BLKSIZE);\n+\t\tALLOC_ARRAY(new, BLKSIZE);\n \t\tfor (; i < BLKSIZE; i++)\n \t\t\tllist_item_put(&new[i]);\n \t}\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 932afab..3dc3868 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1591,8 +1591,7 @@ static void prepare_shallow_update(struct command *commands,\n {\n \tint i, j, k, bitmap_size = (si->ref->nr + 31) / 32;\n \n-\tsi->used_shallow = xmalloc(sizeof(*si->used_shallow) *\n-\t\t\t\t   si->shallow->nr);\n+\tALLOC_ARRAY(si->used_shallow, si->shallow->nr);\n \tassign_shallow_commits_to_refs(si, si->used_shallow, NULL);\n \n \tsi->need_reachability_test =\n@@ -1658,7 +1657,7 @@ static void update_shallow_info(struct command *commands,\n \t\treturn;\n \t}\n \n-\tref_status = xmalloc(sizeof(*ref_status) * ref->nr);\n+\tALLOC_ARRAY(ref_status, ref->nr);\n \tassign_shallow_commits_to_refs(si, NULL, ref_status);\n \tfor (cmd = commands; cmd; cmd = cmd->next) {\n \t\tif (is_null_sha1(cmd->new_sha1))\ndiff --git a/column.c b/column.c\nindex 786abe6..f9fda68 100644\n--- a/column.c\n+++ b/column.c\n@@ -164,7 +164,7 @@ static void display_table(const struct string_list *list,\n \tdata.colopts = colopts;\n \tdata.opts = *opts;\n \n-\tdata.len = xmalloc(sizeof(*data.len) * list->nr);\n+\tALLOC_ARRAY(data.len, list->nr);\n \tfor (i = 0; i < list->nr; i++)\n \t\tdata.len[i] = item_length(colopts, list->items[i].string);\n \ndiff --git a/combine-diff.c b/combine-diff.c\nindex 5571304..a698016 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1372,7 +1372,7 @@ static struct combine_diff_path *find_paths_multitree(\n \tstruct combine_diff_path paths_head;\n \tstruct strbuf base;\n \n-\tparents_sha1 = xmalloc(nparent * sizeof(parents_sha1[0]));\n+\tALLOC_ARRAY(parents_sha1, nparent);\n \tfor (i = 0; i < nparent; i++)\n \t\tparents_sha1[i] = parents->sha1[i];\n \n@@ -1483,7 +1483,7 @@ void diff_tree_combined(const unsigned char *sha1,\n \tif (opt->orderfile && num_paths) {\n \t\tstruct obj_order *o;\n \n-\t\to = xmalloc(sizeof(*o) * num_paths);\n+\t\tALLOC_ARRAY(o, num_paths);\n \t\tfor (i = 0, p = paths; p; p = p->next, i++)\n \t\t\to[i].obj = p;\n \t\torder_objects(opt->orderfile, path_path, o, num_paths);\ndiff --git a/commit.c b/commit.c\nindex 40388d7..31cd91f 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -903,7 +903,7 @@ static int remove_redundant(struct commit **array, int cnt)\n \n \twork = xcalloc(cnt, sizeof(*work));\n \tredundant = xcalloc(cnt, 1);\n-\tfilled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));\n+\tALLOC_ARRAY(filled_index, cnt - 1);\n \n \tfor (i = 0; i < cnt; i++)\n \t\tparse_commit(array[i]);\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex fbe69b8..7803f30 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -893,7 +893,7 @@ static char **get_path_split(void)\n \tif (!n)\n \t\treturn NULL;\n \n-\tpath = xmalloc((n+1)*sizeof(char *));\n+\tALLOC_ARRAY(path, n + 1);\n \tp = envpath;\n \ti = 0;\n \tdo {\n@@ -978,7 +978,7 @@ static wchar_t *make_environment_block(char **deltaenv)\n \t\ti++;\n \n \t/* copy the environment, leaving space for changes */\n-\ttmpenv = xmalloc((size + i) * sizeof(char*));\n+\tALLOC_ARRAY(tmpenv, size + i);\n \tmemcpy(tmpenv, environ, size * sizeof(char*));\n \n \t/* merge supplied environment changes into the temporary environment */\n@@ -1168,7 +1168,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)\n \t\tint argc = 0;\n \t\tconst char **argv2;\n \t\twhile (argv[argc]) argc++;\n-\t\targv2 = xmalloc(sizeof(*argv) * (argc+1));\n+\t\tALLOC_ARRAY(argv2, argc + 1);\n \t\targv2[0] = (char *)cmd;\t/* full path to the script file */\n \t\tmemcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);\n \t\tpid = mingw_spawnv(prog, argv2, 1);\ndiff --git a/diffcore-order.c b/diffcore-order.c\nindex 97dd3d0..69d41f7 100644\n--- a/diffcore-order.c\n+++ b/diffcore-order.c\n@@ -52,7 +52,7 @@ static void prepare_order(const char *orderfile)\n \t\t}\n \t\tif (pass == 0) {\n \t\t\torder_cnt = cnt;\n-\t\t\torder = xmalloc(sizeof(*order) * cnt);\n+\t\t\tALLOC_ARRAY(order, cnt);\n \t\t}\n \t}\n }\n@@ -120,7 +120,7 @@ void diffcore_order(const char *orderfile)\n \tif (!q->nr)\n \t\treturn;\n \n-\to = xmalloc(sizeof(*o) * q->nr);\n+\tALLOC_ARRAY(o, q->nr);\n \tfor (i = 0; i < q->nr; i++)\n \t\to[i].obj = q->queue[i];\n \torder_objects(orderfile, pair_pathtwo, o, q->nr);\ndiff --git a/dir.c b/dir.c\nindex f0b6d0a..66c93c1 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2484,14 +2484,14 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,\n \tud.untracked_alloc = value;\n \tud.untracked_nr\t   = value;\n \tif (ud.untracked_nr)\n-\t\tud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);\n+\t\tALLOC_ARRAY(ud.untracked, ud.untracked_nr);\n \tdata = next;\n \n \tnext = data;\n \tud.dirs_alloc = ud.dirs_nr = decode_varint(&next);\n \tif (next > end)\n \t\treturn -1;\n-\tud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);\n+\tALLOC_ARRAY(ud.dirs, ud.dirs_nr);\n \tdata = next;\n \n \tlen = strlen((const char *)data);\n@@ -2611,7 +2611,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long\n \trd.data\t      = next;\n \trd.end\t      = end;\n \trd.index      = 0;\n-\trd.ucd        = xmalloc(sizeof(*rd.ucd) * len);\n+\tALLOC_ARRAY(rd.ucd, len);\n \n \tif (read_one_dir(&uc->root, &rd) || rd.index != len)\n \t\tgoto done;\ndiff --git a/fast-import.c b/fast-import.c\nindex bf01b34..a6467cb 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -814,7 +814,8 @@ static struct tree_entry *new_tree_entry(void)\n \tif (!avail_tree_entry) {\n \t\tunsigned int n = tree_entry_alloc;\n \t\ttotal_allocd += n * sizeof(struct tree_entry);\n-\t\tavail_tree_entry = e = xmalloc(n * sizeof(struct tree_entry));\n+\t\tALLOC_ARRAY(e, n);\n+\t\tavail_tree_entry = e;\n \t\twhile (n-- > 1) {\n \t\t\t*((void**)e) = e + 1;\n \t\t\te++;\n@@ -898,7 +899,7 @@ static const char *create_index(void)\n \tstruct object_entry_pool *o;\n \n \t/* Build the table of object IDs. */\n-\tidx = xmalloc(object_count * sizeof(*idx));\n+\tALLOC_ARRAY(idx, object_count);\n \tc = idx;\n \tfor (o = blocks; o; o = o->next_pool)\n \t\tfor (e = o->next_free; e-- != o->entries;)\ndiff --git a/fsck.c b/fsck.c\nindex c637f66..ca4c685 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -199,7 +199,8 @@ void fsck_set_msg_type(struct fsck_options *options,\n \n \tif (!options->msg_type) {\n \t\tint i;\n-\t\tint *msg_type = xmalloc(sizeof(int) * FSCK_MSG_MAX);\n+\t\tint *msg_type;\n+\t\tALLOC_ARRAY(msg_type, FSCK_MSG_MAX);\n \t\tfor (i = 0; i < FSCK_MSG_MAX; i++)\n \t\t\tmsg_type[i] = fsck_msg_type(i, options);\n \t\toptions->msg_type = msg_type;\ndiff --git a/graph.c b/graph.c\nindex c25a09a..1350bdd 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -234,12 +234,10 @@ struct git_graph *graph_init(struct rev_info *opt)\n \t * We'll automatically grow columns later if we need more room.\n \t */\n \tgraph->column_capacity = 30;\n-\tgraph->columns = xmalloc(sizeof(struct column) *\n-\t\t\t\t graph->column_capacity);\n-\tgraph->new_columns = xmalloc(sizeof(struct column) *\n-\t\t\t\t     graph->column_capacity);\n-\tgraph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n-\tgraph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);\n+\tALLOC_ARRAY(graph->columns, graph->column_capacity);\n+\tALLOC_ARRAY(graph->new_columns, graph->column_capacity);\n+\tALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);\n+\tALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity);\n \n \t/*\n \t * The diff output prefix callback, with this we can make\ndiff --git a/khash.h b/khash.h\nindex 376475a..c0da40d 100644\n--- a/khash.h\n+++ b/khash.h\n@@ -117,7 +117,7 @@ static const double __ac_HASH_UPPER = 0.77;\n \t\t\tif (new_n_buckets < 4) new_n_buckets = 4;\t\t\t\t\t\\\n \t\t\tif (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0;\t/* requested size is too small */ \\\n \t\t\telse { /* hash table size to be changed (shrink or expand); rehash */ \\\n-\t\t\t\tnew_flags = (khint32_t*)xmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t));\t\\\n+\t\t\t\tALLOC_ARRAY(new_flags, __ac_fsize(new_n_buckets)); \\\n \t\t\t\tif (!new_flags) return -1;\t\t\t\t\t\t\t\t\\\n \t\t\t\tmemset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \\\n \t\t\t\tif (h->n_buckets < new_n_buckets) {\t/* expand */\t\t\\\ndiff --git a/levenshtein.c b/levenshtein.c\nindex fc28159..d263269 100644\n--- a/levenshtein.c\n+++ b/levenshtein.c\n@@ -42,11 +42,13 @@ int levenshtein(const char *string1, const char *string2,\n \t\tint w, int s, int a, int d)\n {\n \tint len1 = strlen(string1), len2 = strlen(string2);\n-\tint *row0 = xmalloc(sizeof(int) * (len2 + 1));\n-\tint *row1 = xmalloc(sizeof(int) * (len2 + 1));\n-\tint *row2 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row0, *row1, *row2;\n \tint i, j;\n \n+\tALLOC_ARRAY(row0, len2 + 1);\n+\tALLOC_ARRAY(row1, len2 + 1);\n+\tALLOC_ARRAY(row2, len2 + 1);\n+\n \tfor (j = 0; j <= len2; j++)\n \t\trow1[j] = j * a;\n \tfor (i = 0; i < len1; i++) {\ndiff --git a/line-log.c b/line-log.c\nindex 5877986..bbe31ed 100644\n--- a/line-log.c\n+++ b/line-log.c\n@@ -522,7 +522,7 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines,\n \tif (diff_populate_filespec(spec, 0))\n \t\tdie(\"Cannot read blob %s\", sha1_to_hex(spec->sha1));\n \n-\tends = xmalloc(size * sizeof(*ends));\n+\tALLOC_ARRAY(ends, size);\n \tends[cur++] = 0;\n \tdata = spec->data;\n \twhile (num < spec->size) {\n@@ -1142,9 +1142,9 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm\n \tif (nparents > 1 && rev->first_parent_only)\n \t\tnparents = 1;\n \n-\tdiffqueues = xmalloc(nparents * sizeof(*diffqueues));\n-\tcand = xmalloc(nparents * sizeof(*cand));\n-\tparents = xmalloc(nparents * sizeof(*parents));\n+\tALLOC_ARRAY(diffqueues, nparents);\n+\tALLOC_ARRAY(cand, nparents);\n+\tALLOC_ARRAY(parents, nparents);\n \n \tp = commit->parents;\n \tfor (i = 0; i < nparents; i++) {\ndiff --git a/notes.c b/notes.c\nindex c1e5035..88cf474 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1035,7 +1035,7 @@ struct notes_tree **load_notes_trees(struct string_list *refs, int flags)\n \tstruct string_list_item *item;\n \tint counter = 0;\n \tstruct notes_tree **trees;\n-\ttrees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));\n+\tALLOC_ARRAY(trees, refs->nr + 1);\n \tfor_each_string_list_item(item, refs) {\n \t\tstruct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));\n \t\tinit_notes(t, item->string, combine_notes_ignore, flags);\ndiff --git a/pack-check.c b/pack-check.c\nindex 433bd86..1da89a4 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -89,7 +89,7 @@ static int verify_packfile(struct packed_git *p,\n \t * we do not do scan-streaming check on the pack file.\n \t */\n \tnr_objects = p->num_objects;\n-\tentries = xmalloc((nr_objects + 1) * sizeof(*entries));\n+\tALLOC_ARRAY(entries, nr_objects + 1);\n \tentries[nr_objects].offset = pack_sig_ofs;\n \t/* first sort entries by pack offset, since unpacking them is more efficient that way */\n \tfor (i = 0; i < nr_objects; i++) {\ndiff --git a/pack-revindex.c b/pack-revindex.c\nindex 155a8a3..96d51c3 100644\n--- a/pack-revindex.c\n+++ b/pack-revindex.c\n@@ -44,10 +44,14 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max)\n \t * keep track of them with alias pointers, always sorting from \"from\"\n \t * to \"to\".\n \t */\n-\tstruct revindex_entry *tmp = xmalloc(n * sizeof(*tmp));\n-\tstruct revindex_entry *from = entries, *to = tmp;\n+\tstruct revindex_entry *tmp, *from, *to;\n \tint bits;\n-\tunsigned *pos = xmalloc(BUCKETS * sizeof(*pos));\n+\tunsigned *pos;\n+\n+\tALLOC_ARRAY(pos, BUCKETS);\n+\tALLOC_ARRAY(tmp, n);\n+\tfrom = entries;\n+\tto = tmp;\n \n \t/*\n \t * If (max >> bits) is zero, then we know that the radix digit we are\n@@ -121,7 +125,7 @@ static void create_pack_revindex(struct packed_git *p)\n \tunsigned i;\n \tconst char *index = p->index_data;\n \n-\tp->revindex = xmalloc(sizeof(*p->revindex) * (num_ent + 1));\n+\tALLOC_ARRAY(p->revindex, num_ent + 1);\n \tindex += 4 * 256;\n \n \tif (p->index_version > 1) {\ndiff --git a/pathspec.c b/pathspec.c\nindex 9304ee3..c9e9b6c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -406,7 +406,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tn++;\n \n \tpathspec->nr = n;\n-\tpathspec->items = item = xmalloc(sizeof(*item) * n);\n+\tALLOC_ARRAY(pathspec->items, n);\n+\titem = pathspec->items;\n \tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n@@ -483,7 +484,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\n-\tdst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);\n+\tALLOC_ARRAY(dst->items, dst->nr);\n \tmemcpy(dst->items, src->items,\n \t       sizeof(struct pathspec_item) * dst->nr);\n }\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 42deeec..5259b7e 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -696,9 +696,10 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)\n static int fetch_dumb(int nr_heads, struct ref **to_fetch)\n {\n \tstruct walker *walker;\n-\tchar **targets = xmalloc(nr_heads * sizeof(char*));\n+\tchar **targets;\n \tint ret, i;\n \n+\tALLOC_ARRAY(targets, nr_heads);\n \tif (options.depth)\n \t\tdie(\"dumb http transport does not support --depth\");\n \tfor (i = 0; i < nr_heads; i++)\ndiff --git a/sha1_file.c b/sha1_file.c\nindex aab1872..2f1c6d3 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -1942,7 +1942,7 @@ static enum object_type packed_to_object_type(struct packed_git *p,\n \t\t/* Push the object we're going to leave behind */\n \t\tif (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {\n \t\t\tpoi_stack_alloc = alloc_nr(poi_stack_nr);\n-\t\t\tpoi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc);\n+\t\t\tALLOC_ARRAY(poi_stack, poi_stack_alloc);\n \t\t\tmemcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);\n \t\t} else {\n \t\t\tALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);\n@@ -2308,7 +2308,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,\n \t\tif (delta_stack_nr >= delta_stack_alloc\n \t\t    && delta_stack == small_delta_stack) {\n \t\t\tdelta_stack_alloc = alloc_nr(delta_stack_nr);\n-\t\t\tdelta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc);\n+\t\t\tALLOC_ARRAY(delta_stack, delta_stack_alloc);\n \t\t\tmemcpy(delta_stack, small_delta_stack,\n \t\t\t       sizeof(*delta_stack)*delta_stack_nr);\n \t\t} else {\ndiff --git a/shallow.c b/shallow.c\nindex 60f1505..71163bf 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -315,8 +315,8 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa)\n \tinfo->shallow = sa;\n \tif (!sa)\n \t\treturn;\n-\tinfo->ours = xmalloc(sizeof(*info->ours) * sa->nr);\n-\tinfo->theirs = xmalloc(sizeof(*info->theirs) * sa->nr);\n+\tALLOC_ARRAY(info->ours, sa->nr);\n+\tALLOC_ARRAY(info->theirs, sa->nr);\n \tfor (i = 0; i < sa->nr; i++) {\n \t\tif (has_sha1_file(sa->sha1[i])) {\n \t\t\tstruct commit_graft *graft;\n@@ -487,7 +487,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,\n \tstruct paint_info pi;\n \n \ttrace_printf_key(&trace_shallow, \"shallow: assign_shallow_commits_to_refs\\n\");\n-\tshallow = xmalloc(sizeof(*shallow) * (info->nr_ours + info->nr_theirs));\n+\tALLOC_ARRAY(shallow, info->nr_ours + info->nr_theirs);\n \tfor (i = 0; i < info->nr_ours; i++)\n \t\tshallow[nr_shallow++] = info->ours[i];\n \tfor (i = 0; i < info->nr_theirs; i++)\ndiff --git a/show-index.c b/show-index.c\nindex d9e4903..acf8d54 100644\n--- a/show-index.c\n+++ b/show-index.c\n@@ -50,7 +50,8 @@ int main(int argc, char **argv)\n \t\t\tunsigned char sha1[20];\n \t\t\tuint32_t crc;\n \t\t\tuint32_t off;\n-\t\t} *entries = xmalloc(nr * sizeof(entries[0]));\n+\t\t} *entries;\n+\t\tALLOC_ARRAY(entries, nr);\n \t\tfor (i = 0; i < nr; i++)\n \t\t\tif (fread(entries[i].sha1, 20, 1, stdin) != 1)\n \t\t\t\tdie(\"unable to read sha1 %u/%u\", i, nr);\ndiff --git a/transport.c b/transport.c\nindex c92f8ae..3b4e644 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -977,7 +977,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)\n \t\t * This condition shouldn't be met in a non-deepening fetch\n \t\t * (see builtin/fetch.c:quickfetch()).\n \t\t */\n-\t\theads = xmalloc(nr_refs * sizeof(*heads));\n+\t\tALLOC_ARRAY(heads, nr_refs);\n \t\tfor (rm = refs; rm; rm = rm->next)\n \t\t\theads[nr_heads++] = rm;\n \t}\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex cb67c1c..54236f2 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -265,7 +265,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)\n \tfor (i = 0, regs->nr = 1; value[i]; i++)\n \t\tif (value[i] == '\\n')\n \t\t\tregs->nr++;\n-\tregs->array = xmalloc(regs->nr * sizeof(struct ff_reg));\n+\tALLOC_ARRAY(regs->array, regs->nr);\n \tfor (i = 0; i < regs->nr; i++) {\n \t\tstruct ff_reg *reg = regs->array + i;\n \t\tconst char *ep = strchr(value, '\\n'), *expression;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278929","messageId":"20160222224428.GI10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 09/22] use xmallocz to avoid size arithmetic","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:28Z","receivedAt":"2016-02-22T22:44:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We frequently allocate strings as xmalloc(len + 1), where\nthe extra 1 is for the NUL terminator. This can be done more\nsimply with xmallocz, which also checks for integer\noverflow.\n\nThere's no case where switching xmalloc(n+1) to xmallocz(n)\nis wrong; the result is the same length, and malloc made no\nguarantees about what was in the buffer anyway. But in some\ncases, we can stop manually placing NUL at the end of the\nallocated buffer. But that's only safe if it's clear that\nthe contents will always fill the buffer.\n\nIn each case where this patch does so, I manually examined\nthe control flow, and I tried to err on the side of caution.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/check-ref-format.c | 2 +-\n builtin/merge-tree.c       | 2 +-\n builtin/worktree.c         | 2 +-\n column.c                   | 3 +--\n combine-diff.c             | 4 +---\n config.c                   | 4 +---\n dir.c                      | 2 +-\n entry.c                    | 2 +-\n grep.c                     | 3 +--\n imap-send.c                | 5 ++---\n ll-merge.c                 | 2 +-\n progress.c                 | 2 +-\n refs.c                     | 2 +-\n setup.c                    | 5 ++---\n strbuf.c                   | 2 +-\n 15 files changed, 17 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c\nindex fd915d5..eac4994 100644\n--- a/builtin/check-ref-format.c\n+++ b/builtin/check-ref-format.c\n@@ -20,7 +20,7 @@ static const char builtin_check_ref_format_usage[] =\n  */\n static char *collapse_slashes(const char *refname)\n {\n-\tchar *ret = xmalloc(strlen(refname) + 1);\n+\tchar *ret = xmallocz(strlen(refname));\n \tchar ch;\n \tchar prev = '/';\n \tchar *cp = ret;\ndiff --git a/builtin/merge-tree.c b/builtin/merge-tree.c\nindex d4f0cbd..ca57004 100644\n--- a/builtin/merge-tree.c\n+++ b/builtin/merge-tree.c\n@@ -174,7 +174,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi\n \n static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)\n {\n-\tchar *path = xmalloc(traverse_path_len(info, n) + 1);\n+\tchar *path = xmallocz(traverse_path_len(info, n));\n \treturn make_traverse_path(path, info, n);\n }\n \ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 475b958..0a45710 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -52,7 +52,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)\n \t\treturn 1;\n \t}\n \tlen = st.st_size;\n-\tpath = xmalloc(len + 1);\n+\tpath = xmallocz(len);\n \tread_in_full(fd, path, len);\n \tclose(fd);\n \twhile (len && (path[len - 1] == '\\n' || path[len - 1] == '\\r'))\ndiff --git a/column.c b/column.c\nindex f9fda68..d55ead1 100644\n--- a/column.c\n+++ b/column.c\n@@ -173,9 +173,8 @@ static void display_table(const struct string_list *list,\n \tif (colopts & COL_DENSE)\n \t\tshrink_columns(&data);\n \n-\tempty_cell = xmalloc(initial_width + 1);\n+\tempty_cell = xmallocz(initial_width);\n \tmemset(empty_cell, ' ', initial_width);\n-\tempty_cell[initial_width] = '\\0';\n \tfor (y = 0; y < data.rows; y++) {\n \t\tfor (x = 0; x < data.cols; x++)\n \t\t\tif (display_cell(&data, initial_width, empty_cell, x, y))\ndiff --git a/combine-diff.c b/combine-diff.c\nindex a698016..890c415 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1043,7 +1043,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t\telem->mode = canon_mode(S_IFLNK);\n \n \t\t\tresult_size = len;\n-\t\t\tresult = xmalloc(len + 1);\n+\t\t\tresult = xmallocz(len);\n \n \t\t\tdone = read_in_full(fd, result, len);\n \t\t\tif (done < 0)\n@@ -1051,8 +1051,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\telse if (done < len)\n \t\t\t\tdie(\"early EOF '%s'\", elem->path);\n \n-\t\t\tresult[len] = 0;\n-\n \t\t\t/* If not a fake symlink, apply filters, e.g. autocrlf */\n \t\t\tif (is_file) {\n \t\t\t\tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/config.c b/config.c\nindex b95ac3a..e7b589a 100644\n--- a/config.c\n+++ b/config.c\n@@ -1902,7 +1902,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \t * Validate the key and while at it, lower case it for matching.\n \t */\n \tif (store_key)\n-\t\t*store_key = xmalloc(strlen(key) + 1);\n+\t\t*store_key = xmallocz(strlen(key));\n \n \tdot = 0;\n \tfor (i = 0; key[i]; i++) {\n@@ -1926,8 +1926,6 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele\n \t\tif (store_key)\n \t\t\t(*store_key)[i] = c;\n \t}\n-\tif (store_key)\n-\t\t(*store_key)[i] = 0;\n \n \treturn 0;\n \ndiff --git a/dir.c b/dir.c\nindex 66c93c1..6c627d5 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -711,7 +711,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\tclose(fd);\n \t\t\treturn 0;\n \t\t}\n-\t\tbuf = xmalloc(size+1);\n+\t\tbuf = xmallocz(size);\n \t\tif (read_in_full(fd, buf, size) != size) {\n \t\t\tfree(buf);\n \t\t\tclose(fd);\ndiff --git a/entry.c b/entry.c\nindex 582c400..a410957 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -6,7 +6,7 @@\n static void create_directories(const char *path, int path_len,\n \t\t\t       const struct checkout *state)\n {\n-\tchar *buf = xmalloc(path_len + 1);\n+\tchar *buf = xmallocz(path_len);\n \tint len = 0;\n \n \twhile (len < path_len) {\ndiff --git a/grep.c b/grep.c\nindex 7b2b96a..528b652 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1741,7 +1741,7 @@ static int grep_source_load_file(struct grep_source *gs)\n \ti = open(filename, O_RDONLY);\n \tif (i < 0)\n \t\tgoto err_ret;\n-\tdata = xmalloc(size + 1);\n+\tdata = xmallocz(size);\n \tif (st.st_size != read_in_full(i, data, size)) {\n \t\terror(_(\"'%s': short read %s\"), filename, strerror(errno));\n \t\tclose(i);\n@@ -1749,7 +1749,6 @@ static int grep_source_load_file(struct grep_source *gs)\n \t\treturn -1;\n \t}\n \tclose(i);\n-\tdata[size] = 0;\n \n \tgs->buf = data;\n \tgs->size = size;\ndiff --git a/imap-send.c b/imap-send.c\nindex 4d3b773..2c52027 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -892,12 +892,11 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)\n \tresponse = xstrfmt(\"%s %s\", user, hex);\n \tresp_len = strlen(response) + 1;\n \n-\tresponse_64 = xmalloc(ENCODED_SIZE(resp_len) + 1);\n+\tresponse_64 = xmallocz(ENCODED_SIZE(resp_len));\n \tencoded_len = EVP_EncodeBlock((unsigned char *)response_64,\n \t\t\t\t      (unsigned char *)response, resp_len);\n \tif (encoded_len < 0)\n \t\tdie(\"EVP_EncodeBlock error\");\n-\tresponse_64[encoded_len] = '\\0';\n \treturn (char *)response_64;\n }\n \n@@ -1188,7 +1187,7 @@ static void lf_to_crlf(struct strbuf *msg)\n \t\tj++;\n \t}\n \n-\tnew = xmalloc(j + 1);\n+\tnew = xmallocz(j);\n \n \t/*\n \t * Second pass: write the new string.  Note that this loop is\ndiff --git a/ll-merge.c b/ll-merge.c\nindex 0338630..ff4a43a 100644\n--- a/ll-merge.c\n+++ b/ll-merge.c\n@@ -205,7 +205,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,\n \tif (fstat(fd, &st))\n \t\tgoto close_bad;\n \tresult->size = st.st_size;\n-\tresult->ptr = xmalloc(result->size + 1);\n+\tresult->ptr = xmallocz(result->size);\n \tif (read_in_full(fd, result->ptr, result->size) != result->size) {\n \t\tfree(result->ptr);\n \t\tresult->ptr = NULL;\ndiff --git a/progress.c b/progress.c\nindex 353bd37..76a88c5 100644\n--- a/progress.c\n+++ b/progress.c\n@@ -247,7 +247,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)\n \t\tsize_t len = strlen(msg) + 5;\n \t\tstruct throughput *tp = progress->throughput;\n \n-\t\tbufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);\n+\t\tbufp = (len < sizeof(buf)) ? buf : xmallocz(len);\n \t\tif (tp) {\n \t\t\tunsigned int rate = !tp->avg_misecs ? 0 :\n \t\t\t\t\ttp->avg_bytes / tp->avg_misecs;\ndiff --git a/refs.c b/refs.c\nindex e2d34b2..1d9e2a7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -124,7 +124,7 @@ int refname_is_safe(const char *refname)\n \t\tchar *buf;\n \t\tint result;\n \n-\t\tbuf = xmalloc(strlen(refname) + 1);\n+\t\tbuf = xmallocz(strlen(refname));\n \t\t/*\n \t\t * Does the refname try to escape refs/?\n \t\t * For example: refs/foo/../bar is safe but refs/foo/../../bar\ndiff --git a/setup.c b/setup.c\nindex 0deb022..ab21086 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -88,7 +88,7 @@ char *prefix_path_gently(const char *prefix, int len,\n \tconst char *orig = path;\n \tchar *sanitized;\n \tif (is_absolute_path(orig)) {\n-\t\tsanitized = xmalloc(strlen(path) + 1);\n+\t\tsanitized = xmallocz(strlen(path));\n \t\tif (remaining_prefix)\n \t\t\t*remaining_prefix = 0;\n \t\tif (normalize_path_copy_len(sanitized, path, remaining_prefix)) {\n@@ -488,14 +488,13 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)\n \t\terror_code = READ_GITFILE_ERR_OPEN_FAILED;\n \t\tgoto cleanup_return;\n \t}\n-\tbuf = xmalloc(st.st_size + 1);\n+\tbuf = xmallocz(st.st_size);\n \tlen = read_in_full(fd, buf, st.st_size);\n \tclose(fd);\n \tif (len != st.st_size) {\n \t\terror_code = READ_GITFILE_ERR_READ_FAILED;\n \t\tgoto cleanup_return;\n \t}\n-\tbuf[len] = '\\0';\n \tif (!starts_with(buf, \"gitdir: \")) {\n \t\terror_code = READ_GITFILE_ERR_INVALID_FORMAT;\n \t\tgoto cleanup_return;\ndiff --git a/strbuf.c b/strbuf.c\nindex bab316d..f60e2ee 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -718,7 +718,7 @@ char *xstrdup_tolower(const char *string)\n \tsize_t len, i;\n \n \tlen = strlen(string);\n-\tresult = xmalloc(len + 1);\n+\tresult = xmallocz(len);\n \tfor (i = 0; i < len; i++)\n \t\tresult[i] = tolower(string[i]);\n \tresult[i] = '\\0';\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278932","messageId":"20160222224431.GJ10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 10/22] convert trivial cases to FLEX_ARRAY macros","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:32Z","receivedAt":"2016-02-22T22:44:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Using FLEX_ARRAY macros reduces the amount of manual\ncomputation size we have to do. It also ensures we don't\noverflow size_t, and it makes sure we write the same number\nof bytes that we allocated.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n attr.c               |  4 +---\n builtin/blame.c      |  4 +---\n builtin/help.c       |  9 +++------\n builtin/mktree.c     |  9 +++++----\n builtin/reflog.c     |  7 ++-----\n cache-tree.c         |  4 +---\n combine-diff.c       |  4 +---\n diff.c               |  7 ++-----\n dir.c                | 16 +++-------------\n hashmap.c            |  3 +--\n help.c               |  6 ++----\n log-tree.c           |  5 ++---\n name-hash.c          |  3 +--\n ref-filter.c         |  6 ++----\n refs.c               |  6 ++----\n refs/files-backend.c | 19 +++++--------------\n remote.c             |  5 +----\n 17 files changed, 35 insertions(+), 82 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex c83ec49..6537a43 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -93,9 +93,7 @@ static struct git_attr *git_attr_internal(const char *name, int len)\n \tif (invalid_attr_name(name, len))\n \t\treturn NULL;\n \n-\ta = xmalloc(sizeof(*a) + len + 1);\n-\tmemcpy(a->name, name, len);\n-\ta->name[len] = 0;\n+\tFLEX_ALLOC_MEM(a, name, name, len);\n \ta->h = hval;\n \ta->next = git_attr_hash[pos];\n \ta->attr_nr = attr_nr++;\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex b4ed462..e982fb8 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -466,13 +466,11 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin,\n static struct origin *make_origin(struct commit *commit, const char *path)\n {\n \tstruct origin *o;\n-\tsize_t pathlen = strlen(path) + 1;\n-\to = xcalloc(1, sizeof(*o) + pathlen);\n+\tFLEX_ALLOC_STR(o, path, path);\n \to->commit = commit;\n \to->refcnt = 1;\n \to->next = commit->util;\n \tcommit->util = o;\n-\tmemcpy(o->path, path, pathlen); /* includes NUL */\n \treturn o;\n }\n \ndiff --git a/builtin/help.c b/builtin/help.c\nindex 1cd0c1e..3c55ce4 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -171,12 +171,10 @@ static void exec_man_cmd(const char *cmd, const char *page)\n static void add_man_viewer(const char *name)\n {\n \tstruct man_viewer_list **p = &man_viewer_list;\n-\tsize_t len = strlen(name);\n \n \twhile (*p)\n \t\tp = &((*p)->next);\n-\t*p = xcalloc(1, (sizeof(**p) + len + 1));\n-\tmemcpy((*p)->name, name, len); /* NUL-terminated by xcalloc */\n+\tFLEX_ALLOC_STR(*p, name, name);\n }\n \n static int supported_man_viewer(const char *name, size_t len)\n@@ -190,9 +188,8 @@ static void do_add_man_viewer_info(const char *name,\n \t\t\t\t   size_t len,\n \t\t\t\t   const char *value)\n {\n-\tstruct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);\n-\n-\tmemcpy(new->name, name, len); /* NUL-terminated by xcalloc */\n+\tstruct man_viewer_info_list *new;\n+\tFLEX_ALLOC_MEM(new, name, name, len);\n \tnew->info = xstrdup(value);\n \tnew->next = man_viewer_info_list;\n \tman_viewer_info_list = new;\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a237caa..4282b62 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -19,16 +19,17 @@ static int alloc, used;\n static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)\n {\n \tstruct treeent *ent;\n-\tint len = strlen(path);\n+\tsize_t len = strlen(path);\n \tif (strchr(path, '/'))\n \t\tdie(\"path %s contains slash\", path);\n \n-\tALLOC_GROW(entries, used + 1, alloc);\n-\tent = entries[used++] = xmalloc(sizeof(**entries) + len + 1);\n+\tFLEX_ALLOC_MEM(ent, name, path, len);\n \tent->mode = mode;\n \tent->len = len;\n \thashcpy(ent->sha1, sha1);\n-\tmemcpy(ent->name, path, len+1);\n+\n+\tALLOC_GROW(entries, used + 1, alloc);\n+\tentries[used++] = ent;\n }\n \n static int ent_compare(const void *a_, const void *b_)\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 9980731..2d46b64 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -382,11 +382,9 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n {\n \tstruct collected_reflog *e;\n \tstruct collect_reflog_cb *cb = cb_data;\n-\tsize_t namelen = strlen(ref);\n \n-\te = xmalloc(sizeof(*e) + namelen + 1);\n+\tFLEX_ALLOC_STR(e, reflog, ref);\n \thashcpy(e->sha1, oid->hash);\n-\tmemcpy(e->reflog, ref, namelen + 1);\n \tALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);\n \tcb->e[cb->nr++] = e;\n \treturn 0;\n@@ -411,8 +409,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \t\t    ent->pattern[len] == '\\0')\n \t\t\treturn ent;\n \n-\tent = xcalloc(1, sizeof(*ent) + len + 1);\n-\tmemcpy(ent->pattern, pattern, len);\n+\tFLEX_ALLOC_MEM(ent, pattern, pattern, len);\n \t*reflog_expire_cfg_tail = ent;\n \treflog_expire_cfg_tail = &(ent->next);\n \treturn ent;\ndiff --git a/cache-tree.c b/cache-tree.c\nindex 20ee7b5..3ebf9c3 100644\n--- a/cache-tree.c\n+++ b/cache-tree.c\n@@ -79,11 +79,9 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,\n \tALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);\n \tit->subtree_nr++;\n \n-\tdown = xmalloc(sizeof(*down) + pathlen + 1);\n+\tFLEX_ALLOC_MEM(down, name, path, pathlen);\n \tdown->cache_tree = NULL;\n \tdown->namelen = pathlen;\n-\tmemcpy(down->name, path, pathlen);\n-\tdown->name[pathlen] = 0;\n \n \tif (pos < it->subtree_nr)\n \t\tmemmove(it->down + pos + 1,\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 890c415..be09a2b 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -319,7 +319,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)\n \tif (line[len-1] == '\\n')\n \t\tlen--;\n \n-\tlline = xmalloc(sizeof(*lline) + len + 1);\n+\tFLEX_ALLOC_MEM(lline, line, line, len);\n \tlline->len = len;\n \tlline->next = NULL;\n \tlline->prev = sline->plost.lost_tail;\n@@ -330,8 +330,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)\n \tsline->plost.lost_tail = lline;\n \tsline->plost.len++;\n \tlline->parent_map = this_mask;\n-\tmemcpy(lline->line, line, len);\n-\tlline->line[len] = 0;\n }\n \n struct combine_diff_state {\ndiff --git a/diff.c b/diff.c\nindex 2136b69..27d14a7 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2607,12 +2607,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,\n \n struct diff_filespec *alloc_filespec(const char *path)\n {\n-\tint namelen = strlen(path);\n-\tstruct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);\n+\tstruct diff_filespec *spec;\n \n-\tmemset(spec, 0, sizeof(*spec));\n-\tspec->path = (char *)(spec + 1);\n-\tmemcpy(spec->path, path, namelen+1);\n+\tFLEXPTR_ALLOC_STR(spec, path, path);\n \tspec->count = 1;\n \tspec->is_binary = -1;\n \treturn spec;\ndiff --git a/dir.c b/dir.c\nindex 6c627d5..f06ebb7 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -503,12 +503,7 @@ void add_exclude(const char *string, const char *base,\n \n \tparse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);\n \tif (flags & EXC_FLAG_MUSTBEDIR) {\n-\t\tchar *s;\n-\t\tx = xmalloc(sizeof(*x) + patternlen + 1);\n-\t\ts = (char *)(x+1);\n-\t\tmemcpy(s, string, patternlen);\n-\t\ts[patternlen] = '\\0';\n-\t\tx->pattern = s;\n+\t\tFLEXPTR_ALLOC_MEM(x, pattern, string, patternlen);\n \t} else {\n \t\tx = xmalloc(sizeof(*x));\n \t\tx->pattern = string;\n@@ -625,10 +620,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,\n \t}\n \n \tuc->dir_created++;\n-\td = xmalloc(sizeof(*d) + len + 1);\n-\tmemset(d, 0, sizeof(*d));\n-\tmemcpy(d->name, name, len);\n-\td->name[len] = '\\0';\n+\tFLEX_ALLOC_MEM(d, name, name, len);\n \n \tALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);\n \tmemmove(dir->dirs + first + 1, dir->dirs + first,\n@@ -1167,10 +1159,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)\n {\n \tstruct dir_entry *ent;\n \n-\tent = xmalloc(sizeof(*ent) + len + 1);\n+\tFLEX_ALLOC_MEM(ent, name, pathname, len);\n \tent->len = len;\n-\tmemcpy(ent->name, pathname, len);\n-\tent->name[len] = 0;\n \treturn ent;\n }\n \ndiff --git a/hashmap.c b/hashmap.c\nindex f693839..b10b642 100644\n--- a/hashmap.c\n+++ b/hashmap.c\n@@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len)\n \te = hashmap_get(&map, &key, data);\n \tif (!e) {\n \t\t/* not found: create it */\n-\t\te = xmallocz(sizeof(struct pool_entry) + len);\n+\t\tFLEX_ALLOC_MEM(e, data, data, len);\n \t\thashmap_entry_init(e, key.ent.hash);\n \t\te->len = len;\n-\t\tmemcpy(e->data, data, len);\n \t\thashmap_add(&map, e);\n \t}\n \treturn e->data;\ndiff --git a/help.c b/help.c\nindex d996b34..19328ea 100644\n--- a/help.c\n+++ b/help.c\n@@ -11,11 +11,9 @@\n \n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n-\tstruct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);\n-\n+\tstruct cmdname *ent;\n+\tFLEX_ALLOC_MEM(ent, name, name, len);\n \tent->len = len;\n-\tmemcpy(ent->name, name, len);\n-\tent->name[len] = 0;\n \n \tALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);\n \tcmds->names[cmds->cnt++] = ent;\ndiff --git a/log-tree.c b/log-tree.c\nindex f70a30e..60f9839 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -77,9 +77,8 @@ int parse_decorate_color_config(const char *var, const char *slot_name, const ch\n \n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)\n {\n-\tint nlen = strlen(name);\n-\tstruct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);\n-\tmemcpy(res->name, name, nlen + 1);\n+\tstruct name_decoration *res;\n+\tFLEX_ALLOC_STR(res, name, name);\n \tres->type = type;\n \tres->next = add_decoration(&name_decoration, obj, res);\n }\ndiff --git a/name-hash.c b/name-hash.c\nindex 332ba95..6d9f23e 100644\n--- a/name-hash.c\n+++ b/name-hash.c\n@@ -55,10 +55,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,\n \tdir = find_dir_entry(istate, ce->name, namelen);\n \tif (!dir) {\n \t\t/* not found, create it and add to hash table */\n-\t\tdir = xcalloc(1, sizeof(struct dir_entry) + namelen + 1);\n+\t\tFLEX_ALLOC_MEM(dir, name, ce->name, namelen);\n \t\thashmap_entry_init(dir, memihash(ce->name, namelen));\n \t\tdir->namelen = namelen;\n-\t\tstrncpy(dir->name, ce->name, namelen);\n \t\thashmap_add(&istate->dir_hash, dir);\n \n \t\t/* recursively add missing parent directories */\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f097176..9ccfc51 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1255,10 +1255,8 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \t\t\t\t\t\t const unsigned char *objectname,\n \t\t\t\t\t\t int flag)\n {\n-\tsize_t len = strlen(refname);\n-\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n-\tmemcpy(ref->refname, refname, len);\n-\tref->refname[len] = '\\0';\n+\tstruct ref_array_item *ref;\n+\tFLEX_ALLOC_STR(ref, refname, refname);\n \thashcpy(ref->objectname, objectname);\n \tref->flag = flag;\n \ndiff --git a/refs.c b/refs.c\nindex 1d9e2a7..2d86445 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -761,10 +761,8 @@ void ref_transaction_free(struct ref_transaction *transaction)\n static struct ref_update *add_update(struct ref_transaction *transaction,\n \t\t\t\t     const char *refname)\n {\n-\tsize_t len = strlen(refname) + 1;\n-\tstruct ref_update *update = xcalloc(1, sizeof(*update) + len);\n-\n-\tmemcpy((char *)update->refname, refname, len); /* includes NUL */\n+\tstruct ref_update *update;\n+\tFLEX_ALLOC_STR(update, refname, refname);\n \tALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);\n \ttransaction->updates[transaction->nr++] = update;\n \treturn update;\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex b569762..81f68f8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -199,17 +199,14 @@ static struct ref_entry *create_ref_entry(const char *refname,\n \t\t\t\t\t  const unsigned char *sha1, int flag,\n \t\t\t\t\t  int check_name)\n {\n-\tint len;\n \tstruct ref_entry *ref;\n \n \tif (check_name &&\n \t    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))\n \t\tdie(\"Reference has invalid format: '%s'\", refname);\n-\tlen = strlen(refname) + 1;\n-\tref = xmalloc(sizeof(struct ref_entry) + len);\n+\tFLEX_ALLOC_STR(ref, name, refname);\n \thashcpy(ref->u.value.oid.hash, sha1);\n \toidclr(&ref->u.value.peeled);\n-\tmemcpy(ref->name, refname, len);\n \tref->flag = flag;\n \treturn ref;\n }\n@@ -268,9 +265,7 @@ static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n \t\t\t\t\t  int incomplete)\n {\n \tstruct ref_entry *direntry;\n-\tdirentry = xcalloc(1, sizeof(struct ref_entry) + len + 1);\n-\tmemcpy(direntry->name, dirname, len);\n-\tdirentry->name[len] = '\\0';\n+\tFLEX_ALLOC_MEM(direntry, name, dirname, len);\n \tdirentry->u.subdir.ref_cache = ref_cache;\n \tdirentry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);\n \treturn direntry;\n@@ -939,13 +934,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)\n  */\n static struct ref_cache *create_ref_cache(const char *submodule)\n {\n-\tint len;\n \tstruct ref_cache *refs;\n \tif (!submodule)\n \t\tsubmodule = \"\";\n-\tlen = strlen(submodule) + 1;\n-\trefs = xcalloc(1, sizeof(struct ref_cache) + len);\n-\tmemcpy(refs->name, submodule, len);\n+\tFLEX_ALLOC_STR(refs, name, submodule);\n \trefs->next = submodule_ref_caches;\n \tsubmodule_ref_caches = refs;\n \treturn refs;\n@@ -2197,10 +2189,9 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)\n \n \t/* Schedule the loose reference for pruning if requested. */\n \tif ((cb->flags & PACK_REFS_PRUNE)) {\n-\t\tint namelen = strlen(entry->name) + 1;\n-\t\tstruct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);\n+\t\tstruct ref_to_prune *n;\n+\t\tFLEX_ALLOC_STR(n, name, entry->name);\n \t\thashcpy(n->sha1, entry->u.value.oid.hash);\n-\t\tmemcpy(n->name, entry->name, namelen); /* includes NUL */\n \t\tn->next = cb->ref_to_prune;\n \t\tcb->ref_to_prune = n;\n \t}\ndiff --git a/remote.c b/remote.c\nindex 02e698a..25a960f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -2136,16 +2136,13 @@ static int one_local_ref(const char *refname, const struct object_id *oid,\n {\n \tstruct ref ***local_tail = cb_data;\n \tstruct ref *ref;\n-\tint len;\n \n \t/* we already know it starts with refs/ to get here */\n \tif (check_refname_format(refname + 5, 0))\n \t\treturn 0;\n \n-\tlen = strlen(refname) + 1;\n-\tref = xcalloc(1, sizeof(*ref) + len);\n+\tref = alloc_ref(refname);\n \toidcpy(&ref->new_oid, oid);\n-\tmemcpy(ref->name, refname, len);\n \t**local_tail = ref;\n \t*local_tail = &ref->next;\n \treturn 0;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278931","messageId":"20160222224435.GK10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 11/22] use st_add and st_mult for allocation size computation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:35Z","receivedAt":"2016-02-22T22:44:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"If our size computation overflows size_t, we may allocate a\nmuch smaller buffer than we expected and overflow it. It's\nprobably impossible to trigger an overflow in most of these\nsites in practice, but it is easy enough convert their\nadditions and multiplications into overflow-checking\nvariants. This may be fixing real bugs, and it makes\nauditing the code easier.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n archive.c              |  4 ++--\n builtin/apply.c        |  2 +-\n builtin/clean.c        |  2 +-\n builtin/fetch.c        |  2 +-\n builtin/index-pack.c   |  4 ++--\n builtin/merge.c        |  2 +-\n builtin/mv.c           |  4 ++--\n builtin/receive-pack.c |  2 +-\n combine-diff.c         | 14 +++++++-------\n commit.c               |  2 +-\n compat/mingw.c         |  4 ++--\n compat/qsort.c         |  2 +-\n compat/setenv.c        |  2 +-\n compat/win32/syslog.c  |  4 ++--\n diffcore-delta.c       |  6 ++++--\n diffcore-rename.c      |  2 +-\n dir.c                  |  4 ++--\n fast-import.c          |  2 +-\n refs.c                 |  2 +-\n remote.c               |  8 ++++----\n revision.c             |  2 +-\n sha1_file.c            | 20 +++++++++++---------\n sha1_name.c            |  5 ++---\n shallow.c              |  2 +-\n submodule.c            |  6 +++---\n 25 files changed, 56 insertions(+), 53 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 0687afa..5d735ae 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -171,8 +171,8 @@ static void queue_directory(const unsigned char *sha1,\n \t\tunsigned mode, int stage, struct archiver_context *c)\n {\n \tstruct directory *d;\n-\tsize_t len = base->len + 1 + strlen(filename) + 1;\n-\td = xmalloc(sizeof(*d) + len);\n+\tsize_t len = st_add4(base->len, 1, strlen(filename), 1);\n+\td = xmalloc(st_add(sizeof(*d), len));\n \td->up\t   = c->bottom;\n \td->baselen = base->len;\n \td->mode\t   = mode;\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex d61ac65..42c610e 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -2632,7 +2632,7 @@ static void update_image(struct image *img,\n \tinsert_count = postimage->len;\n \n \t/* Adjust the contents */\n-\tresult = xmalloc(img->len + insert_count - remove_count + 1);\n+\tresult = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));\n \tmemcpy(result, img->buf, applied_at);\n \tmemcpy(result + applied_at, postimage->buf, postimage->len);\n \tmemcpy(result + applied_at + postimage->len,\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 8229f7e..0371010 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -615,7 +615,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t\tnr += chosen[i];\n \t\t}\n \n-\t\tresult = xcalloc(nr + 1, sizeof(int));\n+\t\tresult = xcalloc(st_add(nr, 1), sizeof(int));\n \t\tfor (i = 0; i < stuff->nr && j < nr; i++) {\n \t\t\tif (chosen[i])\n \t\t\t\tresult[j++] = i;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8e74213..373a89d 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -1110,7 +1110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)\n \tif (argc > 0) {\n \t\tint j = 0;\n \t\tint i;\n-\t\trefs = xcalloc(argc + 1, sizeof(const char *));\n+\t\trefs = xcalloc(st_add(argc, 1), sizeof(const char *));\n \t\tfor (i = 0; i < argc; i++) {\n \t\t\tif (!strcmp(argv[i], \"tag\")) {\n \t\t\t\ti++;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex a60bcfa..193908a 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1744,9 +1744,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \n \tcurr_pack = open_pack_file(pack_name);\n \tparse_pack_header();\n-\tobjects = xcalloc(nr_objects + 1, sizeof(struct object_entry));\n+\tobjects = xcalloc(st_add(nr_objects, 1), sizeof(struct object_entry));\n \tif (show_stat)\n-\t\tobj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat));\n+\t\tobj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));\n \tofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));\n \tparse_pack_objects(pack_sha1);\n \tresolve_deltas();\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex b98a348..101ffef 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -939,7 +939,7 @@ static int setup_with_upstream(const char ***argv)\n \tif (!branch->merge_nr)\n \t\tdie(_(\"No default upstream defined for the current branch.\"));\n \n-\targs = xcalloc(branch->merge_nr + 1, sizeof(char *));\n+\targs = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));\n \tfor (i = 0; i < branch->merge_nr; i++) {\n \t\tif (!branch->merge[i]->dst)\n \t\t\tdie(_(\"No remote-tracking branch for %s from %s\"),\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 9a9813a..aeae855 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -48,9 +48,9 @@ static const char **internal_copy_pathspec(const char *prefix,\n \n static const char *add_slash(const char *path)\n {\n-\tint len = strlen(path);\n+\tsize_t len = strlen(path);\n \tif (path[len - 1] != '/') {\n-\t\tchar *with_slash = xmalloc(len + 2);\n+\t\tchar *with_slash = xmalloc(st_add(len, 2));\n \t\tmemcpy(with_slash, path, len);\n \t\twith_slash[len++] = '/';\n \t\twith_slash[len] = 0;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 3dc3868..c8e32b2 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -1372,7 +1372,7 @@ static struct command **queue_command(struct command **tail,\n \n \trefname = line + 82;\n \treflen = linelen - 82;\n-\tcmd = xcalloc(1, sizeof(struct command) + reflen + 1);\n+\tcmd = xcalloc(1, st_add3(sizeof(struct command), reflen, 1));\n \thashcpy(cmd->old_sha1, old_sha1);\n \thashcpy(cmd->new_sha1, new_sha1);\n \tmemcpy(cmd->ref_name, refname, reflen);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex be09a2b..0e1d4b0 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -189,11 +189,11 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,\n \t *   - Else if we have NEW, insert newend lline into base and\n \t *   consume newend\n \t */\n-\tlcs = xcalloc(origbaselen + 1, sizeof(int*));\n-\tdirections = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));\n+\tlcs = xcalloc(st_add(origbaselen, 1), sizeof(int*));\n+\tdirections = xcalloc(st_add(origbaselen, 1), sizeof(enum coalesce_direction*));\n \tfor (i = 0; i < origbaselen + 1; i++) {\n-\t\tlcs[i] = xcalloc(lennew + 1, sizeof(int));\n-\t\tdirections[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));\n+\t\tlcs[i] = xcalloc(st_add(lennew, 1), sizeof(int));\n+\t\tdirections[i] = xcalloc(st_add(lennew, 1), sizeof(enum coalesce_direction));\n \t\tdirections[i][0] = BASE;\n \t}\n \tfor (j = 1; j < lennew + 1; j++)\n@@ -1111,7 +1111,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \tif (result_size && result[result_size-1] != '\\n')\n \t\tcnt++; /* incomplete line */\n \n-\tsline = xcalloc(cnt+2, sizeof(*sline));\n+\tsline = xcalloc(st_add(cnt, 2), sizeof(*sline));\n \tsline[0].bol = result;\n \tfor (lno = 0, cp = result; cp < result + result_size; cp++) {\n \t\tif (*cp == '\\n') {\n@@ -1130,7 +1130,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t/* Even p_lno[cnt+1] is valid -- that is for the end line number\n \t * for deletion hunk at the end.\n \t */\n-\tsline[0].p_lno = xcalloc((cnt+2) * num_parent, sizeof(unsigned long));\n+\tsline[0].p_lno = xcalloc(st_mult(st_add(cnt, 2), num_parent), sizeof(unsigned long));\n \tfor (lno = 0; lno <= cnt; lno++)\n \t\tsline[lno+1].p_lno = sline[lno].p_lno + num_parent;\n \n@@ -1262,7 +1262,7 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p,\n \tstruct diff_filespec *pool;\n \n \tpair = xmalloc(sizeof(*pair));\n-\tpool = xcalloc(num_parent + 1, sizeof(struct diff_filespec));\n+\tpool = xcalloc(st_add(num_parent, 1), sizeof(struct diff_filespec));\n \tpair->one = pool + 1;\n \tpair->two = pool;\n \ndiff --git a/commit.c b/commit.c\nindex 31cd91f..3f4f371 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -147,7 +147,7 @@ struct commit_graft *read_graft_line(char *buf, int len)\n \tif ((len + 1) % entry_size)\n \t\tgoto bad_graft_data;\n \ti = (len + 1) / entry_size - 1;\n-\tgraft = xmalloc(sizeof(*graft) + GIT_SHA1_RAWSZ * i);\n+\tgraft = xmalloc(st_add(sizeof(*graft), st_mult(GIT_SHA1_RAWSZ, i)));\n \tgraft->nr_parent = i;\n \tif (get_oid_hex(buf, &graft->oid))\n \t\tgoto bad_graft_data;\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 7803f30..cfedcf9 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -810,7 +810,7 @@ static const char *quote_arg(const char *arg)\n \t\treturn arg;\n \n \t/* insert \\ where necessary */\n-\td = q = xmalloc(len+n+3);\n+\td = q = xmalloc(st_add3(len, n, 3));\n \t*d++ = '\"';\n \twhile (*arg) {\n \t\tif (*arg == '\"')\n@@ -1069,7 +1069,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen\n \t\t\tfree(quoted);\n \t}\n \n-\twargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));\n+\twargs = xmalloc_array(st_add(st_mult(2, args.len), 1), sizeof(wchar_t));\n \txutftowcs(wargs, args.buf, 2 * args.len + 1);\n \tstrbuf_release(&args);\n \ndiff --git a/compat/qsort.c b/compat/qsort.c\nindex 9574d53..7d071af 100644\n--- a/compat/qsort.c\n+++ b/compat/qsort.c\n@@ -47,7 +47,7 @@ static void msort_with_tmp(void *b, size_t n, size_t s,\n void git_qsort(void *b, size_t n, size_t s,\n \t       int (*cmp)(const void *, const void *))\n {\n-\tconst size_t size = n * s;\n+\tconst size_t size = st_mult(n, s);\n \tchar buf[1024];\n \n \tif (size < sizeof(buf)) {\ndiff --git a/compat/setenv.c b/compat/setenv.c\nindex fc1439a..7849f25 100644\n--- a/compat/setenv.c\n+++ b/compat/setenv.c\n@@ -18,7 +18,7 @@ int gitsetenv(const char *name, const char *value, int replace)\n \n \tnamelen = strlen(name);\n \tvaluelen = strlen(value);\n-\tenvstr = malloc((namelen + valuelen + 2));\n+\tenvstr = malloc(st_add3(namelen, valuelen, 2));\n \tif (!envstr) {\n \t\terrno = ENOMEM;\n \t\treturn -1;\ndiff --git a/compat/win32/syslog.c b/compat/win32/syslog.c\nindex d015e43..b905aea 100644\n--- a/compat/win32/syslog.c\n+++ b/compat/win32/syslog.c\n@@ -32,7 +32,7 @@ void syslog(int priority, const char *fmt, ...)\n \t\treturn;\n \t}\n \n-\tstr = malloc(str_len + 1);\n+\tstr = malloc(st_add(str_len, 1));\n \tif (!str) {\n \t\twarning(\"malloc failed: '%s'\", strerror(errno));\n \t\treturn;\n@@ -43,7 +43,7 @@ void syslog(int priority, const char *fmt, ...)\n \tva_end(ap);\n \n \twhile ((pos = strstr(str, \"%1\")) != NULL) {\n-\t\tstr = realloc(str, ++str_len + 1);\n+\t\tstr = realloc(str, st_add(++str_len, 1));\n \t\tif (!str) {\n \t\t\twarning(\"realloc failed: '%s'\", strerror(errno));\n \t\t\treturn;\ndiff --git a/diffcore-delta.c b/diffcore-delta.c\nindex 7cf431d..4159748 100644\n--- a/diffcore-delta.c\n+++ b/diffcore-delta.c\n@@ -53,7 +53,8 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)\n \tint osz = 1 << orig->alloc_log2;\n \tint sz = osz << 1;\n \n-\tnew = xmalloc(sizeof(*orig) + sizeof(struct spanhash) * sz);\n+\tnew = xmalloc(st_add(sizeof(*orig),\n+\t\t\t     st_mult(sizeof(struct spanhash), sz)));\n \tnew->alloc_log2 = orig->alloc_log2 + 1;\n \tnew->free = INITIAL_FREE(new->alloc_log2);\n \tmemset(new->data, 0, sizeof(struct spanhash) * sz);\n@@ -130,7 +131,8 @@ static struct spanhash_top *hash_chars(struct diff_filespec *one)\n \tint is_text = !diff_filespec_is_binary(one);\n \n \ti = INITIAL_HASH_SIZE;\n-\thash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i));\n+\thash = xmalloc(st_add(sizeof(*hash),\n+\t\t\t      st_mult(sizeof(struct spanhash), 1<<i)));\n \thash->alloc_log2 = i;\n \thash->free = INITIAL_FREE(i);\n \tmemset(hash->data, 0, sizeof(struct spanhash) * (1<<i));\ndiff --git a/diffcore-rename.c b/diffcore-rename.c\nindex af1fe08..3b3c1ed 100644\n--- a/diffcore-rename.c\n+++ b/diffcore-rename.c\n@@ -537,7 +537,7 @@ void diffcore_rename(struct diff_options *options)\n \t\t\t\trename_dst_nr * rename_src_nr, 50, 1);\n \t}\n \n-\tmx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));\n+\tmx = xcalloc(st_mult(num_create, NUM_CANDIDATE_PER_DST), sizeof(*mx));\n \tfor (dst_cnt = i = 0; i < rename_dst_nr; i++) {\n \t\tstruct diff_filespec *two = rename_dst[i].two;\n \t\tstruct diff_score *m;\ndiff --git a/dir.c b/dir.c\nindex f06ebb7..2c91541 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -689,7 +689,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,\n \t\t\treturn 0;\n \t\t}\n \t\tif (buf[size-1] != '\\n') {\n-\t\t\tbuf = xrealloc(buf, size+1);\n+\t\t\tbuf = xrealloc(buf, st_add(size, 1));\n \t\t\tbuf[size++] = '\\n';\n \t\t}\n \t} else {\n@@ -2488,7 +2488,7 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,\n \tnext = data + len + 1;\n \tif (next > rd->end)\n \t\treturn -1;\n-\t*untracked_ = untracked = xmalloc(sizeof(*untracked) + len);\n+\t*untracked_ = untracked = xmalloc(st_add(sizeof(*untracked), len));\n \tmemcpy(untracked, &ud, sizeof(ud));\n \tmemcpy(untracked->name, data, len + 1);\n \tdata = next;\ndiff --git a/fast-import.c b/fast-import.c\nindex a6467cb..3053bb8 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -622,7 +622,7 @@ static void *pool_alloc(size_t len)\n \t\t\treturn xmalloc(len);\n \t\t}\n \t\ttotal_allocd += sizeof(struct mem_pool) + mem_pool_alloc;\n-\t\tp = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc);\n+\t\tp = xmalloc(st_add(sizeof(struct mem_pool), mem_pool_alloc));\n \t\tp->next_pool = mem_pool;\n \t\tp->next_free = (char *) p->space;\n \t\tp->end = p->next_free + mem_pool_alloc;\ndiff --git a/refs.c b/refs.c\nindex 2d86445..b0e6ece 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -906,7 +906,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)\n \t\t\t/* -2 for strlen(\"%.*s\") - strlen(\"%s\"); +1 for NUL */\n \t\t\ttotal_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;\n \n-\t\tscanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);\n+\t\tscanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len));\n \n \t\toffset = 0;\n \t\tfor (i = 0; i < nr_rules; i++) {\ndiff --git a/remote.c b/remote.c\nindex 25a960f..21e4ec3 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -931,7 +931,7 @@ static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,\n \t\tconst char *name)\n {\n \tsize_t len = strlen(name);\n-\tstruct ref *ref = xcalloc(1, sizeof(struct ref) + prefixlen + len + 1);\n+\tstruct ref *ref = xcalloc(1, st_add4(sizeof(*ref), prefixlen, len, 1));\n \tmemcpy(ref->name, prefix, prefixlen);\n \tmemcpy(ref->name + prefixlen, name, len);\n \treturn ref;\n@@ -948,9 +948,9 @@ struct ref *copy_ref(const struct ref *ref)\n \tsize_t len;\n \tif (!ref)\n \t\treturn NULL;\n-\tlen = strlen(ref->name);\n-\tcpy = xmalloc(sizeof(struct ref) + len + 1);\n-\tmemcpy(cpy, ref, sizeof(struct ref) + len + 1);\n+\tlen = st_add3(sizeof(struct ref), strlen(ref->name), 1);\n+\tcpy = xmalloc(len);\n+\tmemcpy(cpy, ref, len);\n \tcpy->next = NULL;\n \tcpy->symref = xstrdup_or_null(ref->symref);\n \tcpy->remote_status = xstrdup_or_null(ref->remote_status);\ndiff --git a/revision.c b/revision.c\nindex f24ead5..d4ace60 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -540,7 +540,7 @@ struct treesame_state {\n static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)\n {\n \tunsigned n = commit_list_count(commit->parents);\n-\tstruct treesame_state *st = xcalloc(1, sizeof(*st) + n);\n+\tstruct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n));\n \tst->nparents = n;\n \tadd_decoration(&revs->treesame, &commit->object, st);\n \treturn st;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 2f1c6d3..0251700 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -253,7 +253,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,\n {\n \tstruct alternate_object_database *ent;\n \tstruct alternate_object_database *alt;\n-\tint pfxlen, entlen;\n+\tsize_t pfxlen, entlen;\n \tstruct strbuf pathbuf = STRBUF_INIT;\n \n \tif (!is_absolute_path(entry) && relative_base) {\n@@ -273,8 +273,8 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,\n \twhile (pfxlen && pathbuf.buf[pfxlen-1] == '/')\n \t\tpfxlen -= 1;\n \n-\tentlen = pfxlen + 43; /* '/' + 2 hex + '/' + 38 hex + NUL */\n-\tent = xmalloc(sizeof(*ent) + entlen);\n+\tentlen = st_add(pfxlen, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */\n+\tent = xmalloc(st_add(sizeof(*ent), entlen));\n \tmemcpy(ent->base, pathbuf.buf, pfxlen);\n \tstrbuf_release(&pathbuf);\n \n@@ -1134,7 +1134,7 @@ unsigned char *use_pack(struct packed_git *p,\n \n static struct packed_git *alloc_packed_git(int extra)\n {\n-\tstruct packed_git *p = xmalloc(sizeof(*p) + extra);\n+\tstruct packed_git *p = xmalloc(st_add(sizeof(*p), extra));\n \tmemset(p, 0, sizeof(*p));\n \tp->pack_fd = -1;\n \treturn p;\n@@ -1168,7 +1168,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)\n \t * \".pack\" is long enough to hold any suffix we're adding (and\n \t * the use xsnprintf double-checks that)\n \t */\n-\talloc = path_len + strlen(\".pack\") + 1;\n+\talloc = st_add3(path_len, strlen(\".pack\"), 1);\n \tp = alloc_packed_git(alloc);\n \tmemcpy(p->pack_name, path, path_len);\n \n@@ -1196,7 +1196,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)\n struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)\n {\n \tconst char *path = sha1_pack_name(sha1);\n-\tint alloc = strlen(path) + 1;\n+\tsize_t alloc = st_add(strlen(path), 1);\n \tstruct packed_git *p = alloc_packed_git(alloc);\n \n \tmemcpy(p->pack_name, path, alloc); /* includes NUL */\n@@ -1413,10 +1413,12 @@ static void mark_bad_packed_object(struct packed_git *p,\n {\n \tunsigned i;\n \tfor (i = 0; i < p->num_bad_objects; i++)\n-\t\tif (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))\n+\t\tif (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i))\n \t\t\treturn;\n-\tp->bad_object_sha1 = xrealloc(p->bad_object_sha1, 20 * (p->num_bad_objects + 1));\n-\thashcpy(p->bad_object_sha1 + 20 * p->num_bad_objects, sha1);\n+\tp->bad_object_sha1 = xrealloc(p->bad_object_sha1,\n+\t\t\t\t      st_mult(GIT_SHA1_RAWSZ,\n+\t\t\t\t\t      st_add(p->num_bad_objects, 1)));\n+\thashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1);\n \tp->num_bad_objects++;\n }\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex 89918ca..d14346c 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -87,9 +87,8 @@ static void find_short_object_filename(int len, const char *hex_pfx, struct disa\n \t\t * object databases including our own.\n \t\t */\n \t\tconst char *objdir = get_object_directory();\n-\t\tint objdir_len = strlen(objdir);\n-\t\tint entlen = objdir_len + 43;\n-\t\tfakeent = xmalloc(sizeof(*fakeent) + entlen);\n+\t\tsize_t objdir_len = strlen(objdir);\n+\t\tfakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43));\n \t\tmemcpy(fakeent->base, objdir, objdir_len);\n \t\tfakeent->name = fakeent->base + objdir_len + 1;\n \t\tfakeent->name[-1] = '/';\ndiff --git a/shallow.c b/shallow.c\nindex 71163bf..4d554ca 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -389,7 +389,7 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,\n \tunsigned int i, nr;\n \tstruct commit_list *head = NULL;\n \tint bitmap_nr = (info->nr_bits + 31) / 32;\n-\tint bitmap_size = bitmap_nr * sizeof(uint32_t);\n+\tsize_t bitmap_size = st_mult(bitmap_nr, sizeof(uint32_t));\n \tuint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */\n \tuint32_t *bitmap = paint_alloc(info);\n \tstruct commit *c = lookup_commit_reference_gently(sha1, 1);\ndiff --git a/submodule.c b/submodule.c\nindex b83939c..ac61c65 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -123,7 +123,7 @@ static int add_submodule_odb(const char *path)\n \tstruct strbuf objects_directory = STRBUF_INIT;\n \tstruct alternate_object_database *alt_odb;\n \tint ret = 0;\n-\tint alloc;\n+\tsize_t alloc;\n \n \tstrbuf_git_path_submodule(&objects_directory, path, \"objects/\");\n \tif (!is_directory(objects_directory.buf)) {\n@@ -138,8 +138,8 @@ static int add_submodule_odb(const char *path)\n \t\t\t\t\tobjects_directory.len))\n \t\t\tgoto done;\n \n-\talloc = objects_directory.len + 42; /* for \"12/345...\" sha1 */\n-\talt_odb = xmalloc(sizeof(*alt_odb) + alloc);\n+\talloc = st_add(objects_directory.len, 42); /* for \"12/345...\" sha1 */\n+\talt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc));\n \talt_odb->next = alt_odb_list;\n \txsnprintf(alt_odb->base, alloc, \"%s\", objects_directory.buf);\n \talt_odb->name = alt_odb->base + objects_directory.len;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278933","messageId":"20160222224439.GL10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 12/22] prepare_{git,shell}_cmd: use argv_array","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:39Z","receivedAt":"2016-02-22T22:44:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"These functions transform an existing argv into one suitable\nfor exec-ing or spawning via git or a shell. We can use an\nargv_array in each to avoid dealing with manual counting and\nallocation.\n\nThis also makes the memory allocation more clear and fixes\nsome leaks. In prepare_shell_cmd, we would sometimes\nallocate a new string with \"$@\" in it and sometimes not,\nmeaning the caller could not correctly free it. On the\nnon-Windows side, we are in a child process which will\nexec() or exit() immediately, so the leak isn't a big deal.\nOn Windows, though, we use spawn() from the parent process,\nand leak a string for each shell command we run. On top of\nthat, the Windows code did not free the allocated argv array\nat all (but does for the prepare_git_cmd case!).\n\nBy switching both of these functions to write into an\nargv_array, we can consistently free the result as\nappropriate.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n exec_cmd.c    | 28 +++++++++++-----------------\n exec_cmd.h    |  4 +++-\n run-command.c | 60 +++++++++++++++++++++++++----------------------------------\n 3 files changed, 39 insertions(+), 53 deletions(-)\n\ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex e85f0fd..cf442a9 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"exec_cmd.h\"\n #include \"quote.h\"\n+#include \"argv-array.h\"\n #define MAX_ARGS\t32\n \n static const char *argv_exec_path;\n@@ -107,32 +108,25 @@ void setup_path(void)\n \tstrbuf_release(&new_path);\n }\n \n-const char **prepare_git_cmd(const char **argv)\n+const char **prepare_git_cmd(struct argv_array *out, const char **argv)\n {\n-\tint argc;\n-\tconst char **nargv;\n-\n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\t; /* just counting */\n-\tnargv = xmalloc(sizeof(*nargv) * (argc + 2));\n-\n-\tnargv[0] = \"git\";\n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\tnargv[argc + 1] = argv[argc];\n-\tnargv[argc + 1] = NULL;\n-\treturn nargv;\n+\targv_array_push(out, \"git\");\n+\targv_array_pushv(out, argv);\n+\treturn out->argv;\n }\n \n int execv_git_cmd(const char **argv) {\n-\tconst char **nargv = prepare_git_cmd(argv);\n-\ttrace_argv_printf(nargv, \"trace: exec:\");\n+\tstruct argv_array nargv = ARGV_ARRAY_INIT;\n+\n+\tprepare_git_cmd(&nargv, argv);\n+\ttrace_argv_printf(nargv.argv, \"trace: exec:\");\n \n \t/* execvp() can only ever return if it fails */\n-\tsane_execvp(\"git\", (char **)nargv);\n+\tsane_execvp(\"git\", (char **)nargv.argv);\n \n \ttrace_printf(\"trace: exec failed: %s\\n\", strerror(errno));\n \n-\tfree(nargv);\n+\targv_array_clear(&nargv);\n \treturn -1;\n }\n \ndiff --git a/exec_cmd.h b/exec_cmd.h\nindex 93b0c02..1f6b433 100644\n--- a/exec_cmd.h\n+++ b/exec_cmd.h\n@@ -1,11 +1,13 @@\n #ifndef GIT_EXEC_CMD_H\n #define GIT_EXEC_CMD_H\n \n+struct argv_array;\n+\n extern void git_set_argv_exec_path(const char *exec_path);\n extern const char *git_extract_argv0_path(const char *path);\n extern const char *git_exec_path(void);\n extern void setup_path(void);\n-extern const char **prepare_git_cmd(const char **argv);\n+extern const char **prepare_git_cmd(struct argv_array *out, const char **argv);\n extern int execv_git_cmd(const char **argv); /* NULL terminated */\n LAST_ARG_MUST_BE_NULL\n extern int execl_git_cmd(const char *cmd, ...);\ndiff --git a/run-command.c b/run-command.c\nindex cdf0184..019f6d1 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -160,50 +160,41 @@ int sane_execvp(const char *file, char * const argv[])\n \treturn -1;\n }\n \n-static const char **prepare_shell_cmd(const char **argv)\n+static const char **prepare_shell_cmd(struct argv_array *out, const char **argv)\n {\n-\tint argc, nargc = 0;\n-\tconst char **nargv;\n-\n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\t; /* just counting */\n-\t/* +1 for NULL, +3 for \"sh -c\" plus extra $0 */\n-\tnargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));\n-\n-\tif (argc < 1)\n+\tif (!argv[0])\n \t\tdie(\"BUG: shell command is empty\");\n \n \tif (strcspn(argv[0], \"|&;<>()$`\\\\\\\"' \\t\\n*?[#~=%\") != strlen(argv[0])) {\n #ifndef GIT_WINDOWS_NATIVE\n-\t\tnargv[nargc++] = SHELL_PATH;\n+\t\targv_array_push(out, SHELL_PATH);\n #else\n-\t\tnargv[nargc++] = \"sh\";\n+\t\targv_array_push(out, \"sh\");\n #endif\n-\t\tnargv[nargc++] = \"-c\";\n-\n-\t\tif (argc < 2)\n-\t\t\tnargv[nargc++] = argv[0];\n-\t\telse {\n-\t\t\tstruct strbuf arg0 = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&arg0, \"%s \\\"$@\\\"\", argv[0]);\n-\t\t\tnargv[nargc++] = strbuf_detach(&arg0, NULL);\n-\t\t}\n-\t}\n+\t\targv_array_push(out, \"-c\");\n \n-\tfor (argc = 0; argv[argc]; argc++)\n-\t\tnargv[nargc++] = argv[argc];\n-\tnargv[nargc] = NULL;\n+\t\t/*\n+\t\t * If we have no extra arguments, we do not even need to\n+\t\t * bother with the \"$@\" magic.\n+\t\t */\n+\t\tif (!argv[1])\n+\t\t\targv_array_push(out, argv[0]);\n+\t\telse\n+\t\t\targv_array_pushf(out, \"%s \\\"$@\\\"\", argv[0]);\n+\t}\n \n-\treturn nargv;\n+\targv_array_pushv(out, argv);\n+\treturn out->argv;\n }\n \n #ifndef GIT_WINDOWS_NATIVE\n static int execv_shell_cmd(const char **argv)\n {\n-\tconst char **nargv = prepare_shell_cmd(argv);\n-\ttrace_argv_printf(nargv, \"trace: exec:\");\n-\tsane_execvp(nargv[0], (char **)nargv);\n-\tfree(nargv);\n+\tstruct argv_array nargv = ARGV_ARRAY_INIT;\n+\tprepare_shell_cmd(&nargv, argv);\n+\ttrace_argv_printf(nargv.argv, \"trace: exec:\");\n+\tsane_execvp(nargv.argv[0], (char **)nargv.argv);\n+\targv_array_clear(&nargv);\n \treturn -1;\n }\n #endif\n@@ -457,6 +448,7 @@ fail_pipe:\n {\n \tint fhin = 0, fhout = 1, fherr = 2;\n \tconst char **sargv = cmd->argv;\n+\tstruct argv_array nargv = ARGV_ARRAY_INIT;\n \n \tif (cmd->no_stdin)\n \t\tfhin = open(\"/dev/null\", O_RDWR);\n@@ -482,9 +474,9 @@ fail_pipe:\n \t\tfhout = dup(cmd->out);\n \n \tif (cmd->git_cmd)\n-\t\tcmd->argv = prepare_git_cmd(cmd->argv);\n+\t\tcmd->argv = prepare_git_cmd(&nargv, cmd->argv);\n \telse if (cmd->use_shell)\n-\t\tcmd->argv = prepare_shell_cmd(cmd->argv);\n+\t\tcmd->argv = prepare_shell_cmd(&nargv, cmd->argv);\n \n \tcmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,\n \t\t\tcmd->dir, fhin, fhout, fherr);\n@@ -494,9 +486,7 @@ fail_pipe:\n \tif (cmd->clean_on_exit && cmd->pid >= 0)\n \t\tmark_child_for_cleanup(cmd->pid);\n \n-\tif (cmd->git_cmd)\n-\t\tfree(cmd->argv);\n-\n+\targv_array_clear(&nargv);\n \tcmd->argv = sargv;\n \tif (fhin != 0)\n \t\tclose(fhin);\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278934","messageId":"20160222224442.GM10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 13/22] write_untracked_extension: use FLEX_ALLOC helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:42Z","receivedAt":"2016-02-22T22:44:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We perform unchecked additions when computing the size of a\n\"struct ondisk_untracked_cache\". This is unlikely to have an\ninteger overflow in practice, but we'd like to avoid this\ndangerous pattern to make further audits easier.\n\nNote that there's one subtlety here, though.  We protect\nourselves against a NULL exclude_per_dir entry in our\nsource, and avoid calling strlen() on it, keeping \"len\" at\n0. But later, we unconditionally memcpy \"len + 1\" bytes to\nget the trailing NUL byte. If we did have a NULL\nexclude_per_dir, we would read from bogus memory.\n\nAs it turns out, though, we always create this field\npointing to a string literal, so there's no bug. We can just\nget rid of the pointless extra conditional.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n dir.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 2c91541..a4a9d9f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -2360,16 +2360,15 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra\n \tstruct ondisk_untracked_cache *ouc;\n \tstruct write_data wd;\n \tunsigned char varbuf[16];\n-\tint len = 0, varint_len;\n-\tif (untracked->exclude_per_dir)\n-\t\tlen = strlen(untracked->exclude_per_dir);\n-\touc = xmalloc(sizeof(*ouc) + len + 1);\n+\tint varint_len;\n+\tsize_t len = strlen(untracked->exclude_per_dir);\n+\n+\tFLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);\n \tstat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);\n \tstat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);\n \thashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);\n \thashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);\n \touc->dir_flags = htonl(untracked->dir_flags);\n-\tmemcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);\n \n \tvarint_len = encode_varint(untracked->ident.len, varbuf);\n \tstrbuf_add(out, varbuf, varint_len);\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278935","messageId":"20160222224446.GN10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 14/22] fast-import: simplify allocation in start_packfile","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:46Z","receivedAt":"2016-02-22T22:44:46Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This function allocate a packed_git flex-array, and adds a\nmysterious 2 bytes to the length of the pack_name field. One\nis for the trailing NUL, but the other has no purpose. This\nis probably cargo-culted from add_packed_git, which gets the\n\".idx\" path and needed to allocate enough space to hold the\nmatching \".pack\" (though since 48bcc1c, we calculate the\nsize there differently).\n\nThis site, however, is using the raw path of a tempfile, and\ndoes not need the extra byte. We can just replace the\nallocation with FLEX_ALLOC_STR, which handles the allocation\nand the NUL for us.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n fast-import.c | 5 +----\n 1 file changed, 1 insertion(+), 4 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 3053bb8..9fc7093 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -865,15 +865,12 @@ static void start_packfile(void)\n {\n \tstatic char tmp_file[PATH_MAX];\n \tstruct packed_git *p;\n-\tint namelen;\n \tstruct pack_header hdr;\n \tint pack_fd;\n \n \tpack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),\n \t\t\t      \"pack/tmp_pack_XXXXXX\");\n-\tnamelen = strlen(tmp_file) + 2;\n-\tp = xcalloc(1, sizeof(*p) + namelen);\n-\txsnprintf(p->pack_name, namelen, \"%s\", tmp_file);\n+\tFLEX_ALLOC_STR(p, pack_name, tmp_file);\n \tp->pack_fd = pack_fd;\n \tp->do_not_close = 1;\n \tpack_file = sha1fd(pack_fd, p->pack_name);\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278936","messageId":"20160222224449.GO10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 15/22] fetch-pack: simplify add_sought_entry","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:50Z","receivedAt":"2016-02-22T22:44:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We have two variants of this function, one that takes a\nstring and one that takes a ptr/len combo. But we only call\nthe latter with the length of a NUL-terminated string, so\nour first simplification is to drop it in favor of the\nstring variant.\n\nSince we know we have a string, we can also replace the\nmanual memory computation with a call to alloc_ref().\n\nFurthermore, we can rely on get_oid_hex() to complain if it\nhits the end of the string. That means we can simplify the\ncheck for \"<sha1> <ref>\" versus just \"<ref>\". Rather than\nmanage the ptr/len pair, we can just bump the start of our\nstring forward. The original code over-allocated based on\nthe original \"namelen\" (which wasn't _wrong_, but was simply\nwasteful and confusing).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/fetch-pack.c | 27 +++++++++------------------\n 1 file changed, 9 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 9b2a514..79a611f 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -10,33 +10,24 @@ static const char fetch_pack_usage[] =\n \"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] \"\n \"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]\";\n \n-static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,\n-\t\t\t\t const char *name, int namelen)\n+static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n+\t\t\t     const char *name)\n {\n-\tstruct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);\n+\tstruct ref *ref;\n \tstruct object_id oid;\n-\tconst int chunksz = GIT_SHA1_HEXSZ + 1;\n \n-\tif (namelen > chunksz && name[chunksz - 1] == ' ' &&\n-\t\t!get_oid_hex(name, &oid)) {\n-\t\toidcpy(&ref->old_oid, &oid);\n-\t\tname += chunksz;\n-\t\tnamelen -= chunksz;\n-\t}\n+\tif (!get_oid_hex(name, &oid) && name[GIT_SHA1_HEXSZ] == ' ')\n+\t\tname += GIT_SHA1_HEXSZ + 1;\n+\telse\n+\t\toidclr(&oid);\n \n-\tmemcpy(ref->name, name, namelen);\n-\tref->name[namelen] = '\\0';\n+\tref = alloc_ref(name);\n+\toidcpy(&ref->old_oid, &oid);\n \t(*nr)++;\n \tALLOC_GROW(*sought, *nr, *alloc);\n \t(*sought)[*nr - 1] = ref;\n }\n \n-static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n-\t\t\t     const char *string)\n-{\n-\tadd_sought_entry_mem(sought, nr, alloc, string, strlen(string));\n-}\n-\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, ret;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278937","messageId":"20160222224453.GP10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 16/22] test-path-utils: fix normalize_path_copy output buffer size","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:54Z","receivedAt":"2016-02-22T22:44:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The normalize_path_copy function needs an output buffer that\nis at least as long as its input (it may shrink the path,\nbut never expand it). However, this test program feeds it\nstatic PATH_MAX-sized buffers, which have no relation to the\ninput size.\n\nIn the normalize_ceiling_entry case, we do at least check\nthe size against PATH_MAX and die(), but that case is even\nmore convoluted. We normalize into a fixed-size buffer, free\nthe original, and then replace it with a strdup'd copy of\nthe result. But normalize_path_copy explicitly allows\nnormalizing in-place, so we can simply do that.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n test-path-utils.c | 15 ++++-----------\n 1 file changed, 4 insertions(+), 11 deletions(-)\n\ndiff --git a/test-path-utils.c b/test-path-utils.c\nindex 6232dfe..ba805b3 100644\n--- a/test-path-utils.c\n+++ b/test-path-utils.c\n@@ -8,21 +8,14 @@\n  */\n static int normalize_ceiling_entry(struct string_list_item *item, void *unused)\n {\n-\tconst char *ceil = item->string;\n-\tint len = strlen(ceil);\n-\tchar buf[PATH_MAX+1];\n+\tchar *ceil = item->string;\n \n-\tif (len == 0)\n+\tif (!*ceil)\n \t\tdie(\"Empty path is not supported\");\n-\tif (len > PATH_MAX)\n-\t\tdie(\"Path \\\"%s\\\" is too long\", ceil);\n \tif (!is_absolute_path(ceil))\n \t\tdie(\"Path \\\"%s\\\" is not absolute\", ceil);\n-\tif (normalize_path_copy(buf, ceil) < 0)\n+\tif (normalize_path_copy(ceil, ceil) < 0)\n \t\tdie(\"Path \\\"%s\\\" could not be normalized\", ceil);\n-\tlen = strlen(buf);\n-\tfree(item->string);\n-\titem->string = xstrdup(buf);\n \treturn 1;\n }\n \n@@ -166,7 +159,7 @@ static struct test_data dirname_data[] = {\n int main(int argc, char **argv)\n {\n \tif (argc == 3 && !strcmp(argv[1], \"normalize_path_copy\")) {\n-\t\tchar *buf = xmalloc(PATH_MAX + 1);\n+\t\tchar *buf = xmallocz(strlen(argv[2]));\n \t\tint rv = normalize_path_copy(buf, argv[2]);\n \t\tif (rv)\n \t\t\tbuf = \"++failed++\";\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278939","messageId":"20160222224457.GQ10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 17/22] sequencer: simplify memory allocation of get_message","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:44:57Z","receivedAt":"2016-02-22T22:44:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"For a commit with sha1 \"1234abcd\" and subject \"foo\", this\nfunction produces a struct with three strings:\n\n 1. \"foo\"\n\n 2. \"1234abcd... foo\"\n\n 3. \"parent of 1234abcd... foo\"\n\nIt takes advantage of the fact that these strings are\nsubsets of each other, and allocates only _one_ string, with\npointers into the various parts. Unfortunately, this makes\nthe string allocation complicated and hard to follow.\n\nSince we keep only one of these in memory at a time, we can\nafford to simply allocate three strings. This lets us build\non tools like xstrfmt and avoid manual computation.\n\nWhile we're here, we can also drop the ad-hoc\nreimplementation of get_git_commit_encoding(), and simply\ncall that function.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n sequencer.c | 29 ++++++++++-------------------\n 1 file changed, 10 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8048786..e66f2fe 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -124,42 +124,33 @@ static const char *action_name(const struct replay_opts *opts)\n \n struct commit_message {\n \tchar *parent_label;\n-\tconst char *label;\n-\tconst char *subject;\n+\tchar *label;\n+\tchar *subject;\n \tconst char *message;\n };\n \n static int get_message(struct commit *commit, struct commit_message *out)\n {\n \tconst char *abbrev, *subject;\n-\tint abbrev_len, subject_len;\n-\tchar *q;\n-\n-\tif (!git_commit_encoding)\n-\t\tgit_commit_encoding = \"UTF-8\";\n+\tint subject_len;\n \n-\tout->message = logmsg_reencode(commit, NULL, git_commit_encoding);\n+\tout->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());\n \tabbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);\n-\tabbrev_len = strlen(abbrev);\n \n \tsubject_len = find_commit_subject(out->message, &subject);\n \n-\tout->parent_label = xmalloc(strlen(\"parent of \") + abbrev_len +\n-\t\t\t      strlen(\"... \") + subject_len + 1);\n-\tq = out->parent_label;\n-\tq = mempcpy(q, \"parent of \", strlen(\"parent of \"));\n-\tout->label = q;\n-\tq = mempcpy(q, abbrev, abbrev_len);\n-\tq = mempcpy(q, \"... \", strlen(\"... \"));\n-\tout->subject = q;\n-\tq = mempcpy(q, subject, subject_len);\n-\t*q = '\\0';\n+\tout->subject = xmemdupz(subject, subject_len);\n+\tout->label = xstrfmt(\"%s... %s\", abbrev, out->subject);\n+\tout->parent_label = xstrfmt(\"parent of %s\", out->label);\n+\n \treturn 0;\n }\n \n static void free_message(struct commit *commit, struct commit_message *msg)\n {\n \tfree(msg->parent_label);\n+\tfree(msg->label);\n+\tfree(msg->subject);\n \tunuse_commit_buffer(commit, msg->message);\n }\n \n-- \n2.7.2.645.g4e1306c\n"},{"id":"278938","messageId":"20160222224501.GR10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 18/22] git-compat-util: drop mempcpy compat code","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:45:01Z","receivedAt":"2016-02-22T22:45:01Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There are no callers of this left, as the last one was\ndropped in the previous patch. And there are not likely to\nbe new ones, as the function has been around since 2010\nwithout gaining any new callers.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-compat-util.h | 9 ---------\n 1 file changed, 9 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 57ff9fb..1459f9b 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -681,7 +681,6 @@ extern int git_vsnprintf(char *str, size_t maxsize,\n #ifdef __GLIBC_PREREQ\n #if __GLIBC_PREREQ(2, 1)\n #define HAVE_STRCHRNUL\n-#define HAVE_MEMPCPY\n #endif\n #endif\n \n@@ -695,14 +694,6 @@ static inline char *gitstrchrnul(const char *s, int c)\n }\n #endif\n \n-#ifndef HAVE_MEMPCPY\n-#define mempcpy gitmempcpy\n-static inline void *gitmempcpy(void *dest, const void *src, size_t n)\n-{\n-\treturn (char *)memcpy(dest, src, n) + n;\n-}\n-#endif\n-\n #ifdef NO_INET_PTON\n int inet_pton(int af, const char *src, void *dst);\n #endif\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278940","messageId":"20160222224504.GS10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 19/22] transport_anonymize_url: use xstrfmt","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:45:05Z","receivedAt":"2016-02-22T22:45:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This function uses xcalloc and two memcpy calls to\nconcatenate two strings. We can do this as an xstrfmt\none-liner, and then it is more clear that we are allocating\nthe correct amount of memory.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n transport.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex 3b4e644..ac857a9 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1021,7 +1021,7 @@ int transport_disconnect(struct transport *transport)\n  */\n char *transport_anonymize_url(const char *url)\n {\n-\tchar *anon_url, *scheme_prefix, *anon_part;\n+\tchar *scheme_prefix, *anon_part;\n \tsize_t anon_len, prefix_len = 0;\n \n \tanon_part = strchr(url, '@');\n@@ -1055,10 +1055,8 @@ char *transport_anonymize_url(const char *url)\n \t\t\tgoto literal_copy;\n \t\tprefix_len = scheme_prefix - url + 3;\n \t}\n-\tanon_url = xcalloc(1, 1 + prefix_len + anon_len);\n-\tmemcpy(anon_url, url, prefix_len);\n-\tmemcpy(anon_url + prefix_len, anon_part, anon_len);\n-\treturn anon_url;\n+\treturn xstrfmt(\"%.*s%.*s\", (int)prefix_len, url,\n+\t\t       (int)anon_len, anon_part);\n literal_copy:\n \treturn xstrdup(url);\n }\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278941","messageId":"20160222224508.GT10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 20/22] diff_populate_gitlink: use a strbuf","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:45:08Z","receivedAt":"2016-02-22T22:45:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We allocate 100 bytes to hold the \"Submodule commit ...\"\ntext. This is enough, but it's not immediately obvious that\nthis is the case, and we have to repeat the magic 100 twice.\n\nWe could get away with xstrfmt here, but we want to know the\nsize, as well, so let's use a real strbuf. And while we're\nhere, we can clean up the logic around size_only. It\ncurrently sets and clears the \"data\" field pointlessly, and\nleaves the \"should_free\" flag on even after we have cleared\nthe data.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 27d14a7..a70ec6e 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2704,21 +2704,21 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int\n \n static int diff_populate_gitlink(struct diff_filespec *s, int size_only)\n {\n-\tint len;\n-\tchar *data = xmalloc(100), *dirty = \"\";\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tchar *dirty = \"\";\n \n \t/* Are we looking at the work tree? */\n \tif (s->dirty_submodule)\n \t\tdirty = \"-dirty\";\n \n-\tlen = snprintf(data, 100,\n-\t\t       \"Subproject commit %s%s\\n\", sha1_to_hex(s->sha1), dirty);\n-\ts->data = data;\n-\ts->size = len;\n-\ts->should_free = 1;\n+\tstrbuf_addf(&buf, \"Subproject commit %s%s\\n\", sha1_to_hex(s->sha1), dirty);\n+\ts->size = buf.len;\n \tif (size_only) {\n \t\ts->data = NULL;\n-\t\tfree(data);\n+\t\tstrbuf_release(&buf);\n+\t} else {\n+\t\ts->data = strbuf_detach(&buf, NULL);\n+\t\ts->should_free = 1;\n \t}\n \treturn 0;\n }\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278942","messageId":"20160222224512.GU10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 21/22] convert ewah/bitmap code to use xmalloc","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:45:12Z","receivedAt":"2016-02-22T22:45:12Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This code was originally written with the idea that it could\nbe spun off into its own ewah library, and uses the\noverrideable ewah_malloc to do allocations.\n\nWe plug in xmalloc as our ewah_malloc, of course. But over\nthe years the ewah code itself has become more entangled\nwith git, and the return value of many ewah_malloc sites is\nnot checked.\n\nLet's just drop the level of indirection and use xmalloc and\nfriends directly. This saves a few lines, and will let us\nadapt these sites to our more advanced malloc helpers.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ewah/bitmap.c      | 12 ++++++------\n ewah/ewah_bitmap.c |  9 +++------\n ewah/ewah_io.c     | 10 ++--------\n ewah/ewok.h        | 10 ----------\n 4 files changed, 11 insertions(+), 30 deletions(-)\n\ndiff --git a/ewah/bitmap.c b/ewah/bitmap.c\nindex 47ad674..c88daa0 100644\n--- a/ewah/bitmap.c\n+++ b/ewah/bitmap.c\n@@ -25,8 +25,8 @@\n \n struct bitmap *bitmap_new(void)\n {\n-\tstruct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap));\n-\tbitmap->words = ewah_calloc(32, sizeof(eword_t));\n+\tstruct bitmap *bitmap = xmalloc(sizeof(struct bitmap));\n+\tbitmap->words = xcalloc(32, sizeof(eword_t));\n \tbitmap->word_alloc = 32;\n \treturn bitmap;\n }\n@@ -38,8 +38,8 @@ void bitmap_set(struct bitmap *self, size_t pos)\n \tif (block >= self->word_alloc) {\n \t\tsize_t old_size = self->word_alloc;\n \t\tself->word_alloc = block * 2;\n-\t\tself->words = ewah_realloc(self->words,\n-\t\t\tself->word_alloc * sizeof(eword_t));\n+\t\tself->words = xrealloc(self->words,\n+\t\t\t\t      self->word_alloc * sizeof(eword_t));\n \n \t\tmemset(self->words + old_size, 0x0,\n \t\t\t(self->word_alloc - old_size) * sizeof(eword_t));\n@@ -102,7 +102,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)\n \twhile (ewah_iterator_next(&blowup, &it)) {\n \t\tif (i >= bitmap->word_alloc) {\n \t\t\tbitmap->word_alloc *= 1.5;\n-\t\t\tbitmap->words = ewah_realloc(\n+\t\t\tbitmap->words = xrealloc(\n \t\t\t\tbitmap->words, bitmap->word_alloc * sizeof(eword_t));\n \t\t}\n \n@@ -134,7 +134,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)\n \n \tif (self->word_alloc < other_final) {\n \t\tself->word_alloc = other_final;\n-\t\tself->words = ewah_realloc(self->words,\n+\t\tself->words = xrealloc(self->words,\n \t\t\tself->word_alloc * sizeof(eword_t));\n \t\tmemset(self->words + original_size, 0x0,\n \t\t\t(self->word_alloc - original_size) * sizeof(eword_t));\ndiff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c\nindex b522437..fcd465e 100644\n--- a/ewah/ewah_bitmap.c\n+++ b/ewah/ewah_bitmap.c\n@@ -39,7 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)\n \t\treturn;\n \n \tself->alloc_size = new_size;\n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \tself->rlw = self->buffer + (rlw_offset / sizeof(eword_t));\n }\n@@ -282,11 +282,8 @@ struct ewah_bitmap *ewah_new(void)\n {\n \tstruct ewah_bitmap *self;\n \n-\tself = ewah_malloc(sizeof(struct ewah_bitmap));\n-\tif (self == NULL)\n-\t\treturn NULL;\n-\n-\tself->buffer = ewah_malloc(32 * sizeof(eword_t));\n+\tself = xmalloc(sizeof(struct ewah_bitmap));\n+\tself->buffer = xmalloc(32 * sizeof(eword_t));\n \tself->alloc_size = 32;\n \n \tewah_clear(self);\ndiff --git a/ewah/ewah_io.c b/ewah/ewah_io.c\nindex 43481b9..4acff97 100644\n--- a/ewah/ewah_io.c\n+++ b/ewah/ewah_io.c\n@@ -134,12 +134,9 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)\n \tself->buffer_size = self->alloc_size = get_be32(ptr);\n \tptr += sizeof(uint32_t);\n \n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \n-\tif (!self->buffer)\n-\t\treturn -1;\n-\n \t/*\n \t * Copy the raw data for the bitmap as a whole chunk;\n \t * if we're in a little-endian platform, we'll perform\n@@ -180,12 +177,9 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)\n \t\treturn -1;\n \n \tself->buffer_size = self->alloc_size = (size_t)ntohl(word_count);\n-\tself->buffer = ewah_realloc(self->buffer,\n+\tself->buffer = xrealloc(self->buffer,\n \t\tself->alloc_size * sizeof(eword_t));\n \n-\tif (!self->buffer)\n-\t\treturn -1;\n-\n \t/** 64 bit x N -- compressed words */\n \tbuffer = self->buffer;\n \twords_left = self->buffer_size;\ndiff --git a/ewah/ewok.h b/ewah/ewok.h\nindex 6e2c5e1..269a1a8 100644\n--- a/ewah/ewok.h\n+++ b/ewah/ewok.h\n@@ -20,16 +20,6 @@\n #ifndef __EWOK_BITMAP_H__\n #define __EWOK_BITMAP_H__\n \n-#ifndef ewah_malloc\n-#\tdefine ewah_malloc xmalloc\n-#endif\n-#ifndef ewah_realloc\n-#\tdefine ewah_realloc xrealloc\n-#endif\n-#ifndef ewah_calloc\n-#\tdefine ewah_calloc xcalloc\n-#endif\n-\n struct strbuf;\n typedef uint64_t eword_t;\n #define BITS_IN_EWORD (sizeof(eword_t) * 8)\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278943","messageId":"20160222224515.GV10075@sigill.intra.peff.net","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"[PATCH v3 22/22] ewah: convert to REALLOC_ARRAY, etc","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-02-22T22:45:15Z","receivedAt":"2016-02-22T22:45:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Now that we're built around xmalloc and friends, we can use\nhelpers like REALLOC_ARRAY, ALLOC_GROW, and so on to make\nthe code shorter and protect against integer overflow.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ewah/bitmap.c      | 16 ++++------------\n ewah/ewah_bitmap.c |  5 ++---\n ewah/ewah_io.c     |  6 ++----\n 3 files changed, 8 insertions(+), 19 deletions(-)\n\ndiff --git a/ewah/bitmap.c b/ewah/bitmap.c\nindex c88daa0..7103cee 100644\n--- a/ewah/bitmap.c\n+++ b/ewah/bitmap.c\n@@ -17,7 +17,7 @@\n  * along with this program; if not, write to the Free Software\n  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n  */\n-#include \"git-compat-util.h\"\n+#include \"cache.h\"\n #include \"ewok.h\"\n \n #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))\n@@ -38,9 +38,7 @@ void bitmap_set(struct bitmap *self, size_t pos)\n \tif (block >= self->word_alloc) {\n \t\tsize_t old_size = self->word_alloc;\n \t\tself->word_alloc = block * 2;\n-\t\tself->words = xrealloc(self->words,\n-\t\t\t\t      self->word_alloc * sizeof(eword_t));\n-\n+\t\tREALLOC_ARRAY(self->words, self->word_alloc);\n \t\tmemset(self->words + old_size, 0x0,\n \t\t\t(self->word_alloc - old_size) * sizeof(eword_t));\n \t}\n@@ -100,12 +98,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)\n \tewah_iterator_init(&it, ewah);\n \n \twhile (ewah_iterator_next(&blowup, &it)) {\n-\t\tif (i >= bitmap->word_alloc) {\n-\t\t\tbitmap->word_alloc *= 1.5;\n-\t\t\tbitmap->words = xrealloc(\n-\t\t\t\tbitmap->words, bitmap->word_alloc * sizeof(eword_t));\n-\t\t}\n-\n+\t\tALLOC_GROW(bitmap->words, i + 1, bitmap->word_alloc);\n \t\tbitmap->words[i++] = blowup;\n \t}\n \n@@ -134,8 +127,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)\n \n \tif (self->word_alloc < other_final) {\n \t\tself->word_alloc = other_final;\n-\t\tself->words = xrealloc(self->words,\n-\t\t\tself->word_alloc * sizeof(eword_t));\n+\t\tREALLOC_ARRAY(self->words, self->word_alloc);\n \t\tmemset(self->words + original_size, 0x0,\n \t\t\t(self->word_alloc - original_size) * sizeof(eword_t));\n \t}\ndiff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c\nindex fcd465e..2dc9c82 100644\n--- a/ewah/ewah_bitmap.c\n+++ b/ewah/ewah_bitmap.c\n@@ -39,8 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)\n \t\treturn;\n \n \tself->alloc_size = new_size;\n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \tself->rlw = self->buffer + (rlw_offset / sizeof(eword_t));\n }\n \n@@ -283,8 +282,8 @@ struct ewah_bitmap *ewah_new(void)\n \tstruct ewah_bitmap *self;\n \n \tself = xmalloc(sizeof(struct ewah_bitmap));\n-\tself->buffer = xmalloc(32 * sizeof(eword_t));\n \tself->alloc_size = 32;\n+\tALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \tewah_clear(self);\n \treturn self;\ndiff --git a/ewah/ewah_io.c b/ewah/ewah_io.c\nindex 4acff97..61f6a43 100644\n--- a/ewah/ewah_io.c\n+++ b/ewah/ewah_io.c\n@@ -134,8 +134,7 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)\n \tself->buffer_size = self->alloc_size = get_be32(ptr);\n \tptr += sizeof(uint32_t);\n \n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \t/*\n \t * Copy the raw data for the bitmap as a whole chunk;\n@@ -177,8 +176,7 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)\n \t\treturn -1;\n \n \tself->buffer_size = self->alloc_size = (size_t)ntohl(word_count);\n-\tself->buffer = xrealloc(self->buffer,\n-\t\tself->alloc_size * sizeof(eword_t));\n+\tREALLOC_ARRAY(self->buffer, self->alloc_size);\n \n \t/** 64 bit x N -- compressed words */\n \tbuffer = self->buffer;\n-- \n2.7.2.645.g4e1306c\n"},{"id":"278950","messageId":"xmqqbn784a2k.fsf@gitster.mtv.corp.google.com","threadId":"41418","inReplyTo":"20160222224059.GA3857@sigill.intra.peff.net","subject":"Re: [PATCH v3 0/22] hardening allocations against integer overflow","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-02-22T23:08:51Z","receivedAt":"2016-02-22T23:08:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Fri, Feb 19, 2016 at 06:19:41AM -0500, Jeff King wrote:\n>\n>> Here's a re-roll of jk/tighten-alloc series from:\n>> \n>>   http://thread.gmane.org/gmane.comp.version-control.git/286253\n>\n> And here's v3. The changes this time (and philosophical rationalization\n> of changes I didn't make) are pretty small:\n>\n>   - flip the order of arguments to st_mult() in ALLOC_ARRAY, et al, to\n>     get a probably-irrelevant-but-so-easy-why-not optimization\n>\n>   - mark new global var in daemon.c as static\n>\n>   - add argv_array_detach (new patch 6) to avoid gross memory management\n>     when converting line-log to use argv_array in the subsequent patch\n>\n> So I hope this one is ready for 'next'.  Thanks René, Ramsay, and Eric\n> for reviewing.\n>\n>   [01/22]: reflog_expire_cfg: NUL-terminate pattern field\n>   [02/22]: add helpers for detecting size_t overflow\n>   [03/22]: tree-diff: catch integer overflow in combine_diff_path allocation\n>   [04/22]: harden REALLOC_ARRAY and xcalloc against size_t overflow\n>   [05/22]: add helpers for allocating flex-array structs\n>   [06/22]: argv-array: add detach function\n>   [07/22]: convert manual allocations to argv_array\n>   [08/22]: convert trivial cases to ALLOC_ARRAY\n>   [09/22]: use xmallocz to avoid size arithmetic\n>   [10/22]: convert trivial cases to FLEX_ARRAY macros\n>   [11/22]: use st_add and st_mult for allocation size computation\n>   [12/22]: prepare_{git,shell}_cmd: use argv_array\n>   [13/22]: write_untracked_extension: use FLEX_ALLOC helper\n>   [14/22]: fast-import: simplify allocation in start_packfile\n>   [15/22]: fetch-pack: simplify add_sought_entry\n>   [16/22]: test-path-utils: fix normalize_path_copy output buffer size\n>   [17/22]: sequencer: simplify memory allocation of get_message\n>   [18/22]: git-compat-util: drop mempcpy compat code\n>   [19/22]: transport_anonymize_url: use xstrfmt\n>   [20/22]: diff_populate_gitlink: use a strbuf\n>   [21/22]: convert ewah/bitmap code to use xmalloc\n>   [22/22]: ewah: convert to REALLOC_ARRAY, etc\n\nI admit that I only looked at tbdiff output, but what I saw looked\nvery sensible.\n\nThanks.\n"}]}