Merge branch 'jk/tighten-alloc' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 10 Mar 2016 19:13:43 +0000 (11:13 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 10 Mar 2016 19:13:43 +0000 (11:13 -0800)
* jk/tighten-alloc: (23 commits)
compat/mingw: brown paper bag fix for 50a6c8e
ewah: convert to REALLOC_ARRAY, etc
convert ewah/bitmap code to use xmalloc
diff_populate_gitlink: use a strbuf
transport_anonymize_url: use xstrfmt
git-compat-util: drop mempcpy compat code
sequencer: simplify memory allocation of get_message
test-path-utils: fix normalize_path_copy output buffer size
fetch-pack: simplify add_sought_entry
fast-import: simplify allocation in start_packfile
write_untracked_extension: use FLEX_ALLOC helper
prepare_{git,shell}_cmd: use argv_array
use st_add and st_mult for allocation size computation
convert trivial cases to FLEX_ARRAY macros
use xmallocz to avoid size arithmetic
convert trivial cases to ALLOC_ARRAY
convert manual allocations to argv_array
argv-array: add detach function
add helpers for allocating flex-array structs
harden REALLOC_ARRAY and xcalloc against size_t overflow
...

12 files changed:
1  2 
builtin/blame.c
builtin/grep.c
cache-tree.c
config.c
diff.c
diff.h
remote-curl.c
remote.c
run-command.c
setup.c
sha1_name.c
submodule.c
diff --combined builtin/blame.c
index 5265f79edc907de356dea2ece4d1645210b7aad4,e175d86e56c670f7463a1f6b00e75239c7ba1dfe..0b4f0bbb531407f6003fe66cfe16a48785b1dcf3
@@@ -459,13 -459,11 +459,11 @@@ static void queue_blames(struct scorebo
  static struct origin *make_origin(struct commit *commit, const char *path)
  {
        struct origin *o;
-       size_t pathlen = strlen(path) + 1;
-       o = xcalloc(1, sizeof(*o) + pathlen);
+       FLEX_ALLOC_STR(o, path, path);
        o->commit = commit;
        o->refcnt = 1;
        o->next = commit->util;
        commit->util = o;
-       memcpy(o->path, path, pathlen); /* includes NUL */
        return o;
  }
  
@@@ -2042,7 -2040,8 +2040,8 @@@ static int prepare_lines(struct scorebo
        for (p = buf; p < end; p = get_next_line(p, end))
                num++;
  
-       sb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1));
+       ALLOC_ARRAY(sb->lineno, num + 1);
+       lineno = sb->lineno;
  
        for (p = buf; p < end; p = get_next_line(p, end))
                *lineno++ = p - buf;
@@@ -2392,6 -2391,11 +2391,6 @@@ static struct commit *fake_working_tree
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  
 -      /*
 -       * We are not going to write this out, so this does not matter
 -       * right now, but someday we might optimize diff-index --cached
 -       * with cache-tree information.
 -       */
        cache_tree_invalidate_path(&the_index, path);
  
        return commit;
diff --combined builtin/grep.c
index 3ba35ecf935f9462d8bb4340837f57e0e7219d05,95ddf96d1e416f59dff08a9dde71b04cdb2b6ccd..65c02010c735ad6c5528dab2087d473e1c8b2362
@@@ -354,17 -354,17 +354,17 @@@ static void append_path(struct grep_op
  static void run_pager(struct grep_opt *opt, const char *prefix)
  {
        struct string_list *path_list = opt->output_priv;
-       const char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));
+       struct child_process child = CHILD_PROCESS_INIT;
        int i, status;
  
        for (i = 0; i < path_list->nr; i++)
-               argv[i] = path_list->items[i].string;
-       argv[path_list->nr] = NULL;
+               argv_array_push(&child.args, path_list->items[i].string);
+       child.dir = prefix;
+       child.use_shell = 1;
  
-       status = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, prefix, NULL);
+       status = run_command(&child);
        if (status)
                exit(status);
-       free(argv);
  }
  
  static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
  
        for (nr = 0; nr < active_nr; nr++) {
                const struct cache_entry *ce = active_cache[nr];
 -              if (!S_ISREG(ce->ce_mode))
 +              if (!S_ISREG(ce->ce_mode) || ce_intent_to_add(ce))
                        continue;
                if (!ce_path_match(ce, pathspec, NULL))
                        continue;
diff --combined cache-tree.c
index 20ee7b52df0c33d4473a198270705dffead01cdc,1fbe79a0032d898404580246800c3a7f6250ae6d..3ebf9c3aa44eb2ab25f573192b6449f63311ffd7
@@@ -79,11 -79,9 +79,9 @@@ static struct cache_tree_sub *find_subt
        ALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);
        it->subtree_nr++;
  
-       down = xmalloc(sizeof(*down) + pathlen + 1);
+       FLEX_ALLOC_MEM(down, name, path, pathlen);
        down->cache_tree = NULL;
        down->namelen = pathlen;
-       memcpy(down->name, path, pathlen);
-       down->name[pathlen] = 0;
  
        if (pos < it->subtree_nr)
                memmove(it->down + pos + 1,
@@@ -377,7 -375,7 +375,7 @@@ static int update_one(struct cache_tre
                 * they are not part of generated trees. Invalidate up
                 * to root to force cache-tree users to read elsewhere.
                 */
 -              if (ce->ce_flags & CE_INTENT_TO_ADD) {
 +              if (ce_intent_to_add(ce)) {
                        to_invalidate = 1;
                        continue;
                }
diff --combined config.c
index 325c3eaf9d1c9af8b0857ed1997fea1b6f237da6,ba8fd1376587848f0691883e7d1d71ad4d75d599..03544e7a3f68f858e2fed5492a4460bd05b75602
+++ b/config.c
@@@ -1825,26 -1825,15 +1825,26 @@@ contline
        return offset;
  }
  
 -int git_config_set_in_file(const char *config_filename,
 -                      const char *key, const char *value)
 +int git_config_set_in_file_gently(const char *config_filename,
 +                                const char *key, const char *value)
  {
 -      return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
 +      return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
  }
  
 -int git_config_set(const char *key, const char *value)
 +void git_config_set_in_file(const char *config_filename,
 +                          const char *key, const char *value)
  {
 -      return git_config_set_multivar(key, value, NULL, 0);
 +      git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
 +}
 +
 +int git_config_set_gently(const char *key, const char *value)
 +{
 +      return git_config_set_multivar_gently(key, value, NULL, 0);
 +}
 +
 +void git_config_set(const char *key, const char *value)
 +{
 +      git_config_set_multivar(key, value, NULL, 0);
  }
  
  /*
@@@ -1889,7 -1878,7 +1889,7 @@@ static int git_config_parse_key_1(cons
         * Validate the key and while at it, lower case it for matching.
         */
        if (store_key)
-               *store_key = xmalloc(strlen(key) + 1);
+               *store_key = xmallocz(strlen(key));
  
        dot = 0;
        for (i = 0; key[i]; i++) {
                if (store_key)
                        (*store_key)[i] = c;
        }
-       if (store_key)
-               (*store_key)[i] = 0;
  
        return 0;
  
@@@ -1961,10 -1948,9 +1959,10 @@@ int git_config_key_is_valid(const char 
   * - the config file is removed and the lock file rename()d to it.
   *
   */
 -int git_config_set_multivar_in_file(const char *config_filename,
 -                              const char *key, const char *value,
 -                              const char *value_regex, int multi_replace)
 +int git_config_set_multivar_in_file_gently(const char *config_filename,
 +                                         const char *key, const char *value,
 +                                         const char *value_regex,
 +                                         int multi_replace)
  {
        int fd = -1, in_fd = -1;
        int ret;
@@@ -2191,27 -2177,11 +2189,27 @@@ write_err_out
  
  }
  
 -int git_config_set_multivar(const char *key, const char *value,
 -                      const char *value_regex, int multi_replace)
 +void git_config_set_multivar_in_file(const char *config_filename,
 +                                   const char *key, const char *value,
 +                                   const char *value_regex, int multi_replace)
 +{
 +      if (git_config_set_multivar_in_file_gently(config_filename, key, value,
 +                                                 value_regex, multi_replace) < 0)
 +              die(_("Could not set '%s' to '%s'"), key, value);
 +}
 +
 +int git_config_set_multivar_gently(const char *key, const char *value,
 +                                 const char *value_regex, int multi_replace)
 +{
 +      return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex,
 +                                                    multi_replace);
 +}
 +
 +void git_config_set_multivar(const char *key, const char *value,
 +                           const char *value_regex, int multi_replace)
  {
 -      return git_config_set_multivar_in_file(NULL, key, value, value_regex,
 -                                             multi_replace);
 +      git_config_set_multivar_in_file(NULL, key, value, value_regex,
 +                                      multi_replace);
  }
  
  static int section_name_match (const char *buf, const char *name)
diff --combined diff.c
index a088e269b42d4af24a756c991bf60dca8eb4153d,a70ec6ef1a613a63482b0f7cf8d997af685793d9..059123c5dcef4129763895b0f2ad5a54728b0c07
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -2607,12 -2607,9 +2607,9 @@@ static void builtin_checkdiff(const cha
  
  struct diff_filespec *alloc_filespec(const char *path)
  {
-       int namelen = strlen(path);
-       struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
+       struct diff_filespec *spec;
  
-       memset(spec, 0, sizeof(*spec));
-       spec->path = (char *)(spec + 1);
-       memcpy(spec->path, path, namelen+1);
+       FLEXPTR_ALLOC_STR(spec, path, path);
        spec->count = 1;
        spec->is_binary = -1;
        return spec;
@@@ -2707,21 -2704,21 +2704,21 @@@ static int reuse_worktree_file(const ch
  
  static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
  {
-       int len;
-       char *data = xmalloc(100), *dirty = "";
+       struct strbuf buf = STRBUF_INIT;
+       char *dirty = "";
  
        /* Are we looking at the work tree? */
        if (s->dirty_submodule)
                dirty = "-dirty";
  
-       len = snprintf(data, 100,
-                      "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
-       s->data = data;
-       s->size = len;
-       s->should_free = 1;
+       strbuf_addf(&buf, "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
+       s->size = buf.len;
        if (size_only) {
                s->data = NULL;
-               free(data);
+               strbuf_release(&buf);
+       } else {
+               s->data = strbuf_detach(&buf, NULL);
+               s->should_free = 1;
        }
        return 0;
  }
@@@ -5085,7 -5082,7 +5082,7 @@@ size_t fill_textconv(struct userdiff_dr
  {
        size_t size;
  
 -      if (!driver || !driver->textconv) {
 +      if (!driver) {
                if (!DIFF_FILE_VALID(df)) {
                        *outbuf = "";
                        return 0;
                return df->size;
        }
  
 +      if (!driver->textconv)
 +              die("BUG: fill_textconv called with non-textconv driver");
 +
        if (driver->textconv_cache && df->sha1_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache, df->sha1,
                                          &size);
diff --combined diff.h
index 4505b4d91dd0985b25f5ba8c087c5afe34166631,beafbbdec763f9ac7fb6a41f225a97fa8d0ae580..e7d68edaf9d4744ce3c48356e1835c5506d5322d
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -222,8 -222,8 +222,8 @@@ struct combine_diff_path 
        } parent[FLEX_ARRAY];
  };
  #define combine_diff_path_size(n, l) \
-       (sizeof(struct combine_diff_path) + \
-        sizeof(struct combine_diff_parent) * (n) + (l) + 1)
+       st_add4(sizeof(struct combine_diff_path), (l), 1, \
+               st_mult(sizeof(struct combine_diff_parent), (n)))
  
  extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
                              int dense, struct rev_info *);
@@@ -349,26 -349,10 +349,26 @@@ extern void diff_no_index(struct rev_in
  
  extern int index_differs_from(const char *def, int diff_flags);
  
 +/*
 + * Fill the contents of the filespec "df", respecting any textconv defined by
 + * its userdiff driver.  The "driver" parameter must come from a
 + * previous call to get_textconv(), and therefore should either be NULL or have
 + * textconv enabled.
 + *
 + * Note that the memory ownership of the resulting buffer depends on whether
 + * the driver field is NULL. If it is, then the memory belongs to the filespec
 + * struct. If it is non-NULL, then "outbuf" points to a newly allocated buffer
 + * that should be freed by the caller.
 + */
  extern size_t fill_textconv(struct userdiff_driver *driver,
                            struct diff_filespec *df,
                            char **outbuf);
  
 +/*
 + * Look up the userdiff driver for the given filespec, and return it if
 + * and only if it has textconv enabled (otherwise return NULL). The result
 + * can be passed to fill_textconv().
 + */
  extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
  
  extern int parse_rename_score(const char **cp_p);
diff --combined remote-curl.c
index e114f24448eae40a49acedcb85a0443d3b6ecba2,e85333a51b0b6a88bfcb212d40d39802eca74a1d..e65ea597641d9b7a0f83b7d09a3b45f82394d1ef
@@@ -439,20 -439,8 +439,20 @@@ static int run_slot(struct active_reque
        err = run_one_slot(slot, results);
  
        if (err != HTTP_OK && err != HTTP_REAUTH) {
 -              error("RPC failed; result=%d, HTTP code = %ld",
 -                    results->curl_result, results->http_code);
 +              struct strbuf msg = STRBUF_INIT;
 +              if (results->http_code && results->http_code != 200)
 +                      strbuf_addf(&msg, "HTTP %ld", results->http_code);
 +              if (results->curl_result != CURLE_OK) {
 +                      if (msg.len)
 +                              strbuf_addch(&msg, ' ');
 +                      strbuf_addf(&msg, "curl %d", results->curl_result);
 +                      if (curl_errorstr[0]) {
 +                              strbuf_addch(&msg, ' ');
 +                              strbuf_addstr(&msg, curl_errorstr);
 +                      }
 +              }
 +              error("RPC failed; %s", msg.buf);
 +              strbuf_release(&msg);
        }
  
        return err;
@@@ -708,9 -696,10 +708,10 @@@ static int rpc_service(struct rpc_stat
  static int fetch_dumb(int nr_heads, struct ref **to_fetch)
  {
        struct walker *walker;
-       char **targets = xmalloc(nr_heads * sizeof(char*));
+       char **targets;
        int ret, i;
  
+       ALLOC_ARRAY(targets, nr_heads);
        if (options.depth)
                die("dumb http transport does not support --depth");
        for (i = 0; i < nr_heads; i++)
@@@ -857,23 -846,22 +858,22 @@@ static void parse_fetch(struct strbuf *
  
  static int push_dav(int nr_spec, char **specs)
  {
-       const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
-       int argc = 0, i;
+       struct child_process child = CHILD_PROCESS_INIT;
+       size_t i;
  
-       argv[argc++] = "http-push";
-       argv[argc++] = "--helper-status";
+       child.git_cmd = 1;
+       argv_array_push(&child.args, "http-push");
+       argv_array_push(&child.args, "--helper-status");
        if (options.dry_run)
-               argv[argc++] = "--dry-run";
+               argv_array_push(&child.args, "--dry-run");
        if (options.verbosity > 1)
-               argv[argc++] = "--verbose";
-       argv[argc++] = url.buf;
+               argv_array_push(&child.args, "--verbose");
+       argv_array_push(&child.args, url.buf);
        for (i = 0; i < nr_spec; i++)
-               argv[argc++] = specs[i];
-       argv[argc++] = NULL;
+               argv_array_push(&child.args, specs[i]);
  
-       if (run_command_v_opt(argv, RUN_GIT_CMD))
-               die("git-%s failed", argv[0]);
-       free(argv);
+       if (run_command(&child))
+               die("git-http-push failed");
        return 0;
  }
  
diff --combined remote.c
index 3ceac07620cef06810c8f92adec735cc5baef832,f182382c834ee93f8ddc4b78750b6ce2ac5fa4f7..6e5c1a876f5044ffdea71531695ce04305b072f1
+++ b/remote.c
@@@ -928,7 -928,7 +928,7 @@@ static struct ref *alloc_ref_with_prefi
                const char *name)
  {
        size_t len = strlen(name);
-       struct ref *ref = xcalloc(1, sizeof(struct ref) + prefixlen + len + 1);
+       struct ref *ref = xcalloc(1, st_add4(sizeof(*ref), prefixlen, len, 1));
        memcpy(ref->name, prefix, prefixlen);
        memcpy(ref->name + prefixlen, name, len);
        return ref;
@@@ -945,9 -945,9 +945,9 @@@ struct ref *copy_ref(const struct ref *
        size_t len;
        if (!ref)
                return NULL;
-       len = strlen(ref->name);
-       cpy = xmalloc(sizeof(struct ref) + len + 1);
-       memcpy(cpy, ref, sizeof(struct ref) + len + 1);
+       len = st_add3(sizeof(struct ref), strlen(ref->name), 1);
+       cpy = xmalloc(len);
+       memcpy(cpy, ref, len);
        cpy->next = NULL;
        cpy->symref = xstrdup_or_null(ref->symref);
        cpy->remote_status = xstrdup_or_null(ref->remote_status);
@@@ -1545,8 -1545,11 +1545,8 @@@ void set_ref_status_for_push(struct re
                }
  
                /*
 -               * Bypass the usual "must fast-forward" check but
 -               * replace it with a weaker "the old value must be
 -               * this value we observed".  If the remote ref has
 -               * moved and is now different from what we expect,
 -               * reject any push.
 +               * If the remote ref has moved and is now different
 +               * from what we expect, reject any push.
                 *
                 * It also is an error if the user told us to check
                 * with the remote-tracking branch to find the value
                        if (ref->expect_old_no_trackback ||
                            oidcmp(&ref->old_oid, &ref->old_oid_expect))
                                reject_reason = REF_STATUS_REJECT_STALE;
 +                      else
 +                              /* If the ref isn't stale then force the update. */
 +                              force_ref_update = 1;
                }
  
                /*
 -               * The usual "must fast-forward" rules.
 +               * If the update isn't already rejected then check
 +               * the usual "must fast-forward" rules.
                 *
                 * Decide whether an individual refspec A:B can be
                 * pushed.  The push will succeed if any of the
                 *     passing the --force argument
                 */
  
 -              else if (!ref->deletion && !is_null_oid(&ref->old_oid)) {
 +              if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
                        if (starts_with(ref->name, "refs/tags/"))
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
                        else if (!has_object_file(&ref->old_oid))
@@@ -2133,16 -2132,13 +2133,13 @@@ static int one_local_ref(const char *re
  {
        struct ref ***local_tail = cb_data;
        struct ref *ref;
-       int len;
  
        /* we already know it starts with refs/ to get here */
        if (check_refname_format(refname + 5, 0))
                return 0;
  
-       len = strlen(refname) + 1;
-       ref = xcalloc(1, sizeof(*ref) + len);
+       ref = alloc_ref(refname);
        oidcpy(&ref->new_oid, oid);
-       memcpy(ref->name, refname, len);
        **local_tail = ref;
        *local_tail = &ref->next;
        return 0;
diff --combined run-command.c
index 3add1d66ac344feab2ca39ee6fff663628c5fe32,171cbaa944adc0352eac635029cd22c78144a65e..2392b1efe829bf40ab1f896d160ac28c9bc057e0
@@@ -158,50 -158,41 +158,41 @@@ int sane_execvp(const char *file, char 
        return -1;
  }
  
- static const char **prepare_shell_cmd(const char **argv)
+ static const char **prepare_shell_cmd(struct argv_array *out, const char **argv)
  {
-       int argc, nargc = 0;
-       const char **nargv;
-       for (argc = 0; argv[argc]; argc++)
-               ; /* just counting */
-       /* +1 for NULL, +3 for "sh -c" plus extra $0 */
-       nargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));
-       if (argc < 1)
+       if (!argv[0])
                die("BUG: shell command is empty");
  
        if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
  #ifndef GIT_WINDOWS_NATIVE
-               nargv[nargc++] = SHELL_PATH;
+               argv_array_push(out, SHELL_PATH);
  #else
-               nargv[nargc++] = "sh";
+               argv_array_push(out, "sh");
  #endif
-               nargv[nargc++] = "-c";
-               if (argc < 2)
-                       nargv[nargc++] = argv[0];
-               else {
-                       struct strbuf arg0 = STRBUF_INIT;
-                       strbuf_addf(&arg0, "%s \"$@\"", argv[0]);
-                       nargv[nargc++] = strbuf_detach(&arg0, NULL);
-               }
-       }
+               argv_array_push(out, "-c");
  
-       for (argc = 0; argv[argc]; argc++)
-               nargv[nargc++] = argv[argc];
-       nargv[nargc] = NULL;
+               /*
+                * If we have no extra arguments, we do not even need to
+                * bother with the "$@" magic.
+                */
+               if (!argv[1])
+                       argv_array_push(out, argv[0]);
+               else
+                       argv_array_pushf(out, "%s \"$@\"", argv[0]);
+       }
  
-       return nargv;
+       argv_array_pushv(out, argv);
+       return out->argv;
  }
  
  #ifndef GIT_WINDOWS_NATIVE
  static int execv_shell_cmd(const char **argv)
  {
-       const char **nargv = prepare_shell_cmd(argv);
-       trace_argv_printf(nargv, "trace: exec:");
-       sane_execvp(nargv[0], (char **)nargv);
-       free(nargv);
+       struct argv_array nargv = ARGV_ARRAY_INIT;
+       prepare_shell_cmd(&nargv, argv);
+       trace_argv_printf(nargv.argv, "trace: exec:");
+       sane_execvp(nargv.argv[0], (char **)nargv.argv);
+       argv_array_clear(&nargv);
        return -1;
  }
  #endif
@@@ -455,6 -446,7 +446,7 @@@ fail_pipe
  {
        int fhin = 0, fhout = 1, fherr = 2;
        const char **sargv = cmd->argv;
+       struct argv_array nargv = ARGV_ARRAY_INIT;
  
        if (cmd->no_stdin)
                fhin = open("/dev/null", O_RDWR);
                fhout = dup(cmd->out);
  
        if (cmd->git_cmd)
-               cmd->argv = prepare_git_cmd(cmd->argv);
+               cmd->argv = prepare_git_cmd(&nargv, cmd->argv);
        else if (cmd->use_shell)
-               cmd->argv = prepare_shell_cmd(cmd->argv);
+               cmd->argv = prepare_shell_cmd(&nargv, cmd->argv);
  
        cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
                        cmd->dir, fhin, fhout, fherr);
        if (cmd->clean_on_exit && cmd->pid >= 0)
                mark_child_for_cleanup(cmd->pid);
  
-       if (cmd->git_cmd)
-               free(cmd->argv);
+       argv_array_clear(&nargv);
        cmd->argv = sargv;
        if (fhin != 0)
                close(fhin);
@@@ -633,11 -623,6 +623,11 @@@ int in_async(void
        return !pthread_equal(main_thread, pthread_self());
  }
  
 +void NORETURN async_exit(int code)
 +{
 +      pthread_exit((void *)(intptr_t)code);
 +}
 +
  #else
  
  static struct {
@@@ -683,11 -668,6 +673,11 @@@ int in_async(void
        return process_is_async;
  }
  
 +void NORETURN async_exit(int code)
 +{
 +      exit(code);
 +}
 +
  #endif
  
  int start_async(struct async *async)
diff --combined setup.c
index 59ec6587aa7e54b72d7a2f9fe0af51d66b2c8901,669062a0906ce7a78810582332a2b6bb72c3d0c5..de1a2a7ea5973fef256328a26730117466c15172
+++ b/setup.c
@@@ -88,7 -88,7 +88,7 @@@ char *prefix_path_gently(const char *pr
        const char *orig = path;
        char *sanitized;
        if (is_absolute_path(orig)) {
-               sanitized = xmalloc(strlen(path) + 1);
+               sanitized = xmallocz(strlen(path));
                if (remaining_prefix)
                        *remaining_prefix = 0;
                if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
@@@ -139,7 -139,9 +139,7 @@@ int check_filename(const char *prefix, 
                if (arg[2] == '\0') /* ":/" is root dir, always exists */
                        return 1;
                name = arg + 2;
 -      } else if (!no_wildcard(arg))
 -              return 1;
 -      else if (prefix)
 +      } else if (prefix)
                name = prefix_filename(prefix, strlen(prefix), arg);
        else
                name = arg;
@@@ -200,7 -202,7 +200,7 @@@ void verify_filename(const char *prefix
  {
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
 -      if (check_filename(prefix, arg))
 +      if (check_filename(prefix, arg) || !no_wildcard(arg))
                return;
        die_verify_filename(prefix, arg, diagnose_misspelt_rev);
  }
@@@ -449,6 -451,17 +449,6 @@@ static int check_repository_format_gent
        return ret;
  }
  
 -static void update_linked_gitdir(const char *gitfile, const char *gitdir)
 -{
 -      struct strbuf path = STRBUF_INIT;
 -      struct stat st;
 -
 -      strbuf_addf(&path, "%s/gitdir", gitdir);
 -      if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
 -              write_file(path.buf, "%s", gitfile);
 -      strbuf_release(&path);
 -}
 -
  /*
   * Try to read the location of the git directory from the .git file,
   * return path to git directory if found.
@@@ -486,14 -499,13 +486,13 @@@ const char *read_gitfile_gently(const c
                error_code = READ_GITFILE_ERR_OPEN_FAILED;
                goto cleanup_return;
        }
-       buf = xmalloc(st.st_size + 1);
+       buf = xmallocz(st.st_size);
        len = read_in_full(fd, buf, st.st_size);
        close(fd);
        if (len != st.st_size) {
                error_code = READ_GITFILE_ERR_READ_FAILED;
                goto cleanup_return;
        }
-       buf[len] = '\0';
        if (!starts_with(buf, "gitdir: ")) {
                error_code = READ_GITFILE_ERR_INVALID_FORMAT;
                goto cleanup_return;
                error_code = READ_GITFILE_ERR_NOT_A_REPO;
                goto cleanup_return;
        }
 -      update_linked_gitdir(path, dir);
        path = real_path(dir);
  
  cleanup_return:
diff --combined sha1_name.c
index d61b3b964e51e71e75398984df91bf59fea17fbf,532db4fdc6dcf905e99470e773a6166be2f903ed..ab5a163c9bab7f5799011b984715ed1ca9deed10
@@@ -87,9 -87,8 +87,8 @@@ static void find_short_object_filename(
                 * object databases including our own.
                 */
                const char *objdir = get_object_directory();
-               int objdir_len = strlen(objdir);
-               int entlen = objdir_len + 43;
-               fakeent = xmalloc(sizeof(*fakeent) + entlen);
+               size_t objdir_len = strlen(objdir);
+               fakeent = xmalloc(st_add3(sizeof(*fakeent), objdir_len, 43));
                memcpy(fakeent->base, objdir, objdir_len);
                fakeent->name = fakeent->base + objdir_len + 1;
                fakeent->name[-1] = '/';
@@@ -882,12 -881,12 +881,12 @@@ static int get_sha1_oneline(const char 
  
        if (prefix[0] == '!') {
                if (prefix[1] != '!')
 -                      die ("Invalid search pattern: %s", prefix);
 +                      return -1;
                prefix++;
        }
  
        if (regcomp(&regex, prefix, REG_EXTENDED))
 -              die("Invalid search pattern: %s", prefix);
 +              return -1;
  
        for (l = list; l; l = l->next) {
                l->item->object.flags |= ONELINE_SEEN;
diff --combined submodule.c
index b58d4ee945883fb3b69caf3c606e174bd677acf7,bd97b15a9284c45f8a64a43a32deaf190cd243ea..2a6cc9e8bab8f8ac198d7621131bcd70b38956a3
@@@ -68,7 -68,7 +68,7 @@@ int update_path_in_gitmodules(const cha
        strbuf_addstr(&entry, "submodule.");
        strbuf_addstr(&entry, submodule->name);
        strbuf_addstr(&entry, ".path");
 -      if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
 +      if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) {
                /* Maybe the user already did that, don't error out here */
                warning(_("Could not update .gitmodules entry %s"), entry.buf);
                strbuf_release(&entry);
@@@ -122,7 -122,7 +122,7 @@@ static int add_submodule_odb(const cha
        struct strbuf objects_directory = STRBUF_INIT;
        struct alternate_object_database *alt_odb;
        int ret = 0;
-       int alloc;
+       size_t alloc;
  
        strbuf_git_path_submodule(&objects_directory, path, "objects/");
        if (!is_directory(objects_directory.buf)) {
                                        objects_directory.len))
                        goto done;
  
-       alloc = objects_directory.len + 42; /* for "12/345..." sha1 */
-       alt_odb = xmalloc(sizeof(*alt_odb) + alloc);
+       alloc = st_add(objects_directory.len, 42); /* for "12/345..." sha1 */
+       alt_odb = xmalloc(st_add(sizeof(*alt_odb), alloc));
        alt_odb->next = alt_odb_list;
        xsnprintf(alt_odb->base, alloc, "%s", objects_directory.buf);
        alt_odb->name = alt_odb->base + objects_directory.len;
@@@ -1034,9 -1034,11 +1034,9 @@@ void connect_work_tree_and_git_dir(cons
        /* Update core.worktree setting */
        strbuf_reset(&file_name);
        strbuf_addf(&file_name, "%s/config", git_dir);
 -      if (git_config_set_in_file(file_name.buf, "core.worktree",
 -                                 relative_path(real_work_tree, git_dir,
 -                                               &rel_path)))
 -              die(_("Could not set core.worktree in %s"),
 -                  file_name.buf);
 +      git_config_set_in_file(file_name.buf, "core.worktree",
 +                             relative_path(real_work_tree, git_dir,
 +                                           &rel_path));
  
        strbuf_release(&file_name);
        strbuf_release(&rel_path);