Imported Upstream version 2.7.3 upstream/2.7.3
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:15:41 +0000 (15:15 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:15:41 +0000 (15:15 +0900)
136 files changed:
Documentation/RelNotes/2.7.3.txt [new file with mode: 0644]
Documentation/git-push.txt
Documentation/git.txt
Documentation/technical/api-argv-array.txt
GIT-VERSION-GEN
RelNotes
alias.c
archive.c
argv-array.c
argv-array.h
attr.c
bisect.c
branch.c
branch.h
builtin/am.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/check-ref-format.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/config.c
builtin/fast-export.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/grep.c
builtin/help.c
builtin/index-pack.c
builtin/init-db.c
builtin/merge-base.c
builtin/merge-tree.c
builtin/merge.c
builtin/mktree.c
builtin/mv.c
builtin/pack-objects.c
builtin/pack-redundant.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote-ext.c
builtin/remote.c
builtin/rev-parse.c
builtin/submodule--helper.c
builtin/worktree.c
cache-tree.c
cache.h
column.c
combine-diff.c
commit.c
compat/mingw.c
compat/precompose_utf8.c
compat/qsort.c
compat/setenv.c
compat/win32/syslog.c
config.c
daemon.c
diff.c
diff.h
diffcore-delta.c
diffcore-order.c
diffcore-rename.c
dir.c
entry.c
ewah/bitmap.c
ewah/ewah_bitmap.c
ewah/ewah_io.c
ewah/ewok.h
exec_cmd.c
exec_cmd.h
fast-import.c
fetch-pack.c
fsck.c
git-compat-util.h
git-merge-one-file.sh
git.c
graph.c
grep.c
hashmap.c
help.c
imap-send.c
khash.h
levenshtein.c
line-log.c
ll-merge.c
log-tree.c
merge-blobs.c
name-hash.c
notes.c
pack-check.c
pack-revindex.c
pager.c
pathspec.c
progress.c
ref-filter.c
refs.c
refs.h
refs/files-backend.c
remote-curl.c
remote.c
revision.c
run-command.c
run-command.h
sequencer.c
setup.c
sha1_file.c
sha1_name.c
shallow.c
show-index.c
strbuf.c
submodule.c
t/t1308-config-set.sh
t/t1501-work-tree.sh [moved from t/t1501-worktree.sh with 100% similarity]
t/t1509-root-work-tree.sh [moved from t/t1509-root-worktree.sh with 100% similarity]
t/t2019-checkout-ambiguous-ref.sh
t/t2027-worktree-list.sh
t/t3200-branch.sh
t/t5313-pack-bounds-checks.sh [new file with mode: 0755]
t/t5504-fetch-receive-strict.sh
t/t5505-remote.sh
t/t6133-pathspec-rev-dwim.sh [new file with mode: 0755]
t/t7400-submodule-basic.sh
t/t7409-submodule-detached-work-tree.sh [moved from t/t7409-submodule-detached-worktree.sh with 100% similarity]
t/t8005-blame-i18n.sh
t/t9200-git-cvsexportcommit.sh
t/test-lib-functions.sh
templates/hooks--update.sample
test-path-utils.c
transport.c
tree-diff.c
userdiff.h
wrapper.c
write_or_die.c
xdiff-interface.c
xdiff/xdiff.h
xdiff/xemit.c
xdiff/xmerge.c

diff --git a/Documentation/RelNotes/2.7.3.txt b/Documentation/RelNotes/2.7.3.txt
new file mode 100644 (file)
index 0000000..6adf038
--- /dev/null
@@ -0,0 +1,62 @@
+Git v2.7.3 Release Notes
+========================
+
+Fixes since v2.7.2
+------------------
+
+ * Traditionally, the tests that try commands that work on the
+   contents in the working tree were named with "worktree" in their
+   filenames, but with the recent addition of "git worktree"
+   subcommand, whose tests are also named similarly, it has become
+   harder to tell them apart.  The traditional tests have been renamed
+   to use "work-tree" instead in an attempt to differentiate them.
+
+ * Many codepaths forget to check return value from git_config_set();
+   the function is made to die() to make sure we do not proceed when
+   setting a configuration variable failed.
+
+ * Handling of errors while writing into our internal asynchronous
+   process has been made more robust, which reduces flakiness in our
+   tests.
+
+ * "git show 'HEAD:Foo[BAR]Baz'" did not interpret the argument as a
+   rev, i.e. the object named by the the pathname with wildcard
+   characters in a tree object.
+
+ * "git rev-parse --git-common-dir" used in the worktree feature
+   misbehaved when run from a subdirectory.
+
+ * The "v(iew)" subcommand of the interactive "git am -i" command was
+   broken in 2.6.0 timeframe when the command was rewritten in C.
+
+ * "git merge-tree" used to mishandle "both sides added" conflict with
+   its own "create a fake ancestor file that has the common parts of
+   what both sides have added and do a 3-way merge" logic; this has
+   been updated to use the usual "3-way merge with an empty blob as
+   the fake common ancestor file" approach used in the rest of the
+   system.
+
+ * The memory ownership rule of fill_textconv() API, which was a bit
+   tricky, has been documented a bit better.
+
+ * The documentation did not clearly state that the 'simple' mode is
+   now the default for "git push" when push.default configuration is
+   not set.
+
+ * Recent versions of GNU grep are pickier when their input contains
+   arbitrary binary data, which some of our tests uses.  Rewrite the
+   tests to sidestep the problem.
+
+ * A helper function "git submodule" uses since v2.7.0 to list the
+   modules that match the pathspec argument given to its subcommands
+   (e.g. "submodule add <repo> <path>") has been fixed.
+
+ * "git config section.var value" to set a value in per-repository
+   configuration file failed when it was run outside any repository,
+   but didn't say the reason correctly.
+
+ * The code to read the pack data using the offsets stored in the pack
+   idx file has been made more carefully check the validity of the
+   data in the idx.
+
+Also includes documentation and test updates.
index 4c775bc..af521f8 100644 (file)
@@ -37,6 +37,13 @@ the default `<refspec>` by consulting `remote.*.push` configuration,
 and if it is not found, honors `push.default` configuration to decide
 what to push (See linkgit:git-config[1] for the meaning of `push.default`).
 
+When neither the command-line nor the configuration specify what to
+push, the default behavior is used, which corresponds to the `simple`
+value for `push.default`: the current branch is pushed to the
+corresponding upstream branch, but as a safety measure, the push is
+aborted if the upstream branch does not have the same name as the
+local one.
+
 
 OPTIONS[[OPTIONS]]
 ------------------
index 68a71b4..c3da46d 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.7.2/git.html[documentation for release 2.7.2]
+* link:v2.7.3/git.html[documentation for release 2.7.3]
 
 * release notes for
+  link:RelNotes/2.7.3.txt[2.7.3],
   link:RelNotes/2.7.2.txt[2.7.2],
   link:RelNotes/2.7.1.txt[2.7.1],
   link:RelNotes/2.7.0.txt[2.7].
index 8076172..cfc0630 100644 (file)
@@ -56,3 +56,10 @@ Functions
 `argv_array_clear`::
        Free all memory associated with the array and return it to the
        initial, empty state.
+
+`argv_array_detach`::
+       Disconnect the `argv` member from the `argv_array` struct and
+       return it. The caller is responsible for freeing the memory used
+       by the array, and by the strings it references. After detaching,
+       the `argv_array` is in a reinitialized state and can be pushed
+       into again.
index d7ab24e..c3ec13b 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.7.2
+DEF_VER=v2.7.3
 
 LF='
 '
index 64e8170..65d6f36 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.7.2.txt
\ No newline at end of file
+Documentation/RelNotes/2.7.3.txt
\ No newline at end of file
diff --git a/alias.c b/alias.c
index a11229d..3b90397 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -23,7 +23,7 @@ int split_cmdline(char *cmdline, const char ***argv)
        int src, dst, count = 0, size = 16;
        char quoted = 0;
 
-       *argv = xmalloc(sizeof(**argv) * size);
+       ALLOC_ARRAY(*argv, size);
 
        /* split alias_string */
        (*argv)[count++] = cmdline;
index 0687afa..5d735ae 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -171,8 +171,8 @@ static void queue_directory(const unsigned char *sha1,
                unsigned mode, int stage, struct archiver_context *c)
 {
        struct directory *d;
-       size_t len = base->len + 1 + strlen(filename) + 1;
-       d = xmalloc(sizeof(*d) + len);
+       size_t len = st_add4(base->len, 1, strlen(filename), 1);
+       d = xmalloc(st_add(sizeof(*d), len));
        d->up      = c->bottom;
        d->baselen = base->len;
        d->mode    = mode;
index eaed477..5d370fa 100644 (file)
@@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array)
        }
        argv_array_init(array);
 }
+
+const char **argv_array_detach(struct argv_array *array)
+{
+       if (array->argv == empty_argv)
+               return xcalloc(1, sizeof(const char *));
+       else {
+               const char **ret = array->argv;
+               argv_array_init(array);
+               return ret;
+       }
+}
index a2fa0aa..29056e4 100644 (file)
@@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...);
 void argv_array_pushv(struct argv_array *, const char **);
 void argv_array_pop(struct argv_array *);
 void argv_array_clear(struct argv_array *);
+const char **argv_array_detach(struct argv_array *);
 
 #endif /* ARGV_ARRAY_H */
diff --git a/attr.c b/attr.c
index 086c08d..6537a43 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -93,9 +93,7 @@ static struct git_attr *git_attr_internal(const char *name, int len)
        if (invalid_attr_name(name, len))
                return NULL;
 
-       a = xmalloc(sizeof(*a) + len + 1);
-       memcpy(a->name, name, len);
-       a->name[len] = 0;
+       FLEX_ALLOC_MEM(a, name, name, len);
        a->h = hval;
        a->next = git_attr_hash[pos];
        a->attr_nr = attr_nr++;
@@ -799,7 +797,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)
                        ++count;
        }
        *num = count;
-       *check = xmalloc(sizeof(**check) * count);
+       ALLOC_ARRAY(*check, count);
        j = 0;
        for (i = 0; i < attr_nr; i++) {
                const char *value = check_all_attr[i].value;
index 42aa7aa..6d0793b 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -708,10 +708,10 @@ static struct commit *get_commit_reference(const unsigned char *sha1)
 
 static struct commit **get_bad_and_good_commits(int *rev_nr)
 {
-       int len = 1 + good_revs.nr;
-       struct commit **rev = xmalloc(len * sizeof(*rev));
+       struct commit **rev;
        int i, n = 0;
 
+       ALLOC_ARRAY(rev, 1 + good_revs.nr);
        rev[n++] = get_commit_reference(current_bad_oid->hash);
        for (i = 0; i < good_revs.nr; i++)
                rev[n++] = get_commit_reference(good_revs.sha1[i]);
index 7ff3f20..c50ea42 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -49,7 +49,13 @@ static int should_setup_rebase(const char *origin)
        return 0;
 }
 
-void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
+static const char tracking_advice[] =
+N_("\n"
+"After fixing the error cause you may try to fix up\n"
+"the remote tracking information by invoking\n"
+"\"git branch --set-upstream-to=%s%s%s\".");
+
+int install_branch_config(int flag, const char *local, const char *origin, const char *remote)
 {
        const char *shortname = NULL;
        struct strbuf key = STRBUF_INIT;
@@ -60,20 +66,23 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
            && !origin) {
                warning(_("Not setting branch %s as its own upstream."),
                        local);
-               return;
+               return 0;
        }
 
        strbuf_addf(&key, "branch.%s.remote", local);
-       git_config_set(key.buf, origin ? origin : ".");
+       if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
+               goto out_err;
 
        strbuf_reset(&key);
        strbuf_addf(&key, "branch.%s.merge", local);
-       git_config_set(key.buf, remote);
+       if (git_config_set_gently(key.buf, remote) < 0)
+               goto out_err;
 
        if (rebasing) {
                strbuf_reset(&key);
                strbuf_addf(&key, "branch.%s.rebase", local);
-               git_config_set(key.buf, "true");
+               if (git_config_set_gently(key.buf, "true") < 0)
+                       goto out_err;
        }
        strbuf_release(&key);
 
@@ -102,6 +111,19 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
                                          local, remote);
                }
        }
+
+       return 0;
+
+out_err:
+       strbuf_release(&key);
+       error(_("Unable to write upstream branch configuration"));
+
+       advise(_(tracking_advice),
+              origin ? origin : "",
+              origin ? "/" : "",
+              shortname ? shortname : remote);
+
+       return -1;
 }
 
 /*
@@ -109,8 +131,8 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
  * config.
  */
-static int setup_tracking(const char *new_ref, const char *orig_ref,
-                         enum branch_track track, int quiet)
+static void setup_tracking(const char *new_ref, const char *orig_ref,
+                          enum branch_track track, int quiet)
 {
        struct tracking tracking;
        int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
@@ -118,7 +140,7 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
        memset(&tracking, 0, sizeof(tracking));
        tracking.spec.dst = (char *)orig_ref;
        if (for_each_remote(find_tracked_branch, &tracking))
-               return 1;
+               return;
 
        if (!tracking.matches)
                switch (track) {
@@ -127,18 +149,18 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
                case BRANCH_TRACK_OVERRIDE:
                        break;
                default:
-                       return 1;
+                       return;
                }
 
        if (tracking.matches > 1)
-               return error(_("Not tracking: ambiguous information for ref %s"),
-                               orig_ref);
+               die(_("Not tracking: ambiguous information for ref %s"),
+                   orig_ref);
 
-       install_branch_config(config_flags, new_ref, tracking.remote,
-                             tracking.src ? tracking.src : orig_ref);
+       if (install_branch_config(config_flags, new_ref, tracking.remote,
+                             tracking.src ? tracking.src : orig_ref) < 0)
+               exit(-1);
 
        free(tracking.src);
-       return 0;
 }
 
 int read_branch_desc(struct strbuf *buf, const char *branch_name)
index 58aa45f..78ad438 100644 (file)
--- a/branch.h
+++ b/branch.h
@@ -43,9 +43,10 @@ void remove_branch_state(void);
 /*
  * Configure local branch "local" as downstream to branch "remote"
  * from remote "origin".  Used by git branch --set-upstream.
+ * Returns 0 on success.
  */
 #define BRANCH_CONFIG_VERBOSE 01
-extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
+extern int install_branch_config(int flag, const char *local, const char *origin, const char *remote);
 
 /*
  * Read branch description
index 95decc6..5668e0c 100644 (file)
@@ -1821,7 +1821,7 @@ static int do_interactive(struct am_state *state)
 
                        if (!pager)
                                pager = "cat";
-                       argv_array_push(&cp.args, pager);
+                       prepare_pager_args(&cp, pager);
                        argv_array_push(&cp.args, am_path(state, "patch"));
                        run_command(&cp);
                }
index deb1364..0db6d14 100644 (file)
@@ -2632,7 +2632,7 @@ static void update_image(struct image *img,
        insert_count = postimage->len;
 
        /* Adjust the contents */
-       result = xmalloc(img->len + insert_count - remove_count + 1);
+       result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));
        memcpy(result, img->buf, applied_at);
        memcpy(result + applied_at, postimage->buf, postimage->len);
        memcpy(result + applied_at + postimage->len,
index 5265f79..0b4f0bb 100644 (file)
@@ -459,13 +459,11 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin,
 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 @@ static int prepare_lines(struct scoreboard *sb)
        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;
index 3f6c825..7b45b6b 100644 (file)
@@ -570,7 +570,6 @@ static const char edit_description[] = "BRANCH_DESCRIPTION";
 
 static int edit_branch_description(const char *branch_name)
 {
-       int status;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf name = STRBUF_INIT;
 
@@ -595,11 +594,11 @@ static int edit_branch_description(const char *branch_name)
        strbuf_stripspace(&buf, 1);
 
        strbuf_addf(&name, "branch.%s.description", branch_name);
-       status = git_config_set(name.buf, buf.len ? buf.buf : NULL);
+       git_config_set(name.buf, buf.len ? buf.buf : NULL);
        strbuf_release(&name);
        strbuf_release(&buf);
 
-       return status;
+       return 0;
 }
 
 int cmd_branch(int argc, const char **argv, const char *prefix)
index fd915d5..eac4994 100644 (file)
@@ -20,7 +20,7 @@ static const char builtin_check_ref_format_usage[] =
  */
 static char *collapse_slashes(const char *refname)
 {
-       char *ret = xmalloc(strlen(refname) + 1);
+       char *ret = xmallocz(strlen(refname));
        char ch;
        char prev = '/';
        char *cp = ret;
index e8110a9..d53ab75 100644 (file)
@@ -981,7 +981,8 @@ static int parse_branchname_arg(int argc, const char **argv,
                 */
                int recover_with_dwim = dwim_new_local_branch_ok;
 
-               if (check_filename(NULL, arg) && !has_dash_dash)
+               if (!has_dash_dash &&
+                   (check_filename(NULL, arg) || !no_wildcard(arg)))
                        recover_with_dwim = 0;
                /*
                 * Accept "git checkout foo" and "git checkout foo --"
index 919157b..fb1824c 100644 (file)
@@ -543,7 +543,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
        int eof = 0;
        int i;
 
-       chosen = xmalloc(sizeof(int) * stuff->nr);
+       ALLOC_ARRAY(chosen, stuff->nr);
        /* set chosen as uninitialized */
        for (i = 0; i < stuff->nr; i++)
                chosen[i] = -1;
@@ -615,7 +615,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
                                nr += chosen[i];
                }
 
-               result = xcalloc(nr + 1, sizeof(int));
+               result = xcalloc(st_add(nr, 1), sizeof(int));
                for (i = 0; i < stuff->nr && j < nr; i++) {
                        if (chosen[i])
                                result[j++] = i;
index a0b3cd9..8a90cad 100644 (file)
@@ -732,7 +732,7 @@ static int checkout(void)
 
 static int write_one_config(const char *key, const char *value, void *data)
 {
-       return git_config_set_multivar(key, value ? value : "true", "^$", 0);
+       return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0);
 }
 
 static void write_config(struct string_list *config)
index adc7727..746233e 100644 (file)
@@ -352,6 +352,9 @@ static int get_colorbool(const char *var, int print)
 
 static void check_write(void)
 {
+       if (!given_config_source.file && !startup_info->have_repository)
+               die("not in a git directory");
+
        if (given_config_source.use_stdin)
                die("writing to stdin is not supported");
 
@@ -582,7 +585,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
-               ret = git_config_set_in_file(given_config_source.file, argv[0], value);
+               ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
                if (ret == CONFIG_NOTHING_SET)
                        error("cannot overwrite multiple values with a single value\n"
                        "       Use a regexp, --add or --replace-all to change %s.", argv[0]);
@@ -592,23 +595,23 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, argv[2], 0);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value, argv[2], 0);
        }
        else if (actions == ACTION_ADD) {
                check_write();
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value,
-                                                      CONFIG_REGEX_NONE, 0);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value,
+                                                             CONFIG_REGEX_NONE, 0);
        }
        else if (actions == ACTION_REPLACE_ALL) {
                check_write();
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, argv[2], 1);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value, argv[2], 1);
        }
        else if (actions == ACTION_GET) {
                check_argc(argc, 1, 2);
@@ -634,17 +637,17 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 1, 2);
                if (argc == 2)
-                       return git_config_set_multivar_in_file(given_config_source.file,
-                                                              argv[0], NULL, argv[1], 0);
+                       return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                                     argv[0], NULL, argv[1], 0);
                else
-                       return git_config_set_in_file(given_config_source.file,
-                                                     argv[0], NULL);
+                       return git_config_set_in_file_gently(given_config_source.file,
+                                                            argv[0], NULL);
        }
        else if (actions == ACTION_UNSET_ALL) {
                check_write();
                check_argc(argc, 1, 2);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], NULL, argv[1], 1);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], NULL, argv[1], 1);
        }
        else if (actions == ACTION_RENAME_SECTION) {
                int ret;
index 2471297..8164b58 100644 (file)
@@ -1021,7 +1021,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                const char **refspecs_str;
                int i;
 
-               refspecs_str = xmalloc(sizeof(*refspecs_str) * refspecs_list.nr);
+               ALLOC_ARRAY(refspecs_str, refspecs_list.nr);
                for (i = 0; i < refspecs_list.nr; i++)
                        refspecs_str[i] = refspecs_list.items[i].string;
 
index cf3019e..7d5914f 100644 (file)
@@ -10,33 +10,24 @@ static const char fetch_pack_usage[] =
 "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
 "[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
 
-static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
-                                const char *name, int namelen)
+static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
+                            const char *name)
 {
-       struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
+       struct ref *ref;
        struct object_id oid;
-       const int chunksz = GIT_SHA1_HEXSZ + 1;
 
-       if (namelen > chunksz && name[chunksz - 1] == ' ' &&
-               !get_oid_hex(name, &oid)) {
-               oidcpy(&ref->old_oid, &oid);
-               name += chunksz;
-               namelen -= chunksz;
-       }
+       if (!get_oid_hex(name, &oid) && name[GIT_SHA1_HEXSZ] == ' ')
+               name += GIT_SHA1_HEXSZ + 1;
+       else
+               oidclr(&oid);
 
-       memcpy(ref->name, name, namelen);
-       ref->name[namelen] = '\0';
+       ref = alloc_ref(name);
+       oidcpy(&ref->old_oid, &oid);
        (*nr)++;
        ALLOC_GROW(*sought, *nr, *alloc);
        (*sought)[*nr - 1] = ref;
 }
 
-static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
-                            const char *string)
-{
-       add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
-}
-
 int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 {
        int i, ret;
index 17f40e1..683f08e 100644 (file)
@@ -1107,7 +1107,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
        if (argc > 0) {
                int j = 0;
                int i;
-               refs = xcalloc(argc + 1, sizeof(const char *));
+               refs = xcalloc(st_add(argc, 1), sizeof(const char *));
                for (i = 0; i < argc; i++) {
                        if (!strcmp(argv[i], "tag")) {
                                i++;
index 3ba35ec..65c0201 100644 (file)
@@ -354,17 +354,17 @@ static void append_path(struct grep_opt *opt, const void *data, size_t len)
 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)
index 1cd0c1e..3c55ce4 100644 (file)
@@ -171,12 +171,10 @@ static void exec_man_cmd(const char *cmd, const char *page)
 static void add_man_viewer(const char *name)
 {
        struct man_viewer_list **p = &man_viewer_list;
-       size_t len = strlen(name);
 
        while (*p)
                p = &((*p)->next);
-       *p = xcalloc(1, (sizeof(**p) + len + 1));
-       memcpy((*p)->name, name, len); /* NUL-terminated by xcalloc */
+       FLEX_ALLOC_STR(*p, name, name);
 }
 
 static int supported_man_viewer(const char *name, size_t len)
@@ -190,9 +188,8 @@ static void do_add_man_viewer_info(const char *name,
                                   size_t len,
                                   const char *value)
 {
-       struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);
-
-       memcpy(new->name, name, len); /* NUL-terminated by xcalloc */
+       struct man_viewer_info_list *new;
+       FLEX_ALLOC_MEM(new, name, name, len);
        new->info = xstrdup(value);
        new->next = man_viewer_info_list;
        man_viewer_info_list = new;
index 6a01509..4524519 100644 (file)
@@ -1346,7 +1346,7 @@ static void fix_unresolved_deltas(struct sha1file *f)
         * before deltas depending on them, a good heuristic is to start
         * resolving deltas in the same order as their position in the pack.
         */
-       sorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos));
+       ALLOC_ARRAY(sorted_by_pos, nr_ref_deltas);
        for (i = 0; i < nr_ref_deltas; i++)
                sorted_by_pos[i] = &ref_deltas[i];
        qsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare);
@@ -1514,6 +1514,7 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
                if (!(off & 0x80000000))
                        continue;
                off = off & 0x7fffffff;
+               check_pack_index_ptr(p, &idx2[off * 2]);
                if (idx2[off * 2])
                        continue;
                /*
@@ -1744,9 +1745,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
 
        curr_pack = open_pack_file(pack_name);
        parse_pack_header();
-       objects = xcalloc(nr_objects + 1, sizeof(struct object_entry));
+       objects = xcalloc(st_add(nr_objects, 1), sizeof(struct object_entry));
        if (show_stat)
-               obj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat));
+               obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
        ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
        parse_pack_objects(pack_sha1);
        resolve_deltas();
@@ -1759,7 +1760,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (show_stat)
                show_pack_info(stat_only);
 
-       idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
+       ALLOC_ARRAY(idx_objects, nr_objects);
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;
        curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
index 07229d6..6223b7d 100644 (file)
@@ -250,7 +250,7 @@ static int create_default_files(const char *template_path)
                git_config_set("core.bare", "false");
                /* allow template config file to override the default */
                if (log_all_ref_updates == -1)
-                   git_config_set("core.logallrefupdates", "true");
+                       git_config_set("core.logallrefupdates", "true");
                if (needs_work_tree_config(get_git_dir(), work_tree))
                        git_config_set("core.worktree", work_tree);
        }
index a891162..c0d1822 100644 (file)
@@ -252,7 +252,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
        if (argc < 2)
                usage_with_options(merge_base_usage, options);
 
-       rev = xmalloc(argc * sizeof(*rev));
+       ALLOC_ARRAY(rev, argc);
        while (argc-- > 0)
                rev[rev_nr++] = get_commit_reference(*argv++);
        return show_merge_base(rev, rev_nr, show_all);
index d4f0cbd..ca57004 100644 (file)
@@ -174,7 +174,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi
 
 static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
 {
-       char *path = xmalloc(traverse_path_len(info, n) + 1);
+       char *path = xmallocz(traverse_path_len(info, n));
        return make_traverse_path(path, info, n);
 }
 
index b98a348..101ffef 100644 (file)
@@ -939,7 +939,7 @@ static int setup_with_upstream(const char ***argv)
        if (!branch->merge_nr)
                die(_("No default upstream defined for the current branch."));
 
-       args = xcalloc(branch->merge_nr + 1, sizeof(char *));
+       args = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));
        for (i = 0; i < branch->merge_nr; i++) {
                if (!branch->merge[i]->dst)
                        die(_("No remote-tracking branch for %s from %s"),
index a964d6b..b0aab65 100644 (file)
@@ -19,16 +19,17 @@ static int alloc, used;
 static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)
 {
        struct treeent *ent;
-       int len = strlen(path);
+       size_t len = strlen(path);
        if (strchr(path, '/'))
                die("path %s contains slash", path);
 
-       ALLOC_GROW(entries, used + 1, alloc);
-       ent = entries[used++] = xmalloc(sizeof(**entries) + len + 1);
+       FLEX_ALLOC_MEM(ent, name, path, len);
        ent->mode = mode;
        ent->len = len;
        hashcpy(ent->sha1, sha1);
-       memcpy(ent->name, path, len+1);
+
+       ALLOC_GROW(entries, used + 1, alloc);
+       entries[used++] = ent;
 }
 
 static int ent_compare(const void *a_, const void *b_)
index d1d4316..aeae855 100644 (file)
@@ -24,7 +24,8 @@ static const char **internal_copy_pathspec(const char *prefix,
                                           int count, unsigned flags)
 {
        int i;
-       const char **result = xmalloc((count + 1) * sizeof(const char *));
+       const char **result;
+       ALLOC_ARRAY(result, count + 1);
        memcpy(result, pathspec, count * sizeof(const char *));
        result[count] = NULL;
        for (i = 0; i < count; i++) {
@@ -47,9 +48,9 @@ static const char **internal_copy_pathspec(const char *prefix,
 
 static const char *add_slash(const char *path)
 {
-       int len = strlen(path);
+       size_t len = strlen(path);
        if (path[len - 1] != '/') {
-               char *with_slash = xmalloc(len + 2);
+               char *with_slash = xmalloc(st_add(len, 2));
                memcpy(with_slash, path, len);
                with_slash[len++] = '/';
                with_slash[len] = 0;
index 4dae5b1..b4f1fa6 100644 (file)
@@ -624,7 +624,7 @@ static struct object_entry **compute_write_order(void)
 {
        unsigned int i, wo_end, last_untagged;
 
-       struct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));
+       struct object_entry **wo;
        struct object_entry *objects = to_pack.objects;
 
        for (i = 0; i < to_pack.nr_objects; i++) {
@@ -657,6 +657,7 @@ static struct object_entry **compute_write_order(void)
         * Give the objects in the original recency order until
         * we see a tagged tip.
         */
+       ALLOC_ARRAY(wo, to_pack.nr_objects);
        for (i = wo_end = 0; i < to_pack.nr_objects; i++) {
                if (objects[i].tagged)
                        break;
@@ -769,7 +770,7 @@ static void write_pack_file(void)
 
        if (progress > pack_to_stdout)
                progress_state = start_progress(_("Writing objects"), nr_result);
-       written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));
+       ALLOC_ARRAY(written_list, to_pack.nr_objects);
        write_order = compute_write_order();
 
        do {
@@ -2129,7 +2130,7 @@ static void prepare_pack(int window, int depth)
        if (!to_pack.nr_objects || !window || !depth)
                return;
 
-       delta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));
+       ALLOC_ARRAY(delta_list, to_pack.nr_objects);
        nr_deltas = n = 0;
 
        for (i = 0; i < to_pack.nr_objects; i++) {
index d0532f6..72c8158 100644 (file)
@@ -53,7 +53,7 @@ static inline struct llist_item *llist_item_get(void)
                free_nodes = free_nodes->next;
        } else {
                int i = 1;
-               new = xmalloc(sizeof(struct llist_item) * BLKSIZE);
+               ALLOC_ARRAY(new, BLKSIZE);
                for (; i < BLKSIZE; i++)
                        llist_item_put(&new[i]);
        }
index f2d6761..c8e32b2 100644 (file)
@@ -1031,7 +1031,6 @@ static void run_update_post_hook(struct command *commands)
 {
        struct command *cmd;
        int argc;
-       const char **argv;
        struct child_process proc = CHILD_PROCESS_INIT;
        const char *hook;
 
@@ -1044,21 +1043,16 @@ static void run_update_post_hook(struct command *commands)
        if (!argc || !hook)
                return;
 
-       argv = xmalloc(sizeof(*argv) * (2 + argc));
-       argv[0] = hook;
-
-       for (argc = 1, cmd = commands; cmd; cmd = cmd->next) {
+       argv_array_push(&proc.args, hook);
+       for (cmd = commands; cmd; cmd = cmd->next) {
                if (cmd->error_string || cmd->did_not_exist)
                        continue;
-               argv[argc] = xstrdup(cmd->ref_name);
-               argc++;
+               argv_array_push(&proc.args, cmd->ref_name);
        }
-       argv[argc] = NULL;
 
        proc.no_stdin = 1;
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
-       proc.argv = argv;
 
        if (!start_command(&proc)) {
                if (use_sideband)
@@ -1378,7 +1372,7 @@ static struct command **queue_command(struct command **tail,
 
        refname = line + 82;
        reflen = linelen - 82;
-       cmd = xcalloc(1, sizeof(struct command) + reflen + 1);
+       cmd = xcalloc(1, st_add3(sizeof(struct command), reflen, 1));
        hashcpy(cmd->old_sha1, old_sha1);
        hashcpy(cmd->new_sha1, new_sha1);
        memcpy(cmd->ref_name, refname, reflen);
@@ -1597,8 +1591,7 @@ static void prepare_shallow_update(struct command *commands,
 {
        int i, j, k, bitmap_size = (si->ref->nr + 31) / 32;
 
-       si->used_shallow = xmalloc(sizeof(*si->used_shallow) *
-                                  si->shallow->nr);
+       ALLOC_ARRAY(si->used_shallow, si->shallow->nr);
        assign_shallow_commits_to_refs(si, si->used_shallow, NULL);
 
        si->need_reachability_test =
@@ -1664,7 +1657,7 @@ static void update_shallow_info(struct command *commands,
                return;
        }
 
-       ref_status = xmalloc(sizeof(*ref_status) * ref->nr);
+       ALLOC_ARRAY(ref_status, ref->nr);
        assign_shallow_commits_to_refs(si, NULL, ref_status);
        for (cmd = commands; cmd; cmd = cmd->next) {
                if (is_null_sha1(cmd->new_sha1))
index f39960e..2d46b64 100644 (file)
@@ -382,11 +382,9 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
 {
        struct collected_reflog *e;
        struct collect_reflog_cb *cb = cb_data;
-       size_t namelen = strlen(ref);
 
-       e = xmalloc(sizeof(*e) + namelen + 1);
+       FLEX_ALLOC_STR(e, reflog, ref);
        hashcpy(e->sha1, oid->hash);
-       memcpy(e->reflog, ref, namelen + 1);
        ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
        cb->e[cb->nr++] = e;
        return 0;
@@ -396,7 +394,6 @@ static struct reflog_expire_cfg {
        struct reflog_expire_cfg *next;
        unsigned long expire_total;
        unsigned long expire_unreachable;
-       size_t len;
        char pattern[FLEX_ARRAY];
 } *reflog_expire_cfg, **reflog_expire_cfg_tail;
 
@@ -408,13 +405,11 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
                reflog_expire_cfg_tail = &reflog_expire_cfg;
 
        for (ent = reflog_expire_cfg; ent; ent = ent->next)
-               if (ent->len == len &&
-                   !memcmp(ent->pattern, pattern, len))
+               if (!strncmp(ent->pattern, pattern, len) &&
+                   ent->pattern[len] == '\0')
                        return ent;
 
-       ent = xcalloc(1, (sizeof(*ent) + len));
-       memcpy(ent->pattern, pattern, len);
-       ent->len = len;
+       FLEX_ALLOC_MEM(ent, pattern, pattern, len);
        *reflog_expire_cfg_tail = ent;
        reflog_expire_cfg_tail = &(ent->next);
        return ent;
index e3cd25d..7457c74 100644 (file)
@@ -114,30 +114,14 @@ static char *strip_escapes(const char *str, const char *service,
        }
 }
 
-/* Should be enough... */
-#define MAXARGUMENTS 256
-
-static const char **parse_argv(const char *arg, const char *service)
+static void parse_argv(struct argv_array *out, const char *arg, const char *service)
 {
-       int arguments = 0;
-       int i;
-       const char **ret;
-       char *temparray[MAXARGUMENTS + 1];
-
        while (*arg) {
-               char *expanded;
-               if (arguments == MAXARGUMENTS)
-                       die("remote-ext command has too many arguments");
-               expanded = strip_escapes(arg, service, &arg);
+               char *expanded = strip_escapes(arg, service, &arg);
                if (expanded)
-                       temparray[arguments++] = expanded;
+                       argv_array_push(out, expanded);
+               free(expanded);
        }
-
-       ret = xmalloc((arguments + 1) * sizeof(char *));
-       for (i = 0; i < arguments; i++)
-               ret[i] = temparray[i];
-       ret[arguments] = NULL;
-       return ret;
 }
 
 static void send_git_request(int stdin_fd, const char *serv, const char *repo,
@@ -158,7 +142,7 @@ static int run_child(const char *arg, const char *service)
        child.in = -1;
        child.out = -1;
        child.err = 0;
-       child.argv = parse_argv(arg, service);
+       parse_argv(&child.args, arg, service);
 
        if (start_command(&child) < 0)
                die("Can't run specified command");
index 6694cf2..4313695 100644 (file)
@@ -108,8 +108,8 @@ enum {
 #define MIRROR_PUSH 2
 #define MIRROR_BOTH (MIRROR_FETCH|MIRROR_PUSH)
 
-static int add_branch(const char *key, const char *branchname,
-               const char *remotename, int mirror, struct strbuf *tmp)
+static void add_branch(const char *key, const char *branchname,
+                      const char *remotename, int mirror, struct strbuf *tmp)
 {
        strbuf_reset(tmp);
        strbuf_addch(tmp, '+');
@@ -119,7 +119,7 @@ static int add_branch(const char *key, const char *branchname,
        else
                strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
                                branchname, remotename, branchname);
-       return git_config_set_multivar(key, tmp->buf, "^$", 0);
+       git_config_set_multivar(key, tmp->buf, "^$", 0);
 }
 
 static const char mirror_advice[] =
@@ -197,8 +197,7 @@ static int add(int argc, const char **argv)
                die(_("'%s' is not a valid remote name"), name);
 
        strbuf_addf(&buf, "remote.%s.url", name);
-       if (git_config_set(buf.buf, url))
-               return 1;
+       git_config_set(buf.buf, url);
 
        if (!mirror || mirror & MIRROR_FETCH) {
                strbuf_reset(&buf);
@@ -206,25 +205,22 @@ static int add(int argc, const char **argv)
                if (track.nr == 0)
                        string_list_append(&track, "*");
                for (i = 0; i < track.nr; i++) {
-                       if (add_branch(buf.buf, track.items[i].string,
-                                      name, mirror, &buf2))
-                               return 1;
+                       add_branch(buf.buf, track.items[i].string,
+                                  name, mirror, &buf2);
                }
        }
 
        if (mirror & MIRROR_PUSH) {
                strbuf_reset(&buf);
                strbuf_addf(&buf, "remote.%s.mirror", name);
-               if (git_config_set(buf.buf, "true"))
-                       return 1;
+               git_config_set(buf.buf, "true");
        }
 
        if (fetch_tags != TAGS_DEFAULT) {
                strbuf_reset(&buf);
                strbuf_addf(&buf, "remote.%s.tagopt", name);
-               if (git_config_set(buf.buf,
-                       fetch_tags == TAGS_SET ? "--tags" : "--no-tags"))
-                       return 1;
+               git_config_set(buf.buf,
+                              fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
        }
 
        if (fetch && fetch_remote(name))
@@ -590,25 +586,20 @@ static int migrate_file(struct remote *remote)
 
        strbuf_addf(&buf, "remote.%s.url", remote->name);
        for (i = 0; i < remote->url_nr; i++)
-               if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0))
-                       return error(_("Could not append '%s' to '%s'"),
-                                       remote->url[i], buf.buf);
+               git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
        strbuf_reset(&buf);
        strbuf_addf(&buf, "remote.%s.push", remote->name);
        for (i = 0; i < remote->push_refspec_nr; i++)
-               if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0))
-                       return error(_("Could not append '%s' to '%s'"),
-                                       remote->push_refspec[i], buf.buf);
+               git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0);
        strbuf_reset(&buf);
        strbuf_addf(&buf, "remote.%s.fetch", remote->name);
        for (i = 0; i < remote->fetch_refspec_nr; i++)
-               if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0))
-                       return error(_("Could not append '%s' to '%s'"),
-                                       remote->fetch_refspec[i], buf.buf);
+               git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0);
        if (remote->origin == REMOTE_REMOTES)
                unlink_or_warn(git_path("remotes/%s", remote->name));
        else if (remote->origin == REMOTE_BRANCHES)
                unlink_or_warn(git_path("branches/%s", remote->name));
+
        return 0;
 }
 
@@ -655,8 +646,7 @@ static int mv(int argc, const char **argv)
 
        strbuf_reset(&buf);
        strbuf_addf(&buf, "remote.%s.fetch", rename.new);
-       if (git_config_set_multivar(buf.buf, NULL, NULL, 1))
-               return error(_("Could not remove config section '%s'"), buf.buf);
+       git_config_set_multivar(buf.buf, NULL, NULL, 1);
        strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old);
        for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
                char *ptr;
@@ -676,8 +666,7 @@ static int mv(int argc, const char **argv)
                                  "\tPlease update the configuration manually if necessary."),
                                buf2.buf);
 
-               if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
-                       return error(_("Could not append '%s'"), buf.buf);
+               git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
        }
 
        read_branches();
@@ -687,9 +676,7 @@ static int mv(int argc, const char **argv)
                if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
                        strbuf_reset(&buf);
                        strbuf_addf(&buf, "branch.%s.remote", item->string);
-                       if (git_config_set(buf.buf, rename.new)) {
-                               return error(_("Could not set '%s'"), buf.buf);
-                       }
+                       git_config_set(buf.buf, rename.new);
                }
        }
 
@@ -787,10 +774,7 @@ static int rm(int argc, const char **argv)
                                strbuf_reset(&buf);
                                strbuf_addf(&buf, "branch.%s.%s",
                                                item->string, *k);
-                               if (git_config_set(buf.buf, NULL)) {
-                                       strbuf_release(&buf);
-                                       return -1;
-                               }
+                               git_config_set(buf.buf, NULL);
                        }
                }
        }
@@ -1409,24 +1393,20 @@ static int update(int argc, const char **argv)
 
 static int remove_all_fetch_refspecs(const char *remote, const char *key)
 {
-       return git_config_set_multivar(key, NULL, NULL, 1);
+       return git_config_set_multivar_gently(key, NULL, NULL, 1);
 }
 
-static int add_branches(struct remote *remote, const char **branches,
-                       const char *key)
+static void add_branches(struct remote *remote, const char **branches,
+                        const char *key)
 {
        const char *remotename = remote->name;
        int mirror = remote->mirror;
        struct strbuf refspec = STRBUF_INIT;
 
        for (; *branches; branches++)
-               if (add_branch(key, *branches, remotename, mirror, &refspec)) {
-                       strbuf_release(&refspec);
-                       return 1;
-               }
+               add_branch(key, *branches, remotename, mirror, &refspec);
 
        strbuf_release(&refspec);
-       return 0;
 }
 
 static int set_remote_branches(const char *remotename, const char **branches,
@@ -1445,10 +1425,7 @@ static int set_remote_branches(const char *remotename, const char **branches,
                strbuf_release(&key);
                return 1;
        }
-       if (add_branches(remote, branches, key.buf)) {
-               strbuf_release(&key);
-               return 1;
-       }
+       add_branches(remote, branches, key.buf);
 
        strbuf_release(&key);
        return 0;
@@ -1580,10 +1557,11 @@ static int set_url(int argc, const char **argv)
        if ((!oldurl && !delete_mode) || add_mode) {
                if (add_mode)
                        git_config_set_multivar(name_buf.buf, newurl,
-                               "^$", 0);
+                                                      "^$", 0);
                else
                        git_config_set(name_buf.buf, newurl);
                strbuf_release(&name_buf);
+
                return 0;
        }
 
index 7e074aa..7a4f2c0 100644 (file)
@@ -763,7 +763,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                continue;
                        }
                        if (!strcmp(arg, "--git-common-dir")) {
-                               puts(get_git_common_dir());
+                               const char *pfx = prefix ? prefix : "";
+                               puts(prefix_filename(pfx, strlen(pfx), get_git_common_dir()));
                                continue;
                        }
                        if (!strcmp(arg, "--resolve-git-dir")) {
index f4c3eff..ed764c9 100644 (file)
@@ -22,17 +22,12 @@ static int module_list_compute(int argc, const char **argv,
                               struct module_list *list)
 {
        int i, result = 0;
-       char *max_prefix, *ps_matched = NULL;
-       int max_prefix_len;
+       char *ps_matched = NULL;
        parse_pathspec(pathspec, 0,
                       PATHSPEC_PREFER_FULL |
                       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
                       prefix, argv);
 
-       /* Find common prefix for all pathspec's */
-       max_prefix = common_prefix(pathspec);
-       max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
-
        if (pathspec->nr)
                ps_matched = xcalloc(pathspec->nr, 1);
 
@@ -44,7 +39,7 @@ static int module_list_compute(int argc, const char **argv,
 
                if (!S_ISGITLINK(ce->ce_mode) ||
                    !match_pathspec(pathspec, ce->name, ce_namelen(ce),
-                                   max_prefix_len, ps_matched, 1))
+                                   0, ps_matched, 1))
                        continue;
 
                ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
@@ -57,7 +52,6 @@ static int module_list_compute(int argc, const char **argv,
                         */
                        i++;
        }
-       free(max_prefix);
 
        if (ps_matched && report_path_error(ps_matched, pathspec, prefix))
                result = -1;
index 475b958..0a45710 100644 (file)
@@ -52,7 +52,7 @@ static int prune_worktree(const char *id, struct strbuf *reason)
                return 1;
        }
        len = st.st_size;
-       path = xmalloc(len + 1);
+       path = xmallocz(len);
        read_in_full(fd, path, len);
        close(fd);
        while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
index 20ee7b5..3ebf9c3 100644 (file)
@@ -79,11 +79,9 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,
        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,
diff --git a/cache.h b/cache.h
index 015d53b..1a2cec0 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -228,7 +228,9 @@ struct cache_entry {
 #error "CE_EXTENDED_FLAGS out of range"
 #endif
 
+/* Forward structure decls */
 struct pathspec;
+struct child_process;
 
 /*
  * Copy the sha1 and stat state of a cache entry from one to
@@ -1366,6 +1368,16 @@ extern void clear_delta_base_cache(void);
 extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
 
 /*
+ * Make sure that a pointer access into an mmap'd index file is within bounds,
+ * and can provide at least 8 bytes of data.
+ *
+ * Note that this is only necessary for variable-length segments of the file
+ * (like the 64-bit extended offset table), as we compare the size to the
+ * fixed-length parts when we open the file.
+ */
+extern void check_pack_index_ptr(const struct packed_git *p, const void *ptr);
+
+/*
  * Return the SHA-1 of the nth object within the specified packfile.
  * Open the index if it is not already open.  The return value points
  * at the SHA-1 within the mmapped index.  Return NULL if there is an
@@ -1485,7 +1497,7 @@ extern int update_server_info(int);
 /* git_config_parse_key() returns these negated: */
 #define CONFIG_INVALID_KEY 1
 #define CONFIG_NO_SECTION_OR_NAME 2
-/* git_config_set(), git_config_set_multivar() return the above or these: */
+/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
 #define CONFIG_NO_LOCK -1
 #define CONFIG_INVALID_FILE 3
 #define CONFIG_NO_WRITE 4
@@ -1523,12 +1535,16 @@ extern int git_config_bool(const char *, const char *);
 extern int git_config_maybe_bool(const char *, const char *);
 extern int git_config_string(const char **, const char *, const char *);
 extern int git_config_pathname(const char **, const char *, const char *);
-extern int git_config_set_in_file(const char *, const char *, const char *);
-extern int git_config_set(const char *, const char *);
+extern int git_config_set_in_file_gently(const char *, const char *, const char *);
+extern void git_config_set_in_file(const char *, const char *, const char *);
+extern int git_config_set_gently(const char *, const char *);
+extern void git_config_set(const char *, const char *);
 extern int git_config_parse_key(const char *, char **, int *);
 extern int git_config_key_is_valid(const char *key);
-extern int git_config_set_multivar(const char *, const char *, const char *, int);
-extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
+extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
+extern void git_config_set_multivar(const char *, const char *, const char *, int);
+extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
+extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
 extern int git_config_rename_section_in_file(const char *, const char *, const char *);
 extern const char *git_etc_gitconfig(void);
@@ -1675,6 +1691,7 @@ extern int pager_use_color;
 extern int term_columns(void);
 extern int decimal_width(uintmax_t);
 extern int check_pager_config(const char *cmd);
+extern void prepare_pager_args(struct child_process *, const char *pager);
 
 extern const char *editor_program;
 extern const char *askpass_program;
index 786abe6..d55ead1 100644 (file)
--- a/column.c
+++ b/column.c
@@ -164,7 +164,7 @@ static void display_table(const struct string_list *list,
        data.colopts = colopts;
        data.opts = *opts;
 
-       data.len = xmalloc(sizeof(*data.len) * list->nr);
+       ALLOC_ARRAY(data.len, list->nr);
        for (i = 0; i < list->nr; i++)
                data.len[i] = item_length(colopts, list->items[i].string);
 
@@ -173,9 +173,8 @@ static void display_table(const struct string_list *list,
        if (colopts & COL_DENSE)
                shrink_columns(&data);
 
-       empty_cell = xmalloc(initial_width + 1);
+       empty_cell = xmallocz(initial_width);
        memset(empty_cell, ' ', initial_width);
-       empty_cell[initial_width] = '\0';
        for (y = 0; y < data.rows; y++) {
                for (x = 0; x < data.cols; x++)
                        if (display_cell(&data, initial_width, empty_cell, x, y))
index 5571304..0e1d4b0 100644 (file)
@@ -189,11 +189,11 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
         *   - Else if we have NEW, insert newend lline into base and
         *   consume newend
         */
-       lcs = xcalloc(origbaselen + 1, sizeof(int*));
-       directions = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));
+       lcs = xcalloc(st_add(origbaselen, 1), sizeof(int*));
+       directions = xcalloc(st_add(origbaselen, 1), sizeof(enum coalesce_direction*));
        for (i = 0; i < origbaselen + 1; i++) {
-               lcs[i] = xcalloc(lennew + 1, sizeof(int));
-               directions[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));
+               lcs[i] = xcalloc(st_add(lennew, 1), sizeof(int));
+               directions[i] = xcalloc(st_add(lennew, 1), sizeof(enum coalesce_direction));
                directions[i][0] = BASE;
        }
        for (j = 1; j < lennew + 1; j++)
@@ -319,7 +319,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
        if (line[len-1] == '\n')
                len--;
 
-       lline = xmalloc(sizeof(*lline) + len + 1);
+       FLEX_ALLOC_MEM(lline, line, line, len);
        lline->len = len;
        lline->next = NULL;
        lline->prev = sline->plost.lost_tail;
@@ -330,8 +330,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
        sline->plost.lost_tail = lline;
        sline->plost.len++;
        lline->parent_map = this_mask;
-       memcpy(lline->line, line, len);
-       lline->line[len] = 0;
 }
 
 struct combine_diff_state {
@@ -1043,7 +1041,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                                elem->mode = canon_mode(S_IFLNK);
 
                        result_size = len;
-                       result = xmalloc(len + 1);
+                       result = xmallocz(len);
 
                        done = read_in_full(fd, result, len);
                        if (done < 0)
@@ -1051,8 +1049,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        else if (done < len)
                                die("early EOF '%s'", elem->path);
 
-                       result[len] = 0;
-
                        /* If not a fake symlink, apply filters, e.g. autocrlf */
                        if (is_file) {
                                struct strbuf buf = STRBUF_INIT;
@@ -1115,7 +1111,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        if (result_size && result[result_size-1] != '\n')
                cnt++; /* incomplete line */
 
-       sline = xcalloc(cnt+2, sizeof(*sline));
+       sline = xcalloc(st_add(cnt, 2), sizeof(*sline));
        sline[0].bol = result;
        for (lno = 0, cp = result; cp < result + result_size; cp++) {
                if (*cp == '\n') {
@@ -1134,7 +1130,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        /* Even p_lno[cnt+1] is valid -- that is for the end line number
         * for deletion hunk at the end.
         */
-       sline[0].p_lno = xcalloc((cnt+2) * num_parent, sizeof(unsigned long));
+       sline[0].p_lno = xcalloc(st_mult(st_add(cnt, 2), num_parent), sizeof(unsigned long));
        for (lno = 0; lno <= cnt; lno++)
                sline[lno+1].p_lno = sline[lno].p_lno + num_parent;
 
@@ -1266,7 +1262,7 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p,
        struct diff_filespec *pool;
 
        pair = xmalloc(sizeof(*pair));
-       pool = xcalloc(num_parent + 1, sizeof(struct diff_filespec));
+       pool = xcalloc(st_add(num_parent, 1), sizeof(struct diff_filespec));
        pair->one = pool + 1;
        pair->two = pool;
 
@@ -1372,7 +1368,7 @@ static struct combine_diff_path *find_paths_multitree(
        struct combine_diff_path paths_head;
        struct strbuf base;
 
-       parents_sha1 = xmalloc(nparent * sizeof(parents_sha1[0]));
+       ALLOC_ARRAY(parents_sha1, nparent);
        for (i = 0; i < nparent; i++)
                parents_sha1[i] = parents->sha1[i];
 
@@ -1483,7 +1479,7 @@ void diff_tree_combined(const unsigned char *sha1,
        if (opt->orderfile && num_paths) {
                struct obj_order *o;
 
-               o = xmalloc(sizeof(*o) * num_paths);
+               ALLOC_ARRAY(o, num_paths);
                for (i = 0, p = paths; p; p = p->next, i++)
                        o[i].obj = p;
                order_objects(opt->orderfile, path_path, o, num_paths);
index 40388d7..3f4f371 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -147,7 +147,7 @@ struct commit_graft *read_graft_line(char *buf, int len)
        if ((len + 1) % entry_size)
                goto bad_graft_data;
        i = (len + 1) / entry_size - 1;
-       graft = xmalloc(sizeof(*graft) + GIT_SHA1_RAWSZ * i);
+       graft = xmalloc(st_add(sizeof(*graft), st_mult(GIT_SHA1_RAWSZ, i)));
        graft->nr_parent = i;
        if (get_oid_hex(buf, &graft->oid))
                goto bad_graft_data;
@@ -903,7 +903,7 @@ static int remove_redundant(struct commit **array, int cnt)
 
        work = xcalloc(cnt, sizeof(*work));
        redundant = xcalloc(cnt, 1);
-       filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
+       ALLOC_ARRAY(filled_index, cnt - 1);
 
        for (i = 0; i < cnt; i++)
                parse_commit(array[i]);
index 9b2a1f5..af56c1f 100644 (file)
@@ -769,7 +769,7 @@ static const char *quote_arg(const char *arg)
                return arg;
 
        /* insert \ where necessary */
-       d = q = xmalloc(len+n+3);
+       d = q = xmalloc(st_add3(len, n, 3));
        *d++ = '"';
        while (*arg) {
                if (*arg == '"')
@@ -852,7 +852,7 @@ static char **get_path_split(void)
        if (!n)
                return NULL;
 
-       path = xmalloc((n+1)*sizeof(char *));
+       ALLOC_ARRAY(path, n + 1);
        p = envpath;
        i = 0;
        do {
@@ -937,7 +937,7 @@ static wchar_t *make_environment_block(char **deltaenv)
                i++;
 
        /* copy the environment, leaving space for changes */
-       tmpenv = xmalloc((size + i) * sizeof(char*));
+       ALLOC_ARRAY(tmpenv, size + i);
        memcpy(tmpenv, environ, size * sizeof(char*));
 
        /* merge supplied environment changes into the temporary environment */
@@ -1028,7 +1028,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
                        free(quoted);
        }
 
-       wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+       ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1));
        xutftowcs(wargs, args.buf, 2 * args.len + 1);
        strbuf_release(&args);
 
@@ -1127,7 +1127,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
                int argc = 0;
                const char **argv2;
                while (argv[argc]) argc++;
-               argv2 = xmalloc(sizeof(*argv) * (argc+1));
+               ALLOC_ARRAY(argv2, argc + 1);
                argv2[0] = (char *)cmd; /* full path to the script file */
                memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
                pid = mingw_spawnv(prog, argv2, 1);
index 079070f..dfbe6d8 100644 (file)
@@ -50,7 +50,8 @@ void probe_utf8_pathname_composition(void)
                close(output_fd);
                git_path_buf(&path, "%s", auml_nfd);
                precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
-               git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false");
+               git_config_set("core.precomposeunicode",
+                              precomposed_unicode ? "true" : "false");
                git_path_buf(&path, "%s", auml_nfc);
                if (unlink(path.buf))
                        die_errno(_("failed to unlink '%s'"), path.buf);
index 9574d53..7d071af 100644 (file)
@@ -47,7 +47,7 @@ static void msort_with_tmp(void *b, size_t n, size_t s,
 void git_qsort(void *b, size_t n, size_t s,
               int (*cmp)(const void *, const void *))
 {
-       const size_t size = n * s;
+       const size_t size = st_mult(n, s);
        char buf[1024];
 
        if (size < sizeof(buf)) {
index fc1439a..7849f25 100644 (file)
@@ -18,7 +18,7 @@ int gitsetenv(const char *name, const char *value, int replace)
 
        namelen = strlen(name);
        valuelen = strlen(value);
-       envstr = malloc((namelen + valuelen + 2));
+       envstr = malloc(st_add3(namelen, valuelen, 2));
        if (!envstr) {
                errno = ENOMEM;
                return -1;
index d015e43..b905aea 100644 (file)
@@ -32,7 +32,7 @@ void syslog(int priority, const char *fmt, ...)
                return;
        }
 
-       str = malloc(str_len + 1);
+       str = malloc(st_add(str_len, 1));
        if (!str) {
                warning("malloc failed: '%s'", strerror(errno));
                return;
@@ -43,7 +43,7 @@ void syslog(int priority, const char *fmt, ...)
        va_end(ap);
 
        while ((pos = strstr(str, "%1")) != NULL) {
-               str = realloc(str, ++str_len + 1);
+               str = realloc(str, st_add(++str_len, 1));
                if (!str) {
                        warning("realloc failed: '%s'", strerror(errno));
                        return;
index 86a5eb2..03544e7 100644 (file)
--- a/config.c
+++ b/config.c
@@ -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);
 }
 
 /*
@@ -1878,7 +1889,7 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele
         * 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++) {
@@ -1902,8 +1913,6 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele
                if (store_key)
                        (*store_key)[i] = c;
        }
-       if (store_key)
-               (*store_key)[i] = 0;
 
        return 0;
 
@@ -1950,9 +1959,10 @@ int git_config_key_is_valid(const char *key)
  * - 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;
@@ -2179,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)
index be70cd4..1e258ac 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -808,7 +808,7 @@ static void check_dead_children(void)
                        cradle = &blanket->next;
 }
 
-static char **cld_argv;
+static struct argv_array cld_argv = ARGV_ARRAY_INIT;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
        struct child_process cld = CHILD_PROCESS_INIT;
@@ -842,7 +842,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 #endif
        }
 
-       cld.argv = (const char **)cld_argv;
+       cld.argv = cld_argv.argv;
        cld.in = incoming;
        cld.out = dup(incoming);
 
@@ -1374,12 +1374,10 @@ int main(int argc, char **argv)
                write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
 
        /* prepare argv for serving-processes */
-       cld_argv = xmalloc(sizeof (char *) * (argc + 2));
-       cld_argv[0] = argv[0];  /* git-daemon */
-       cld_argv[1] = "--serve";
+       argv_array_push(&cld_argv, argv[0]); /* git-daemon */
+       argv_array_push(&cld_argv, "--serve");
        for (i = 1; i < argc; ++i)
-               cld_argv[i+1] = argv[i];
-       cld_argv[argc+1] = NULL;
+               argv_array_push(&cld_argv, argv[i]);
 
        return serve(&listen_addr, listen_port, cred);
 }
diff --git a/diff.c b/diff.c
index 2136b69..059123c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -2607,12 +2607,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
 
 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 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
 
 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 @@ size_t fill_textconv(struct userdiff_driver *driver,
 {
        size_t size;
 
-       if (!driver || !driver->textconv) {
+       if (!driver) {
                if (!DIFF_FILE_VALID(df)) {
                        *outbuf = "";
                        return 0;
@@ -5096,6 +5093,9 @@ size_t fill_textconv(struct userdiff_driver *driver,
                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 --git a/diff.h b/diff.h
index 70b2d70..e7d68ed 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -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,10 +349,26 @@ extern void diff_no_index(struct rev_info *, int, const char **);
 
 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);
index 7cf431d..4159748 100644 (file)
@@ -53,7 +53,8 @@ static struct spanhash_top *spanhash_rehash(struct spanhash_top *orig)
        int osz = 1 << orig->alloc_log2;
        int sz = osz << 1;
 
-       new = xmalloc(sizeof(*orig) + sizeof(struct spanhash) * sz);
+       new = xmalloc(st_add(sizeof(*orig),
+                            st_mult(sizeof(struct spanhash), sz)));
        new->alloc_log2 = orig->alloc_log2 + 1;
        new->free = INITIAL_FREE(new->alloc_log2);
        memset(new->data, 0, sizeof(struct spanhash) * sz);
@@ -130,7 +131,8 @@ static struct spanhash_top *hash_chars(struct diff_filespec *one)
        int is_text = !diff_filespec_is_binary(one);
 
        i = INITIAL_HASH_SIZE;
-       hash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i));
+       hash = xmalloc(st_add(sizeof(*hash),
+                             st_mult(sizeof(struct spanhash), 1<<i)));
        hash->alloc_log2 = i;
        hash->free = INITIAL_FREE(i);
        memset(hash->data, 0, sizeof(struct spanhash) * (1<<i));
index 97dd3d0..69d41f7 100644 (file)
@@ -52,7 +52,7 @@ static void prepare_order(const char *orderfile)
                }
                if (pass == 0) {
                        order_cnt = cnt;
-                       order = xmalloc(sizeof(*order) * cnt);
+                       ALLOC_ARRAY(order, cnt);
                }
        }
 }
@@ -120,7 +120,7 @@ void diffcore_order(const char *orderfile)
        if (!q->nr)
                return;
 
-       o = xmalloc(sizeof(*o) * q->nr);
+       ALLOC_ARRAY(o, q->nr);
        for (i = 0; i < q->nr; i++)
                o[i].obj = q->queue[i];
        order_objects(orderfile, pair_pathtwo, o, q->nr);
index af1fe08..3b3c1ed 100644 (file)
@@ -537,7 +537,7 @@ void diffcore_rename(struct diff_options *options)
                                rename_dst_nr * rename_src_nr, 50, 1);
        }
 
-       mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
+       mx = xcalloc(st_mult(num_create, NUM_CANDIDATE_PER_DST), sizeof(*mx));
        for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
                struct diff_filespec *two = rename_dst[i].two;
                struct diff_score *m;
diff --git a/dir.c b/dir.c
index 29aec12..3087b7e 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -503,12 +503,7 @@ void add_exclude(const char *string, const char *base,
 
        parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);
        if (flags & EXC_FLAG_MUSTBEDIR) {
-               char *s;
-               x = xmalloc(sizeof(*x) + patternlen + 1);
-               s = (char *)(x+1);
-               memcpy(s, string, patternlen);
-               s[patternlen] = '\0';
-               x->pattern = s;
+               FLEXPTR_ALLOC_MEM(x, pattern, string, patternlen);
        } else {
                x = xmalloc(sizeof(*x));
                x->pattern = string;
@@ -625,10 +620,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,
        }
 
        uc->dir_created++;
-       d = xmalloc(sizeof(*d) + len + 1);
-       memset(d, 0, sizeof(*d));
-       memcpy(d->name, name, len);
-       d->name[len] = '\0';
+       FLEX_ALLOC_MEM(d, name, name, len);
 
        ALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);
        memmove(dir->dirs + first + 1, dir->dirs + first,
@@ -697,7 +689,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,
                        return 0;
                }
                if (buf[size-1] != '\n') {
-                       buf = xrealloc(buf, size+1);
+                       buf = xrealloc(buf, st_add(size, 1));
                        buf[size++] = '\n';
                }
        } else {
@@ -711,7 +703,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,
                        close(fd);
                        return 0;
                }
-               buf = xmalloc(size+1);
+               buf = xmallocz(size);
                if (read_in_full(fd, buf, size) != size) {
                        free(buf);
                        close(fd);
@@ -1167,10 +1159,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)
 {
        struct dir_entry *ent;
 
-       ent = xmalloc(sizeof(*ent) + len + 1);
+       FLEX_ALLOC_MEM(ent, name, pathname, len);
        ent->len = len;
-       memcpy(ent->name, pathname, len);
-       ent->name[len] = 0;
        return ent;
 }
 
@@ -2334,16 +2324,15 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
        struct ondisk_untracked_cache *ouc;
        struct write_data wd;
        unsigned char varbuf[16];
-       int len = 0, varint_len;
-       if (untracked->exclude_per_dir)
-               len = strlen(untracked->exclude_per_dir);
-       ouc = xmalloc(sizeof(*ouc) + len + 1);
+       int varint_len;
+       size_t len = strlen(untracked->exclude_per_dir);
+
+       FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
        stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
        stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
        hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
        hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
        ouc->dir_flags = htonl(untracked->dir_flags);
-       memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);
 
        varint_len = encode_varint(untracked->ident.len, varbuf);
        strbuf_add(out, varbuf, varint_len);
@@ -2448,21 +2437,21 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,
        ud.untracked_alloc = value;
        ud.untracked_nr    = value;
        if (ud.untracked_nr)
-               ud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);
+               ALLOC_ARRAY(ud.untracked, ud.untracked_nr);
        data = next;
 
        next = data;
        ud.dirs_alloc = ud.dirs_nr = decode_varint(&next);
        if (next > end)
                return -1;
-       ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);
+       ALLOC_ARRAY(ud.dirs, ud.dirs_nr);
        data = next;
 
        len = strlen((const char *)data);
        next = data + len + 1;
        if (next > rd->end)
                return -1;
-       *untracked_ = untracked = xmalloc(sizeof(*untracked) + len);
+       *untracked_ = untracked = xmalloc(st_add(sizeof(*untracked), len));
        memcpy(untracked, &ud, sizeof(ud));
        memcpy(untracked->name, data, len + 1);
        data = next;
@@ -2575,7 +2564,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
        rd.data       = next;
        rd.end        = end;
        rd.index      = 0;
-       rd.ucd        = xmalloc(sizeof(*rd.ucd) * len);
+       ALLOC_ARRAY(rd.ucd, len);
 
        if (read_one_dir(&uc->root, &rd) || rd.index != len)
                goto done;
diff --git a/entry.c b/entry.c
index 582c400..a410957 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -6,7 +6,7 @@
 static void create_directories(const char *path, int path_len,
                               const struct checkout *state)
 {
-       char *buf = xmalloc(path_len + 1);
+       char *buf = xmallocz(path_len);
        int len = 0;
 
        while (len < path_len) {
index 47ad674..7103cee 100644 (file)
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-#include "git-compat-util.h"
+#include "cache.h"
 #include "ewok.h"
 
 #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))
@@ -25,8 +25,8 @@
 
 struct bitmap *bitmap_new(void)
 {
-       struct bitmap *bitmap = ewah_malloc(sizeof(struct bitmap));
-       bitmap->words = ewah_calloc(32, sizeof(eword_t));
+       struct bitmap *bitmap = xmalloc(sizeof(struct bitmap));
+       bitmap->words = xcalloc(32, sizeof(eword_t));
        bitmap->word_alloc = 32;
        return bitmap;
 }
@@ -38,9 +38,7 @@ void bitmap_set(struct bitmap *self, size_t pos)
        if (block >= self->word_alloc) {
                size_t old_size = self->word_alloc;
                self->word_alloc = block * 2;
-               self->words = ewah_realloc(self->words,
-                       self->word_alloc * sizeof(eword_t));
-
+               REALLOC_ARRAY(self->words, self->word_alloc);
                memset(self->words + old_size, 0x0,
                        (self->word_alloc - old_size) * sizeof(eword_t));
        }
@@ -100,12 +98,7 @@ struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah)
        ewah_iterator_init(&it, ewah);
 
        while (ewah_iterator_next(&blowup, &it)) {
-               if (i >= bitmap->word_alloc) {
-                       bitmap->word_alloc *= 1.5;
-                       bitmap->words = ewah_realloc(
-                               bitmap->words, bitmap->word_alloc * sizeof(eword_t));
-               }
-
+               ALLOC_GROW(bitmap->words, i + 1, bitmap->word_alloc);
                bitmap->words[i++] = blowup;
        }
 
@@ -134,8 +127,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
 
        if (self->word_alloc < other_final) {
                self->word_alloc = other_final;
-               self->words = ewah_realloc(self->words,
-                       self->word_alloc * sizeof(eword_t));
+               REALLOC_ARRAY(self->words, self->word_alloc);
                memset(self->words + original_size, 0x0,
                        (self->word_alloc - original_size) * sizeof(eword_t));
        }
index b522437..2dc9c82 100644 (file)
@@ -39,8 +39,7 @@ static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)
                return;
 
        self->alloc_size = new_size;
-       self->buffer = ewah_realloc(self->buffer,
-               self->alloc_size * sizeof(eword_t));
+       REALLOC_ARRAY(self->buffer, self->alloc_size);
        self->rlw = self->buffer + (rlw_offset / sizeof(eword_t));
 }
 
@@ -282,12 +281,9 @@ struct ewah_bitmap *ewah_new(void)
 {
        struct ewah_bitmap *self;
 
-       self = ewah_malloc(sizeof(struct ewah_bitmap));
-       if (self == NULL)
-               return NULL;
-
-       self->buffer = ewah_malloc(32 * sizeof(eword_t));
+       self = xmalloc(sizeof(struct ewah_bitmap));
        self->alloc_size = 32;
+       ALLOC_ARRAY(self->buffer, self->alloc_size);
 
        ewah_clear(self);
        return self;
index 43481b9..61f6a43 100644 (file)
@@ -134,11 +134,7 @@ int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)
        self->buffer_size = self->alloc_size = get_be32(ptr);
        ptr += sizeof(uint32_t);
 
-       self->buffer = ewah_realloc(self->buffer,
-               self->alloc_size * sizeof(eword_t));
-
-       if (!self->buffer)
-               return -1;
+       REALLOC_ARRAY(self->buffer, self->alloc_size);
 
        /*
         * Copy the raw data for the bitmap as a whole chunk;
@@ -180,11 +176,7 @@ int ewah_deserialize(struct ewah_bitmap *self, int fd)
                return -1;
 
        self->buffer_size = self->alloc_size = (size_t)ntohl(word_count);
-       self->buffer = ewah_realloc(self->buffer,
-               self->alloc_size * sizeof(eword_t));
-
-       if (!self->buffer)
-               return -1;
+       REALLOC_ARRAY(self->buffer, self->alloc_size);
 
        /** 64 bit x N -- compressed words */
        buffer = self->buffer;
index 6e2c5e1..269a1a8 100644 (file)
 #ifndef __EWOK_BITMAP_H__
 #define __EWOK_BITMAP_H__
 
-#ifndef ewah_malloc
-#      define ewah_malloc xmalloc
-#endif
-#ifndef ewah_realloc
-#      define ewah_realloc xrealloc
-#endif
-#ifndef ewah_calloc
-#      define ewah_calloc xcalloc
-#endif
-
 struct strbuf;
 typedef uint64_t eword_t;
 #define BITS_IN_EWORD (sizeof(eword_t) * 8)
index e85f0fd..9d5703a 100644 (file)
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "exec_cmd.h"
 #include "quote.h"
+#include "argv-array.h"
 #define MAX_ARGS       32
 
 static const char *argv_exec_path;
@@ -43,12 +44,10 @@ const char *git_extract_argv0_path(const char *argv0)
 
        if (!argv0 || !*argv0)
                return NULL;
-       slash = argv0 + strlen(argv0);
 
-       while (argv0 <= slash && !is_dir_sep(*slash))
-               slash--;
+       slash = find_last_dir_sep(argv0);
 
-       if (slash >= argv0) {
+       if (slash) {
                argv0_path = xstrndup(argv0, slash - argv0);
                return slash + 1;
        }
@@ -107,32 +106,25 @@ void setup_path(void)
        strbuf_release(&new_path);
 }
 
-const char **prepare_git_cmd(const char **argv)
+const char **prepare_git_cmd(struct argv_array *out, const char **argv)
 {
-       int argc;
-       const char **nargv;
-
-       for (argc = 0; argv[argc]; argc++)
-               ; /* just counting */
-       nargv = xmalloc(sizeof(*nargv) * (argc + 2));
-
-       nargv[0] = "git";
-       for (argc = 0; argv[argc]; argc++)
-               nargv[argc + 1] = argv[argc];
-       nargv[argc + 1] = NULL;
-       return nargv;
+       argv_array_push(out, "git");
+       argv_array_pushv(out, argv);
+       return out->argv;
 }
 
 int execv_git_cmd(const char **argv) {
-       const char **nargv = prepare_git_cmd(argv);
-       trace_argv_printf(nargv, "trace: exec:");
+       struct argv_array nargv = ARGV_ARRAY_INIT;
+
+       prepare_git_cmd(&nargv, argv);
+       trace_argv_printf(nargv.argv, "trace: exec:");
 
        /* execvp() can only ever return if it fails */
-       sane_execvp("git", (char **)nargv);
+       sane_execvp("git", (char **)nargv.argv);
 
        trace_printf("trace: exec failed: %s\n", strerror(errno));
 
-       free(nargv);
+       argv_array_clear(&nargv);
        return -1;
 }
 
index 93b0c02..1f6b433 100644 (file)
@@ -1,11 +1,13 @@
 #ifndef GIT_EXEC_CMD_H
 #define GIT_EXEC_CMD_H
 
+struct argv_array;
+
 extern void git_set_argv_exec_path(const char *exec_path);
 extern const char *git_extract_argv0_path(const char *path);
 extern const char *git_exec_path(void);
 extern void setup_path(void);
-extern const char **prepare_git_cmd(const char **argv);
+extern const char **prepare_git_cmd(struct argv_array *out, const char **argv);
 extern int execv_git_cmd(const char **argv); /* NULL terminated */
 LAST_ARG_MUST_BE_NULL
 extern int execl_git_cmd(const char *cmd, ...);
index 3c65edb..75f7748 100644 (file)
@@ -622,7 +622,7 @@ static void *pool_alloc(size_t len)
                        return xmalloc(len);
                }
                total_allocd += sizeof(struct mem_pool) + mem_pool_alloc;
-               p = xmalloc(sizeof(struct mem_pool) + mem_pool_alloc);
+               p = xmalloc(st_add(sizeof(struct mem_pool), mem_pool_alloc));
                p->next_pool = mem_pool;
                p->next_free = (char *) p->space;
                p->end = p->next_free + mem_pool_alloc;
@@ -814,7 +814,8 @@ static struct tree_entry *new_tree_entry(void)
        if (!avail_tree_entry) {
                unsigned int n = tree_entry_alloc;
                total_allocd += n * sizeof(struct tree_entry);
-               avail_tree_entry = e = xmalloc(n * sizeof(struct tree_entry));
+               ALLOC_ARRAY(e, n);
+               avail_tree_entry = e;
                while (n-- > 1) {
                        *((void**)e) = e + 1;
                        e++;
@@ -864,15 +865,12 @@ static void start_packfile(void)
 {
        static char tmp_file[PATH_MAX];
        struct packed_git *p;
-       int namelen;
        struct pack_header hdr;
        int pack_fd;
 
        pack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),
                              "pack/tmp_pack_XXXXXX");
-       namelen = strlen(tmp_file) + 2;
-       p = xcalloc(1, sizeof(*p) + namelen);
-       xsnprintf(p->pack_name, namelen, "%s", tmp_file);
+       FLEX_ALLOC_STR(p, pack_name, tmp_file);
        p->pack_fd = pack_fd;
        p->do_not_close = 1;
        pack_file = sha1fd(pack_fd, p->pack_name);
@@ -898,7 +896,7 @@ static const char *create_index(void)
        struct object_entry_pool *o;
 
        /* Build the table of object IDs. */
-       idx = xmalloc(object_count * sizeof(*idx));
+       ALLOC_ARRAY(idx, object_count);
        c = idx;
        for (o = blocks; o; o = o->next_pool)
                for (e = o->next_free; e-- != o->entries;)
index 01e34b6..f96f6df 100644 (file)
@@ -15,6 +15,7 @@
 #include "version.h"
 #include "prio-queue.h"
 #include "sha1-array.h"
+#include "sigchain.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -671,9 +672,12 @@ static int everything_local(struct fetch_pack_args *args,
 static int sideband_demux(int in, int out, void *data)
 {
        int *xd = data;
+       int ret;
 
-       int ret = recv_sideband("fetch-pack", xd[0], out);
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = recv_sideband("fetch-pack", xd[0], out);
        close(out);
+       sigchain_pop(SIGPIPE);
        return ret;
 }
 
diff --git a/fsck.c b/fsck.c
index c637f66..ca4c685 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -199,7 +199,8 @@ void fsck_set_msg_type(struct fsck_options *options,
 
        if (!options->msg_type) {
                int i;
-               int *msg_type = xmalloc(sizeof(int) * FSCK_MSG_MAX);
+               int *msg_type;
+               ALLOC_ARRAY(msg_type, FSCK_MSG_MAX);
                for (i = 0; i < FSCK_MSG_MAX; i++)
                        msg_type[i] = fsck_msg_type(i, options);
                options->msg_type = msg_type;
index 693a336..c07e0c1 100644 (file)
 #define unsigned_add_overflows(a, b) \
     ((b) > maximum_unsigned_value_of_type(a) - (a))
 
+/*
+ * Returns true if the multiplication of "a" and "b" will
+ * overflow. The types of "a" and "b" must match and must be unsigned.
+ * Note that this macro evaluates "a" twice!
+ */
+#define unsigned_mult_overflows(a, b) \
+    ((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
+
 #ifdef __GNUC__
 #define TYPEOF(x) (__typeof__(x))
 #else
@@ -325,10 +333,6 @@ extern char *gitdirname(char *);
 #define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin"
 #endif
 
-#ifndef STRIP_EXTENSION
-#define STRIP_EXTENSION ""
-#endif
-
 #ifndef has_dos_drive_prefix
 static inline int git_has_dos_drive_prefix(const char *path)
 {
@@ -673,7 +677,6 @@ extern int git_vsnprintf(char *str, size_t maxsize,
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
 #define HAVE_STRCHRNUL
-#define HAVE_MEMPCPY
 #endif
 #endif
 
@@ -687,14 +690,6 @@ static inline char *gitstrchrnul(const char *s, int c)
 }
 #endif
 
-#ifndef HAVE_MEMPCPY
-#define mempcpy gitmempcpy
-static inline void *gitmempcpy(void *dest, const void *src, size_t n)
-{
-       return (char *)memcpy(dest, src, n) + n;
-}
-#endif
-
 #ifdef NO_INET_PTON
 int inet_pton(int af, const char *src, void *dst);
 #endif
@@ -713,6 +708,32 @@ extern void release_pack_memory(size_t);
 typedef void (*try_to_free_t)(size_t);
 extern try_to_free_t set_try_to_free_routine(try_to_free_t);
 
+static inline size_t st_add(size_t a, size_t b)
+{
+       if (unsigned_add_overflows(a, b))
+               die("size_t overflow: %"PRIuMAX" + %"PRIuMAX,
+                   (uintmax_t)a, (uintmax_t)b);
+       return a + b;
+}
+#define st_add3(a,b,c)   st_add((a),st_add((b),(c)))
+#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))
+
+static inline size_t st_mult(size_t a, size_t b)
+{
+       if (unsigned_mult_overflows(a, b))
+               die("size_t overflow: %"PRIuMAX" * %"PRIuMAX,
+                   (uintmax_t)a, (uintmax_t)b);
+       return a * b;
+}
+
+static inline size_t st_sub(size_t a, size_t b)
+{
+       if (a < b)
+               die("size_t underflow: %"PRIuMAX" - %"PRIuMAX,
+                   (uintmax_t)a, (uintmax_t)b);
+       return a - b;
+}
+
 #ifdef HAVE_ALLOCA_H
 # include <alloca.h>
 # define xalloca(size)      (alloca(size))
@@ -745,7 +766,70 @@ extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);
 extern char *xgetcwd(void);
 extern FILE *fopen_for_writing(const char *path);
 
-#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))
+#define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))
+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
+
+/*
+ * These functions help you allocate structs with flex arrays, and copy
+ * the data directly into the array. For example, if you had:
+ *
+ *   struct foo {
+ *     int bar;
+ *     char name[FLEX_ARRAY];
+ *   };
+ *
+ * you can do:
+ *
+ *   struct foo *f;
+ *   FLEX_ALLOC_MEM(f, name, src, len);
+ *
+ * to allocate a "foo" with the contents of "src" in the "name" field.
+ * The resulting struct is automatically zero'd, and the flex-array field
+ * is NUL-terminated (whether the incoming src buffer was or not).
+ *
+ * The FLEXPTR_* variants operate on structs that don't use flex-arrays,
+ * but do want to store a pointer to some extra data in the same allocated
+ * block. For example, if you have:
+ *
+ *   struct foo {
+ *     char *name;
+ *     int bar;
+ *   };
+ *
+ * you can do:
+ *
+ *   struct foo *f;
+ *   FLEX_ALLOC_STR(f, name, src);
+ *
+ * and "name" will point to a block of memory after the struct, which will be
+ * freed along with the struct (but the pointer can be repointed anywhere).
+ *
+ * The *_STR variants accept a string parameter rather than a ptr/len
+ * combination.
+ *
+ * Note that these macros will evaluate the first parameter multiple
+ * times, and it must be assignable as an lvalue.
+ */
+#define FLEX_ALLOC_MEM(x, flexname, buf, len) do { \
+       (x) = NULL; /* silence -Wuninitialized for offset calculation */ \
+       (x) = xalloc_flex(sizeof(*(x)), (char *)(&((x)->flexname)) - (char *)(x), (buf), (len)); \
+} while (0)
+#define FLEXPTR_ALLOC_MEM(x, ptrname, buf, len) do { \
+       (x) = xalloc_flex(sizeof(*(x)), sizeof(*(x)), (buf), (len)); \
+       (x)->ptrname = (void *)((x)+1); \
+} while(0)
+#define FLEX_ALLOC_STR(x, flexname, str) \
+       FLEX_ALLOC_MEM((x), flexname, (str), strlen(str))
+#define FLEXPTR_ALLOC_STR(x, ptrname, str) \
+       FLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))
+
+static inline void *xalloc_flex(size_t base_len, size_t offset,
+                               const void *src, size_t src_len)
+{
+       unsigned char *ret = xcalloc(1, st_add3(base_len, src_len, 1));
+       memcpy(ret + offset, src, src_len);
+       return ret;
+}
 
 static inline char *xstrdup_or_null(const char *str)
 {
index cdc02af..424b034 100755 (executable)
@@ -120,8 +120,7 @@ case "${1:-.}${2:-.}${3:-.}" in
        case "$1" in
        '')
                echo "Added $4 in both, but differently."
-               orig=$(git-unpack-file $2)
-               create_virtual_base "$orig" "$src2"
+               orig=$(git-unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
                ;;
        *)
                echo "Auto-merging $4"
diff --git a/git.c b/git.c
index 6ed824c..c19d6bf 100644 (file)
--- a/git.c
+++ b/git.c
@@ -239,19 +239,15 @@ static int handle_alias(int *argcp, const char ***argv)
        alias_string = alias_lookup(alias_command);
        if (alias_string) {
                if (alias_string[0] == '!') {
-                       const char **alias_argv;
-                       int argc = *argcp, i;
+                       struct child_process child = CHILD_PROCESS_INIT;
 
                        commit_pager_choice();
 
-                       /* build alias_argv */
-                       alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
-                       alias_argv[0] = alias_string + 1;
-                       for (i = 1; i < argc; ++i)
-                               alias_argv[i] = (*argv)[i];
-                       alias_argv[argc] = NULL;
+                       child.use_shell = 1;
+                       argv_array_push(&child.args, alias_string + 1);
+                       argv_array_pushv(&child.args, (*argv) + 1);
 
-                       ret = run_command_v_opt(alias_argv, RUN_USING_SHELL);
+                       ret = run_command(&child);
                        if (ret >= 0)   /* normal exit */
                                exit(ret);
 
@@ -506,21 +502,25 @@ int is_builtin(const char *s)
        return !!get_builtin(s);
 }
 
+#ifdef STRIP_EXTENSION
+static void strip_extension(const char **argv)
+{
+       size_t len;
+
+       if (strip_suffix(argv[0], STRIP_EXTENSION, &len))
+               argv[0] = xmemdupz(argv[0], len);
+}
+#else
+#define strip_extension(cmd)
+#endif
+
 static void handle_builtin(int argc, const char **argv)
 {
-       const char *cmd = argv[0];
-       int i;
-       static const char ext[] = STRIP_EXTENSION;
+       const char *cmd;
        struct cmd_struct *builtin;
 
-       if (sizeof(ext) > 1) {
-               i = strlen(argv[0]) - strlen(ext);
-               if (i > 0 && !strcmp(argv[0] + i, ext)) {
-                       char *argv0 = xstrdup(argv[0]);
-                       argv[0] = cmd = argv0;
-                       argv0[i] = '\0';
-               }
-       }
+       strip_extension(argv);
+       cmd = argv[0];
 
        /* Turn "git cmd --help" into "git help cmd" */
        if (argc > 1 && !strcmp(argv[1], "--help")) {
diff --git a/graph.c b/graph.c
index c25a09a..1350bdd 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -234,12 +234,10 @@ struct git_graph *graph_init(struct rev_info *opt)
         * We'll automatically grow columns later if we need more room.
         */
        graph->column_capacity = 30;
-       graph->columns = xmalloc(sizeof(struct column) *
-                                graph->column_capacity);
-       graph->new_columns = xmalloc(sizeof(struct column) *
-                                    graph->column_capacity);
-       graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
-       graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
+       ALLOC_ARRAY(graph->columns, graph->column_capacity);
+       ALLOC_ARRAY(graph->new_columns, graph->column_capacity);
+       ALLOC_ARRAY(graph->mapping, 2 * graph->column_capacity);
+       ALLOC_ARRAY(graph->new_mapping, 2 * graph->column_capacity);
 
        /*
         * The diff output prefix callback, with this we can make
diff --git a/grep.c b/grep.c
index 7b2b96a..528b652 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1741,7 +1741,7 @@ static int grep_source_load_file(struct grep_source *gs)
        i = open(filename, O_RDONLY);
        if (i < 0)
                goto err_ret;
-       data = xmalloc(size + 1);
+       data = xmallocz(size);
        if (st.st_size != read_in_full(i, data, size)) {
                error(_("'%s': short read %s"), filename, strerror(errno));
                close(i);
@@ -1749,7 +1749,6 @@ static int grep_source_load_file(struct grep_source *gs)
                return -1;
        }
        close(i);
-       data[size] = 0;
 
        gs->buf = data;
        gs->size = size;
index f693839..b10b642 100644 (file)
--- a/hashmap.c
+++ b/hashmap.c
@@ -256,10 +256,9 @@ const void *memintern(const void *data, size_t len)
        e = hashmap_get(&map, &key, data);
        if (!e) {
                /* not found: create it */
-               e = xmallocz(sizeof(struct pool_entry) + len);
+               FLEX_ALLOC_MEM(e, data, data, len);
                hashmap_entry_init(e, key.ent.hash);
                e->len = len;
-               memcpy(e->data, data, len);
                hashmap_add(&map, e);
        }
        return e->data;
diff --git a/help.c b/help.c
index d996b34..19328ea 100644 (file)
--- a/help.c
+++ b/help.c
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 {
-       struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);
-
+       struct cmdname *ent;
+       FLEX_ALLOC_MEM(ent, name, name, len);
        ent->len = len;
-       memcpy(ent->name, name, len);
-       ent->name[len] = 0;
 
        ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
        cmds->names[cmds->cnt++] = ent;
index 4d3b773..2c52027 100644 (file)
@@ -892,12 +892,11 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)
        response = xstrfmt("%s %s", user, hex);
        resp_len = strlen(response) + 1;
 
-       response_64 = xmalloc(ENCODED_SIZE(resp_len) + 1);
+       response_64 = xmallocz(ENCODED_SIZE(resp_len));
        encoded_len = EVP_EncodeBlock((unsigned char *)response_64,
                                      (unsigned char *)response, resp_len);
        if (encoded_len < 0)
                die("EVP_EncodeBlock error");
-       response_64[encoded_len] = '\0';
        return (char *)response_64;
 }
 
@@ -1188,7 +1187,7 @@ static void lf_to_crlf(struct strbuf *msg)
                j++;
        }
 
-       new = xmalloc(j + 1);
+       new = xmallocz(j);
 
        /*
         * Second pass: write the new string.  Note that this loop is
diff --git a/khash.h b/khash.h
index 376475a..c0da40d 100644 (file)
--- a/khash.h
+++ b/khash.h
@@ -117,7 +117,7 @@ static const double __ac_HASH_UPPER = 0.77;
                        if (new_n_buckets < 4) new_n_buckets = 4;                                       \
                        if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
                        else { /* hash table size to be changed (shrink or expand); rehash */ \
-                               new_flags = (khint32_t*)xmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
+                               ALLOC_ARRAY(new_flags, __ac_fsize(new_n_buckets)); \
                                if (!new_flags) return -1;                                                              \
                                memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
                                if (h->n_buckets < new_n_buckets) {     /* expand */            \
index fc28159..d263269 100644 (file)
@@ -42,11 +42,13 @@ int levenshtein(const char *string1, const char *string2,
                int w, int s, int a, int d)
 {
        int len1 = strlen(string1), len2 = strlen(string2);
-       int *row0 = xmalloc(sizeof(int) * (len2 + 1));
-       int *row1 = xmalloc(sizeof(int) * (len2 + 1));
-       int *row2 = xmalloc(sizeof(int) * (len2 + 1));
+       int *row0, *row1, *row2;
        int i, j;
 
+       ALLOC_ARRAY(row0, len2 + 1);
+       ALLOC_ARRAY(row1, len2 + 1);
+       ALLOC_ARRAY(row2, len2 + 1);
+
        for (j = 0; j <= len2; j++)
                row1[j] = j * a;
        for (i = 0; i < len1; i++) {
index af6e2f7..bbe31ed 100644 (file)
@@ -14,6 +14,7 @@
 #include "graph.h"
 #include "userdiff.h"
 #include "line-log.h"
+#include "argv-array.h"
 
 static void range_set_grow(struct range_set *rs, size_t extra)
 {
@@ -521,7 +522,7 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines,
        if (diff_populate_filespec(spec, 0))
                die("Cannot read blob %s", sha1_to_hex(spec->sha1));
 
-       ends = xmalloc(size * sizeof(*ends));
+       ALLOC_ARRAY(ends, size);
        ends[cur++] = 0;
        data = spec->data;
        while (num < spec->size) {
@@ -746,22 +747,17 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list
        add_line_range(rev, commit, range);
 
        if (!rev->diffopt.detect_rename) {
-               int i, count = 0;
-               struct line_log_data *r = range;
+               struct line_log_data *r;
+               struct argv_array array = ARGV_ARRAY_INIT;
                const char **paths;
-               while (r) {
-                       count++;
-                       r = r->next;
-               }
-               paths = xmalloc((count+1)*sizeof(char *));
-               r = range;
-               for (i = 0; i < count; i++) {
-                       paths[i] = xstrdup(r->path);
-                       r = r->next;
-               }
-               paths[count] = NULL;
+
+               for (r = range; r; r = r->next)
+                       argv_array_push(&array, r->path);
+               paths = argv_array_detach(&array);
+
                parse_pathspec(&rev->diffopt.pathspec, 0,
                               PATHSPEC_PREFER_FULL, "", paths);
+               /* strings are now owned by pathspec */
                free(paths);
        }
 }
@@ -1146,9 +1142,9 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
        if (nparents > 1 && rev->first_parent_only)
                nparents = 1;
 
-       diffqueues = xmalloc(nparents * sizeof(*diffqueues));
-       cand = xmalloc(nparents * sizeof(*cand));
-       parents = xmalloc(nparents * sizeof(*parents));
+       ALLOC_ARRAY(diffqueues, nparents);
+       ALLOC_ARRAY(cand, nparents);
+       ALLOC_ARRAY(parents, nparents);
 
        p = commit->parents;
        for (i = 0; i < nparents; i++) {
index 0338630..ff4a43a 100644 (file)
@@ -205,7 +205,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
        if (fstat(fd, &st))
                goto close_bad;
        result->size = st.st_size;
-       result->ptr = xmalloc(result->size + 1);
+       result->ptr = xmallocz(result->size);
        if (read_in_full(fd, result->ptr, result->size) != result->size) {
                free(result->ptr);
                result->ptr = NULL;
index f70a30e..60f9839 100644 (file)
@@ -77,9 +77,8 @@ int parse_decorate_color_config(const char *var, const char *slot_name, const ch
 
 void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
 {
-       int nlen = strlen(name);
-       struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);
-       memcpy(res->name, name, nlen + 1);
+       struct name_decoration *res;
+       FLEX_ALLOC_STR(res, name, name);
        res->type = type;
        res->next = add_decoration(&name_decoration, obj, res);
 }
index ddca601..9b6eac2 100644 (file)
@@ -48,40 +48,6 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
        return res.ptr;
 }
 
-static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
-{
-       int i;
-       mmfile_t *dst = priv_;
-
-       for (i = 0; i < nbuf; i++) {
-               memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
-               dst->size += mb[i].size;
-       }
-       return 0;
-}
-
-static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
-{
-       unsigned long size = f1->size < f2->size ? f1->size : f2->size;
-       void *ptr = xmalloc(size);
-       xpparam_t xpp;
-       xdemitconf_t xecfg;
-       xdemitcb_t ecb;
-
-       memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = 0;
-       memset(&xecfg, 0, sizeof(xecfg));
-       xecfg.ctxlen = 3;
-       xecfg.flags = XDL_EMIT_COMMON;
-       ecb.outf = common_outf;
-
-       res->ptr = ptr;
-       res->size = 0;
-
-       ecb.priv = res;
-       return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
-}
-
 void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
 {
        void *res = NULL;
@@ -112,8 +78,8 @@ void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct
                if (fill_mmfile_blob(&common, base) < 0)
                        goto out_free_f2_f1;
        } else {
-               if (generate_common_file(&common, &f1, &f2) < 0)
-                       goto out_free_f2_f1;
+               common.ptr = xstrdup("");
+               common.size = 0;
        }
        res = three_way_filemerge(path, &common, &f1, &f2, size);
        free_mmfile(&common);
index 332ba95..6d9f23e 100644 (file)
@@ -55,10 +55,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate,
        dir = find_dir_entry(istate, ce->name, namelen);
        if (!dir) {
                /* not found, create it and add to hash table */
-               dir = xcalloc(1, sizeof(struct dir_entry) + namelen + 1);
+               FLEX_ALLOC_MEM(dir, name, ce->name, namelen);
                hashmap_entry_init(dir, memihash(ce->name, namelen));
                dir->namelen = namelen;
-               strncpy(dir->name, ce->name, namelen);
                hashmap_add(&istate->dir_hash, dir);
 
                /* recursively add missing parent directories */
diff --git a/notes.c b/notes.c
index db77922..8b59ccd 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1032,7 +1032,7 @@ struct notes_tree **load_notes_trees(struct string_list *refs)
        struct string_list_item *item;
        int counter = 0;
        struct notes_tree **trees;
-       trees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));
+       ALLOC_ARRAY(trees, refs->nr + 1);
        for_each_string_list_item(item, refs) {
                struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));
                init_notes(t, item->string, combine_notes_ignore, 0);
index 433bd86..1da89a4 100644 (file)
@@ -89,7 +89,7 @@ static int verify_packfile(struct packed_git *p,
         * we do not do scan-streaming check on the pack file.
         */
        nr_objects = p->num_objects;
-       entries = xmalloc((nr_objects + 1) * sizeof(*entries));
+       ALLOC_ARRAY(entries, nr_objects + 1);
        entries[nr_objects].offset = pack_sig_ofs;
        /* first sort entries by pack offset, since unpacking them is more efficient that way */
        for (i = 0; i < nr_objects; i++) {
index e542ea7..f6a3613 100644 (file)
@@ -83,10 +83,14 @@ static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max)
         * keep track of them with alias pointers, always sorting from "from"
         * to "to".
         */
-       struct revindex_entry *tmp = xmalloc(n * sizeof(*tmp));
-       struct revindex_entry *from = entries, *to = tmp;
+       struct revindex_entry *tmp, *from, *to;
        int bits;
-       unsigned *pos = xmalloc(BUCKETS * sizeof(*pos));
+       unsigned *pos;
+
+       ALLOC_ARRAY(pos, BUCKETS);
+       ALLOC_ARRAY(tmp, n);
+       from = entries;
+       to = tmp;
 
        /*
         * If (max >> bits) is zero, then we know that the radix digit we are
@@ -161,7 +165,7 @@ static void create_pack_revindex(struct pack_revindex *rix)
        unsigned i;
        const char *index = p->index_data;
 
-       rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
+       ALLOC_ARRAY(rix->revindex, num_ent + 1);
        index += 4 * 256;
 
        if (p->index_version > 1) {
diff --git a/pager.c b/pager.c
index e425070..4bc0481 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -11,7 +11,6 @@
  * something different on Windows.
  */
 
-static const char *pager_argv[] = { NULL, NULL };
 static struct child_process pager_process = CHILD_PROCESS_INIT;
 
 static void wait_for_pager(int in_signal)
@@ -64,6 +63,16 @@ const char *git_pager(int stdout_is_tty)
        return pager;
 }
 
+void prepare_pager_args(struct child_process *pager_process, const char *pager)
+{
+       argv_array_push(&pager_process->args, pager);
+       pager_process->use_shell = 1;
+       if (!getenv("LESS"))
+               argv_array_push(&pager_process->env_array, "LESS=FRX");
+       if (!getenv("LV"))
+               argv_array_push(&pager_process->env_array, "LV=-c");
+}
+
 void setup_pager(void)
 {
        const char *pager = git_pager(isatty(1));
@@ -80,14 +89,8 @@ void setup_pager(void)
        setenv("GIT_PAGER_IN_USE", "true", 1);
 
        /* spawn the pager */
-       pager_argv[0] = pager;
-       pager_process.use_shell = 1;
-       pager_process.argv = pager_argv;
+       prepare_pager_args(&pager_process, pager);
        pager_process.in = -1;
-       if (!getenv("LESS"))
-               argv_array_push(&pager_process.env_array, "LESS=FRX");
-       if (!getenv("LV"))
-               argv_array_push(&pager_process.env_array, "LV=-c");
        argv_array_push(&pager_process.env_array, "GIT_PAGER_IN_USE");
        if (start_command(&pager_process))
                return;
index 9304ee3..c9e9b6c 100644 (file)
@@ -406,7 +406,8 @@ void parse_pathspec(struct pathspec *pathspec,
                n++;
 
        pathspec->nr = n;
-       pathspec->items = item = xmalloc(sizeof(*item) * n);
+       ALLOC_ARRAY(pathspec->items, n);
+       item = pathspec->items;
        pathspec->_raw = argv;
        prefixlen = prefix ? strlen(prefix) : 0;
 
@@ -483,7 +484,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
 void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
 {
        *dst = *src;
-       dst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);
+       ALLOC_ARRAY(dst->items, dst->nr);
        memcpy(dst->items, src->items,
               sizeof(struct pathspec_item) * dst->nr);
 }
index 353bd37..76a88c5 100644 (file)
@@ -247,7 +247,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
                size_t len = strlen(msg) + 5;
                struct throughput *tp = progress->throughput;
 
-               bufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);
+               bufp = (len < sizeof(buf)) ? buf : xmallocz(len);
                if (tp) {
                        unsigned int rate = !tp->avg_misecs ? 0 :
                                        tp->avg_bytes / tp->avg_misecs;
index f097176..9ccfc51 100644 (file)
@@ -1255,10 +1255,8 @@ static struct ref_array_item *new_ref_array_item(const char *refname,
                                                 const unsigned char *objectname,
                                                 int flag)
 {
-       size_t len = strlen(refname);
-       struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
-       memcpy(ref->refname, refname, len);
-       ref->refname[len] = '\0';
+       struct ref_array_item *ref;
+       FLEX_ALLOC_STR(ref, refname, refname);
        hashcpy(ref->objectname, objectname);
        ref->flag = flag;
 
diff --git a/refs.c b/refs.c
index e2d34b2..b0e6ece 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -124,7 +124,7 @@ int refname_is_safe(const char *refname)
                char *buf;
                int result;
 
-               buf = xmalloc(strlen(refname) + 1);
+               buf = xmallocz(strlen(refname));
                /*
                 * Does the refname try to escape refs/?
                 * For example: refs/foo/../bar is safe but refs/foo/../../bar
@@ -761,10 +761,8 @@ void ref_transaction_free(struct ref_transaction *transaction)
 static struct ref_update *add_update(struct ref_transaction *transaction,
                                     const char *refname)
 {
-       size_t len = strlen(refname) + 1;
-       struct ref_update *update = xcalloc(1, sizeof(*update) + len);
-
-       memcpy((char *)update->refname, refname, len); /* includes NUL */
+       struct ref_update *update;
+       FLEX_ALLOC_STR(update, refname, refname);
        ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
        transaction->updates[transaction->nr++] = update;
        return update;
@@ -908,7 +906,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
                        /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
                        total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;
 
-               scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
+               scanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len));
 
                offset = 0;
                for (i = 0; i < nr_rules; i++) {
diff --git a/refs.h b/refs.h
index 7a04077..19ebebc 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -109,6 +109,11 @@ extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
  *   If this succeeds, the ref updates will have taken place and
  *   the transaction cannot be rolled back.
  *
+ * - Instead of `ref_transaction_commit`, use
+ *   `initial_ref_transaction_commit()` if the ref database is known
+ *   to be empty (e.g. during clone).  This is likely to be much
+ *   faster.
+ *
  * - At any time call `ref_transaction_free()` to discard the
  *   transaction and free associated resources.  In particular,
  *   this rolls back the transaction if it has not been
@@ -124,6 +129,13 @@ extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
  *
  * The message is appended to err without first clearing err.
  * err will not be '\n' terminated.
+ *
+ * Caveats
+ * -------
+ *
+ * Note that no locks are taken, and no refs are read, until
+ * `ref_transaction_commit` is called.  So `ref_transaction_verify`
+ * won't report a verification failure until the commit is attempted.
  */
 struct ref_transaction;
 
index 3a27f27..de9af16 100644 (file)
@@ -199,17 +199,14 @@ static struct ref_entry *create_ref_entry(const char *refname,
                                          const unsigned char *sha1, int flag,
                                          int check_name)
 {
-       int len;
        struct ref_entry *ref;
 
        if (check_name &&
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
                die("Reference has invalid format: '%s'", refname);
-       len = strlen(refname) + 1;
-       ref = xmalloc(sizeof(struct ref_entry) + len);
+       FLEX_ALLOC_STR(ref, name, refname);
        hashcpy(ref->u.value.oid.hash, sha1);
        oidclr(&ref->u.value.peeled);
-       memcpy(ref->name, refname, len);
        ref->flag = flag;
        return ref;
 }
@@ -268,9 +265,7 @@ static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
                                          int incomplete)
 {
        struct ref_entry *direntry;
-       direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1);
-       memcpy(direntry->name, dirname, len);
-       direntry->name[len] = '\0';
+       FLEX_ALLOC_MEM(direntry, name, dirname, len);
        direntry->u.subdir.ref_cache = ref_cache;
        direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);
        return direntry;
@@ -939,13 +934,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)
  */
 static struct ref_cache *create_ref_cache(const char *submodule)
 {
-       int len;
        struct ref_cache *refs;
        if (!submodule)
                submodule = "";
-       len = strlen(submodule) + 1;
-       refs = xcalloc(1, sizeof(struct ref_cache) + len);
-       memcpy(refs->name, submodule, len);
+       FLEX_ALLOC_STR(refs, name, submodule);
        refs->next = submodule_ref_caches;
        submodule_ref_caches = refs;
        return refs;
@@ -2191,10 +2183,9 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)
 
        /* Schedule the loose reference for pruning if requested. */
        if ((cb->flags & PACK_REFS_PRUNE)) {
-               int namelen = strlen(entry->name) + 1;
-               struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
+               struct ref_to_prune *n;
+               FLEX_ALLOC_STR(n, name, entry->name);
                hashcpy(n->sha1, entry->u.value.oid.hash);
-               memcpy(n->name, entry->name, namelen); /* includes NUL */
                n->next = cb->ref_to_prune;
                cb->ref_to_prune = n;
        }
index f404faf..e65ea59 100644 (file)
@@ -439,8 +439,20 @@ static int run_slot(struct active_request_slot *slot,
        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;
@@ -696,9 +708,10 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
 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++)
@@ -845,23 +858,22 @@ static void parse_fetch(struct strbuf *buf)
 
 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;
 }
 
index 3ceac07..6e5c1a8 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -928,7 +928,7 @@ static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
                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 @@ struct ref *copy_ref(const struct ref *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);
@@ -2133,16 +2133,13 @@ static int one_local_ref(const char *refname, const struct object_id *oid,
 {
        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;
index 14daefb..df56fce 100644 (file)
@@ -540,7 +540,7 @@ struct treesame_state {
 static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)
 {
        unsigned n = commit_list_count(commit->parents);
-       struct treesame_state *st = xcalloc(1, sizeof(*st) + n);
+       struct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n));
        st->nparents = n;
        add_decoration(&revs->treesame, &commit->object, st);
        return st;
index 13fa452..2392b1e 100644 (file)
@@ -158,50 +158,41 @@ int sane_execvp(const char *file, char * const argv[])
        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 @@ 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);
@@ -480,9 +472,9 @@ fail_pipe:
                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);
@@ -492,9 +484,7 @@ fail_pipe:
        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,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 {
@@ -678,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)
index 12bb26c..c0969c7 100644 (file)
@@ -121,5 +121,6 @@ struct async {
 int start_async(struct async *async);
 int finish_async(struct async *async);
 int in_async(void);
+void NORETURN async_exit(int code);
 
 #endif
index 8c58fa2..e60e75a 100644 (file)
@@ -124,42 +124,33 @@ static const char *action_name(const struct replay_opts *opts)
 
 struct commit_message {
        char *parent_label;
-       const char *label;
-       const char *subject;
+       char *label;
+       char *subject;
        const char *message;
 };
 
 static int get_message(struct commit *commit, struct commit_message *out)
 {
        const char *abbrev, *subject;
-       int abbrev_len, subject_len;
-       char *q;
-
-       if (!git_commit_encoding)
-               git_commit_encoding = "UTF-8";
+       int subject_len;
 
-       out->message = logmsg_reencode(commit, NULL, git_commit_encoding);
+       out->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());
        abbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
-       abbrev_len = strlen(abbrev);
 
        subject_len = find_commit_subject(out->message, &subject);
 
-       out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
-                             strlen("... ") + subject_len + 1);
-       q = out->parent_label;
-       q = mempcpy(q, "parent of ", strlen("parent of "));
-       out->label = q;
-       q = mempcpy(q, abbrev, abbrev_len);
-       q = mempcpy(q, "... ", strlen("... "));
-       out->subject = q;
-       q = mempcpy(q, subject, subject_len);
-       *q = '\0';
+       out->subject = xmemdupz(subject, subject_len);
+       out->label = xstrfmt("%s... %s", abbrev, out->subject);
+       out->parent_label = xstrfmt("parent of %s", out->label);
+
        return 0;
 }
 
 static void free_message(struct commit *commit, struct commit_message *msg)
 {
        free(msg->parent_label);
+       free(msg->label);
+       free(msg->subject);
        unuse_commit_buffer(commit, msg->message);
 }
 
diff --git a/setup.c b/setup.c
index 0deb022..de1a2a7 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -88,7 +88,7 @@ char *prefix_path_gently(const char *prefix, int len,
        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,9 +139,7 @@ int check_filename(const char *prefix, const char *arg)
                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;
@@ -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);
 }
@@ -488,14 +486,13 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
                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;
index 73ccd49..b516874 100644 (file)
@@ -253,7 +253,7 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,
 {
        struct alternate_object_database *ent;
        struct alternate_object_database *alt;
-       int pfxlen, entlen;
+       size_t pfxlen, entlen;
        struct strbuf pathbuf = STRBUF_INIT;
 
        if (!is_absolute_path(entry) && relative_base) {
@@ -273,8 +273,8 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base,
        while (pfxlen && pathbuf.buf[pfxlen-1] == '/')
                pfxlen -= 1;
 
-       entlen = pfxlen + 43; /* '/' + 2 hex + '/' + 38 hex + NUL */
-       ent = xmalloc(sizeof(*ent) + entlen);
+       entlen = st_add(pfxlen, 43); /* '/' + 2 hex + '/' + 38 hex + NUL */
+       ent = xmalloc(st_add(sizeof(*ent), entlen));
        memcpy(ent->base, pathbuf.buf, pfxlen);
        strbuf_release(&pathbuf);
 
@@ -1076,6 +1076,8 @@ unsigned char *use_pack(struct packed_git *p,
                die("packfile %s cannot be accessed", p->pack_name);
        if (offset > (p->pack_size - 20))
                die("offset beyond end of packfile (truncated pack?)");
+       if (offset < 0)
+               die(_("offset before end of packfile (broken .idx?)"));
 
        if (!win || !in_window(win, offset)) {
                if (win)
@@ -1134,7 +1136,7 @@ unsigned char *use_pack(struct packed_git *p,
 
 static struct packed_git *alloc_packed_git(int extra)
 {
-       struct packed_git *p = xmalloc(sizeof(*p) + extra);
+       struct packed_git *p = xmalloc(st_add(sizeof(*p), extra));
        memset(p, 0, sizeof(*p));
        p->pack_fd = -1;
        return p;
@@ -1168,7 +1170,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
         * ".pack" is long enough to hold any suffix we're adding (and
         * the use xsnprintf double-checks that)
         */
-       alloc = path_len + strlen(".pack") + 1;
+       alloc = st_add3(path_len, strlen(".pack"), 1);
        p = alloc_packed_git(alloc);
        memcpy(p->pack_name, path, path_len);
 
@@ -1196,7 +1198,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
 struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
 {
        const char *path = sha1_pack_name(sha1);
-       int alloc = strlen(path) + 1;
+       size_t alloc = st_add(strlen(path), 1);
        struct packed_git *p = alloc_packed_git(alloc);
 
        memcpy(p->pack_name, path, alloc); /* includes NUL */
@@ -1413,10 +1415,12 @@ static void mark_bad_packed_object(struct packed_git *p,
 {
        unsigned i;
        for (i = 0; i < p->num_bad_objects; i++)
-               if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
+               if (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i))
                        return;
-       p->bad_object_sha1 = xrealloc(p->bad_object_sha1, 20 * (p->num_bad_objects + 1));
-       hashcpy(p->bad_object_sha1 + 20 * p->num_bad_objects, sha1);
+       p->bad_object_sha1 = xrealloc(p->bad_object_sha1,
+                                     st_mult(GIT_SHA1_RAWSZ,
+                                             st_add(p->num_bad_objects, 1)));
+       hashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1);
        p->num_bad_objects++;
 }
 
@@ -1942,7 +1946,7 @@ static enum object_type packed_to_object_type(struct packed_git *p,
                /* Push the object we're going to leave behind */
                if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {
                        poi_stack_alloc = alloc_nr(poi_stack_nr);
-                       poi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc);
+                       ALLOC_ARRAY(poi_stack, poi_stack_alloc);
                        memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);
                } else {
                        ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);
@@ -2308,7 +2312,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                if (delta_stack_nr >= delta_stack_alloc
                    && delta_stack == small_delta_stack) {
                        delta_stack_alloc = alloc_nr(delta_stack_nr);
-                       delta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc);
+                       ALLOC_ARRAY(delta_stack, delta_stack_alloc);
                        memcpy(delta_stack, small_delta_stack,
                               sizeof(*delta_stack)*delta_stack_nr);
                } else {
@@ -2446,6 +2450,20 @@ const unsigned char *nth_packed_object_sha1(struct packed_git *p,
        }
 }
 
+void check_pack_index_ptr(const struct packed_git *p, const void *vptr)
+{
+       const unsigned char *ptr = vptr;
+       const unsigned char *start = p->index_data;
+       const unsigned char *end = start + p->index_size;
+       if (ptr < start)
+               die(_("offset before start of pack index for %s (corrupt index?)"),
+                   p->pack_name);
+       /* No need to check for underflow; .idx files must be at least 8 bytes */
+       if (ptr >= end - 8)
+               die(_("offset beyond end of pack index for %s (truncated index?)"),
+                   p->pack_name);
+}
+
 off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
 {
        const unsigned char *index = p->index_data;
@@ -2459,6 +2477,7 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
                if (!(off & 0x80000000))
                        return off;
                index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
+               check_pack_index_ptr(p, index);
                return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
                                   ntohl(*((uint32_t *)(index + 4)));
        }
index 892db21..ab5a163 100644 (file)
@@ -87,9 +87,8 @@ static void find_short_object_filename(int len, const char *hex_pfx, struct disa
                 * 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 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
 
        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;
index 60f1505..4d554ca 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -315,8 +315,8 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa)
        info->shallow = sa;
        if (!sa)
                return;
-       info->ours = xmalloc(sizeof(*info->ours) * sa->nr);
-       info->theirs = xmalloc(sizeof(*info->theirs) * sa->nr);
+       ALLOC_ARRAY(info->ours, sa->nr);
+       ALLOC_ARRAY(info->theirs, sa->nr);
        for (i = 0; i < sa->nr; i++) {
                if (has_sha1_file(sa->sha1[i])) {
                        struct commit_graft *graft;
@@ -389,7 +389,7 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,
        unsigned int i, nr;
        struct commit_list *head = NULL;
        int bitmap_nr = (info->nr_bits + 31) / 32;
-       int bitmap_size = bitmap_nr * sizeof(uint32_t);
+       size_t bitmap_size = st_mult(bitmap_nr, sizeof(uint32_t));
        uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */
        uint32_t *bitmap = paint_alloc(info);
        struct commit *c = lookup_commit_reference_gently(sha1, 1);
@@ -487,7 +487,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info,
        struct paint_info pi;
 
        trace_printf_key(&trace_shallow, "shallow: assign_shallow_commits_to_refs\n");
-       shallow = xmalloc(sizeof(*shallow) * (info->nr_ours + info->nr_theirs));
+       ALLOC_ARRAY(shallow, info->nr_ours + info->nr_theirs);
        for (i = 0; i < info->nr_ours; i++)
                shallow[nr_shallow++] = info->ours[i];
        for (i = 0; i < info->nr_theirs; i++)
index d9e4903..acf8d54 100644 (file)
@@ -50,7 +50,8 @@ int main(int argc, char **argv)
                        unsigned char sha1[20];
                        uint32_t crc;
                        uint32_t off;
-               } *entries = xmalloc(nr * sizeof(entries[0]));
+               } *entries;
+               ALLOC_ARRAY(entries, nr);
                for (i = 0; i < nr; i++)
                        if (fread(entries[i].sha1, 20, 1, stdin) != 1)
                                die("unable to read sha1 %u/%u", i, nr);
index d76f0ae..de7a7c2 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -685,7 +685,7 @@ char *xstrdup_tolower(const char *string)
        size_t len, i;
 
        len = strlen(string);
-       result = xmalloc(len + 1);
+       result = xmallocz(len);
        for (i = 0; i < len; i++)
                result[i] = tolower(string[i]);
        result[i] = '\0';
index 14e7624..2a6cc9e 100644 (file)
@@ -68,7 +68,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
        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 @@ static int add_submodule_odb(const char *path)
        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)) {
@@ -137,8 +137,8 @@ static int add_submodule_odb(const char *path)
                                        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,11 +1034,9 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
        /* 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);
index 91235b7..9863d0d 100755 (executable)
@@ -218,4 +218,15 @@ test_expect_success 'check line errors for malformed values' '
        test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result
 '
 
+test_expect_success 'error on modifying repo config without repo' '
+       mkdir no-repo &&
+       (
+               GIT_CEILING_DIRECTORIES=$(pwd) &&
+               export GIT_CEILING_DIRECTORIES &&
+               cd no-repo &&
+               test_must_fail git config a.b c 2>err &&
+               grep "not in a git directory" err
+       )
+'
+
 test_done
similarity index 100%
rename from t/t1501-worktree.sh
rename to t/t1501-work-tree.sh
index 199b22d..b99d519 100755 (executable)
@@ -56,30 +56,4 @@ test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
        test_i18ngrep ! "^HEAD is now at" stderr
 '
 
-test_expect_success 'wildcard ambiguation, paths win' '
-       git init ambi &&
-       (
-               cd ambi &&
-               echo a >a.c &&
-               git add a.c &&
-               echo b >a.c &&
-               git checkout "*.c" &&
-               echo a >expect &&
-               test_cmp expect a.c
-       )
-'
-
-test_expect_success !MINGW 'wildcard ambiguation, refs lose' '
-       git init ambi2 &&
-       (
-               cd ambi2 &&
-               echo a >"*.c" &&
-               git add . &&
-               test_must_fail git show :"*.c" &&
-               git show :"*.c" -- >actual &&
-               echo a >expect &&
-               test_cmp expect actual
-       )
-'
-
 test_done
index 75ebb1b..1b1b65a 100755 (executable)
@@ -8,6 +8,16 @@ test_expect_success 'setup' '
        test_commit init
 '
 
+test_expect_success 'rev-parse --git-common-dir on main worktree' '
+       git rev-parse --git-common-dir >actual &&
+       echo .git >expected &&
+       test_cmp expected actual &&
+       mkdir sub &&
+       git -C sub rev-parse --git-common-dir >actual2 &&
+       echo sub/.git >expected2 &&
+       test_cmp expected2 actual2
+'
+
 test_expect_success '"list" all worktrees from main' '
        echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
        test_when_finished "rm -rf here && git worktree prune" &&
index cdaf6f6..a897248 100755 (executable)
@@ -446,6 +446,13 @@ test_expect_success '--set-upstream-to fails on a non-ref' '
        test_must_fail git branch --set-upstream-to HEAD^{}
 '
 
+test_expect_success '--set-upstream-to fails on locked config' '
+       test_when_finished "rm -f .git/config.lock" &&
+       >.git/config.lock &&
+       git branch locked &&
+       test_must_fail git branch --set-upstream-to locked
+'
+
 test_expect_success 'use --set-upstream-to modify HEAD' '
        test_config branch.master.remote foo &&
        test_config branch.master.merge foo &&
@@ -466,6 +473,13 @@ test_expect_success '--unset-upstream should fail if given a non-existent branch
        test_must_fail git branch --unset-upstream i-dont-exist
 '
 
+test_expect_success '--unset-upstream should fail if config is locked' '
+       test_when_finished "rm -f .git/config.lock" &&
+       git branch --set-upstream-to locked &&
+       >.git/config.lock &&
+       test_must_fail git branch --unset-upstream
+'
+
 test_expect_success 'test --unset-upstream on HEAD' '
        git branch my14 &&
        test_config branch.master.remote foo &&
@@ -579,7 +593,7 @@ test_expect_success 'avoid ambiguous track' '
        git config remote.ambi1.fetch refs/heads/lalala:refs/heads/master &&
        git config remote.ambi2.url lilili &&
        git config remote.ambi2.fetch refs/heads/lilili:refs/heads/master &&
-       git branch all1 master &&
+       test_must_fail git branch all1 master &&
        test -z "$(git config branch.all1.merge)"
 '
 
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
new file mode 100755 (executable)
index 0000000..a8a587a
--- /dev/null
@@ -0,0 +1,179 @@
+#!/bin/sh
+
+test_description='bounds-checking of access to mmapped on-disk file formats'
+. ./test-lib.sh
+
+clear_base () {
+       test_when_finished 'restore_base' &&
+       rm -f $base
+}
+
+restore_base () {
+       cp base-backup/* .git/objects/pack/
+}
+
+do_pack () {
+       pack_objects=$1; shift
+       sha1=$(
+               for i in $pack_objects
+               do
+                       echo $i
+               done | git pack-objects "$@" .git/objects/pack/pack
+       ) &&
+       pack=.git/objects/pack/pack-$sha1.pack &&
+       idx=.git/objects/pack/pack-$sha1.idx &&
+       chmod +w $pack $idx &&
+       test_when_finished 'rm -f "$pack" "$idx"'
+}
+
+munge () {
+       printf "$3" | dd of="$1" bs=1 conv=notrunc seek=$2
+}
+
+# Offset in a v2 .idx to its initial and extended offset tables. For an index
+# with "nr" objects, this is:
+#
+#   magic(4) + version(4) + fan-out(4*256) + sha1s(20*nr) + crc(4*nr),
+#
+# for the initial, and another ofs(4*nr) past that for the extended.
+#
+ofs_table () {
+       echo $((4 + 4 + 4*256 + 20*$1 + 4*$1))
+}
+extended_table () {
+       echo $(($(ofs_table "$1") + 4*$1))
+}
+
+test_expect_success 'set up base packfile and variables' '
+       # the hash of this content starts with ff, which
+       # makes some later computations much simpler
+       echo 74 >file &&
+       git add file &&
+       git commit -m base &&
+       git repack -ad &&
+       base=$(echo .git/objects/pack/*) &&
+       chmod +w $base &&
+       mkdir base-backup &&
+       cp $base base-backup/ &&
+       object=$(git rev-parse HEAD:file)
+'
+
+test_expect_success 'pack/index object count mismatch' '
+       do_pack $object &&
+       munge $pack 8 "\377\0\0\0" &&
+       clear_base &&
+
+       # We enumerate the objects from the completely-fine
+       # .idx, but notice later that the .pack is bogus
+       # and fail to show any data.
+       echo "$object missing" >expect &&
+       git cat-file --batch-all-objects --batch-check >actual &&
+       test_cmp expect actual &&
+
+       # ...and here fail to load the object (without segfaulting),
+       # but fallback to a good copy if available.
+       test_must_fail git cat-file blob $object &&
+       restore_base &&
+       git cat-file blob $object >actual &&
+       test_cmp file actual &&
+
+       # ...and make sure that index-pack --verify, which has its
+       # own reading routines, does not segfault.
+       test_must_fail git index-pack --verify $pack
+'
+
+test_expect_success 'matched bogus object count' '
+       do_pack $object &&
+       munge $pack 8 "\377\0\0\0" &&
+       munge $idx $((255 * 4)) "\377\0\0\0" &&
+       clear_base &&
+
+       # Unlike above, we should notice early that the .idx is totally
+       # bogus, and not even enumerate its contents.
+       >expect &&
+       git cat-file --batch-all-objects --batch-check >actual &&
+       test_cmp expect actual &&
+
+       # But as before, we can do the same object-access checks.
+       test_must_fail git cat-file blob $object &&
+       restore_base &&
+       git cat-file blob $object >actual &&
+       test_cmp file actual &&
+
+       test_must_fail git index-pack --verify $pack
+'
+
+# Note that we cannot check the fallback case for these
+# further .idx tests, as we notice the problem in functions
+# whose interface doesn't allow an error return (like use_pack()),
+# and thus we just die().
+#
+# There's also no point in doing enumeration tests, as
+# we are munging offsets here, which are about looking up
+# specific objects.
+
+test_expect_success 'bogus object offset (v1)' '
+       do_pack $object --index-version=1 &&
+       munge $idx $((4 * 256)) "\377\0\0\0" &&
+       clear_base &&
+       test_must_fail git cat-file blob $object &&
+       test_must_fail git index-pack --verify $pack
+'
+
+test_expect_success 'bogus object offset (v2, no msb)' '
+       do_pack $object --index-version=2 &&
+       munge $idx $(ofs_table 1) "\0\377\0\0" &&
+       clear_base &&
+       test_must_fail git cat-file blob $object &&
+       test_must_fail git index-pack --verify $pack
+'
+
+test_expect_success 'bogus offset into v2 extended table' '
+       do_pack $object --index-version=2 &&
+       munge $idx $(ofs_table 1) "\377\0\0\0" &&
+       clear_base &&
+       test_must_fail git cat-file blob $object &&
+       test_must_fail git index-pack --verify $pack
+'
+
+test_expect_success 'bogus offset inside v2 extended table' '
+       # We need two objects here, so we can plausibly require
+       # an extended table (if the first object were larger than 2^31).
+       do_pack "$object $(git rev-parse HEAD)" --index-version=2 &&
+
+       # We have to make extra room for the table, so we cannot
+       # just munge in place as usual.
+       {
+               dd if=$idx bs=1 count=$(($(ofs_table 2) + 4)) &&
+               printf "\200\0\0\0" &&
+               printf "\377\0\0\0\0\0\0\0" &&
+               dd if=$idx bs=1 skip=$(extended_table 2)
+       } >tmp &&
+       mv tmp "$idx" &&
+       clear_base &&
+       test_must_fail git cat-file blob $object &&
+       test_must_fail git index-pack --verify $pack
+'
+
+test_expect_success 'bogus OFS_DELTA in packfile' '
+       # Generate a pack with a delta in it.
+       base=$(test-genrandom foo 3000 | git hash-object --stdin -w) &&
+       delta=$(test-genrandom foo 2000 | git hash-object --stdin -w) &&
+       do_pack "$base $delta" --delta-base-offset &&
+       rm -f .git/objects/??/* &&
+
+       # Double check that we have the delta we expect.
+       echo $base >expect &&
+       echo $delta | git cat-file --batch-check="%(deltabase)" >actual &&
+       test_cmp expect actual &&
+
+       # Now corrupt it. We assume the varint size for the delta is small
+       # enough to fit in the first byte (which it should be, since it
+       # is a pure deletion from the base), and that original ofs_delta
+       # takes 2 bytes (which it should, as it should be ~3000).
+       ofs=$(git show-index <$idx | grep $delta | cut -d" " -f1) &&
+       munge $pack $(($ofs + 1)) "\177\377" &&
+       test_must_fail git cat-file blob $delta >/dev/null
+'
+
+test_done
index 89224ed..a3e12d2 100755 (executable)
@@ -101,7 +101,10 @@ test_expect_success 'push with receive.fsckobjects' '
                git config transfer.fsckobjects false
        ) &&
        test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act &&
-       test_cmp exp act
+       {
+               test_cmp exp act ||
+               ! test -s act
+       }
 '
 
 test_expect_success 'push with transfer.fsckobjects' '
index dfaf9d9..013e03d 100755 (executable)
@@ -932,6 +932,15 @@ test_expect_success 'get-url on new remote' '
        echo foo | get_url_test --push --all someremote
 '
 
+test_expect_success 'remote set-url with locked config' '
+       test_when_finished "rm -f .git/config.lock" &&
+       git config --get-all remote.someremote.url >expect &&
+       >.git/config.lock &&
+       test_must_fail git remote set-url someremote baz &&
+       git config --get-all remote.someremote.url >actual &&
+       cmp expect actual
+'
+
 test_expect_success 'remote set-url bar' '
        git remote set-url someremote bar &&
        echo bar >expect &&
diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh
new file mode 100755 (executable)
index 0000000..a290ffc
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+test_description='test dwim of revs versus pathspecs in revision parser'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit base &&
+       echo content >"br[ack]ets" &&
+       git add . &&
+       test_tick &&
+       git commit -m brackets
+'
+
+test_expect_success 'non-rev wildcard dwims to pathspec' '
+       git log -- "*.t" >expect &&
+       git log    "*.t" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'tree:path with metacharacters dwims to rev' '
+       git show "HEAD:br[ack]ets" -- >expect &&
+       git show "HEAD:br[ack]ets"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '^{foo} with metacharacters dwims to rev' '
+       git log "HEAD^{/b.*}" -- >expect &&
+       git log "HEAD^{/b.*}"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '@{foo} with metacharacters dwims to rev' '
+       git log "HEAD@{now [or thereabouts]}" -- >expect &&
+       git log "HEAD@{now [or thereabouts]}"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success ':/*.t from a subdir dwims to a pathspec' '
+       mkdir subdir &&
+       (
+               cd subdir &&
+               git log -- ":/*.t" >expect &&
+               git log    ":/*.t" >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_done
index 540771c..be82a75 100755 (executable)
@@ -999,5 +999,30 @@ test_expect_success 'submodule add clone shallow submodule' '
        )
 '
 
+test_expect_success 'submodule helper list is not confused by common prefixes' '
+       mkdir -p dir1/b &&
+       (
+               cd dir1/b &&
+               git init &&
+               echo hi >testfile2 &&
+               git add . &&
+               git commit -m "test1"
+       ) &&
+       mkdir -p dir2/b &&
+       (
+               cd dir2/b &&
+               git init &&
+               echo hello >testfile1 &&
+               git add .  &&
+               git commit -m "test2"
+       ) &&
+       git submodule add /dir1/b dir1/b &&
+       git submodule add /dir2/b dir2/b &&
+       git commit -m "first submodule commit" &&
+       git submodule--helper list dir1/b |cut -c51- >actual &&
+       echo "dir1/b" >expect &&
+       test_cmp expect actual
+'
+
 
 test_done
index 847d098..75da219 100755 (executable)
@@ -33,11 +33,15 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
+filter_author_summary () {
+       sed -n -e '/^author /p' -e '/^summary /p' "$@"
+}
+
 test_expect_success !MINGW \
        'blame respects i18n.commitencoding' '
-       git blame --incremental file | \
-               egrep "^(author|summary) " > actual &&
-       test_cmp actual expected
+       git blame --incremental file >output &&
+       filter_author_summary output >actual &&
+       test_cmp expected actual
 '
 
 cat >expected <<EOF
@@ -52,9 +56,9 @@ EOF
 test_expect_success !MINGW \
        'blame respects i18n.logoutputencoding' '
        git config i18n.logoutputencoding eucJP &&
-       git blame --incremental file | \
-               egrep "^(author|summary) " > actual &&
-       test_cmp actual expected
+       git blame --incremental file >output &&
+       filter_author_summary output >actual &&
+       test_cmp expected actual
 '
 
 cat >expected <<EOF
@@ -68,9 +72,9 @@ EOF
 
 test_expect_success !MINGW \
        'blame respects --encoding=UTF-8' '
-       git blame --incremental --encoding=UTF-8 file | \
-               egrep "^(author|summary) " > actual &&
-       test_cmp actual expected
+       git blame --incremental --encoding=UTF-8 file >output &&
+       filter_author_summary output >actual &&
+       test_cmp expected actual
 '
 
 cat >expected <<EOF
@@ -84,9 +88,9 @@ EOF
 
 test_expect_success !MINGW \
        'blame respects --encoding=none' '
-       git blame --incremental --encoding=none file | \
-               egrep "^(author|summary) " > actual &&
-       test_cmp actual expected
+       git blame --incremental --encoding=none file >output &&
+       filter_author_summary output >actual &&
+       test_cmp expected actual
 '
 
 test_done
index 812c9cd..7117719 100755 (executable)
@@ -35,7 +35,7 @@ exit 1
 
 check_entries () {
        # $1 == directory, $2 == expected
-       grep '^/' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual
+       sed -ne '/^\//p' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual
        if test -z "$2"
        then
                >expected
index c64e5a5..8d99eb3 100644 (file)
@@ -617,7 +617,7 @@ test_must_fail () {
                return 0
        elif test $exit_code -gt 129 && test $exit_code -le 192
        then
-               echo >&2 "test_must_fail: died by signal: $*"
+               echo >&2 "test_must_fail: died by signal $(($exit_code - 128)): $*"
                return 1
        elif test $exit_code -eq 127
        then
index d847583..80ba941 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# An example hook script to blocks unannotated tags from entering.
+# An example hook script to block unannotated tags from entering.
 # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
 #
 # To enable this hook, rename this file to "update".
index c3adcd8..0c15f18 100644 (file)
@@ -8,21 +8,14 @@
  */
 static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
 {
-       const char *ceil = item->string;
-       int len = strlen(ceil);
-       char buf[PATH_MAX+1];
+       char *ceil = item->string;
 
-       if (len == 0)
+       if (!*ceil)
                die("Empty path is not supported");
-       if (len > PATH_MAX)
-               die("Path \"%s\" is too long", ceil);
        if (!is_absolute_path(ceil))
                die("Path \"%s\" is not absolute", ceil);
-       if (normalize_path_copy(buf, ceil) < 0)
+       if (normalize_path_copy(ceil, ceil) < 0)
                die("Path \"%s\" could not be normalized", ceil);
-       len = strlen(buf);
-       free(item->string);
-       item->string = xstrdup(buf);
        return 1;
 }
 
@@ -166,7 +159,7 @@ static struct test_data dirname_data[] = {
 int main(int argc, char **argv)
 {
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
-               char *buf = xmalloc(PATH_MAX + 1);
+               char *buf = xmallocz(strlen(argv[2]));
                int rv = normalize_path_copy(buf, argv[2]);
                if (rv)
                        buf = "++failed++";
index 67f3666..988047b 100644 (file)
@@ -1306,7 +1306,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
                 * This condition shouldn't be met in a non-deepening fetch
                 * (see builtin/fetch.c:quickfetch()).
                 */
-               heads = xmalloc(nr_refs * sizeof(*heads));
+               ALLOC_ARRAY(heads, nr_refs);
                for (rm = refs; rm; rm = rm->next)
                        heads[nr_heads++] = rm;
        }
@@ -1350,7 +1350,7 @@ int transport_disconnect(struct transport *transport)
  */
 char *transport_anonymize_url(const char *url)
 {
-       char *anon_url, *scheme_prefix, *anon_part;
+       char *scheme_prefix, *anon_part;
        size_t anon_len, prefix_len = 0;
 
        anon_part = strchr(url, '@');
@@ -1384,10 +1384,8 @@ char *transport_anonymize_url(const char *url)
                        goto literal_copy;
                prefix_len = scheme_prefix - url + 3;
        }
-       anon_url = xcalloc(1, 1 + prefix_len + anon_len);
-       memcpy(anon_url, url, prefix_len);
-       memcpy(anon_url + prefix_len, anon_part, anon_len);
-       return anon_url;
+       return xstrfmt("%.*s%.*s", (int)prefix_len, url,
+                      (int)anon_len, anon_part);
 literal_copy:
        return xstrdup(url);
 }
index 290a1da..4dda9a1 100644 (file)
@@ -124,8 +124,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
        unsigned mode, const unsigned char *sha1)
 {
        struct combine_diff_path *p;
-       int len = base->len + pathlen;
-       int alloclen = combine_diff_path_size(nparent, len);
+       size_t len = st_add(base->len, pathlen);
+       size_t alloclen = combine_diff_path_size(nparent, len);
 
        /* if last->next is !NULL - it is a pre-allocated memory, we can reuse */
        p = last->next;
index 4a7e78f..2ef0ce5 100644 (file)
@@ -23,6 +23,10 @@ int userdiff_config(const char *k, const char *v);
 struct userdiff_driver *userdiff_find_by_name(const char *name);
 struct userdiff_driver *userdiff_find_by_path(const char *path);
 
+/*
+ * Initialize any textconv-related fields in the driver and return it, or NULL
+ * if it does not have textconv enabled at all.
+ */
 struct userdiff_driver *userdiff_get_textconv(struct userdiff_driver *driver);
 
 #endif /* USERDIFF */
index 5200178..32c6c60 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -152,6 +152,9 @@ void *xcalloc(size_t nmemb, size_t size)
 {
        void *ret;
 
+       if (unsigned_mult_overflows(nmemb, size))
+               die("data too large to fit into virtual memory space");
+
        memory_limit_check(size * nmemb, 0);
        ret = calloc(nmemb, size);
        if (!ret && (!nmemb || !size))
index e7afe7a..49e80aa 100644 (file)
@@ -1,8 +1,12 @@
 #include "cache.h"
+#include "run-command.h"
 
 static void check_pipe(int err)
 {
        if (err == EPIPE) {
+               if (in_async())
+                       async_exit(141);
+
                signal(SIGPIPE, SIG_DFL);
                raise(SIGPIPE);
                /* Should never happen, but just in case... */
index cb67c1c..54236f2 100644 (file)
@@ -265,7 +265,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
        for (i = 0, regs->nr = 1; value[i]; i++)
                if (value[i] == '\n')
                        regs->nr++;
-       regs->array = xmalloc(regs->nr * sizeof(struct ff_reg));
+       ALLOC_ARRAY(regs->array, regs->nr);
        for (i = 0; i < regs->nr; i++) {
                struct ff_reg *reg = regs->array + i;
                const char *ep = strchr(value, '\n'), *expression;
index c033991..4fb7e79 100644 (file)
@@ -42,7 +42,6 @@ extern "C" {
 #define XDF_IGNORE_BLANK_LINES (1 << 7)
 
 #define XDL_EMIT_FUNCNAMES (1 << 0)
-#define XDL_EMIT_COMMON (1 << 1)
 #define XDL_EMIT_FUNCCONTEXT (1 << 2)
 
 #define XDL_MMB_READONLY (1 << 0)
index 4266ada..993724b 100644 (file)
@@ -120,21 +120,6 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
        return -1;
 }
 
-static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
-                           xdemitconf_t const *xecfg) {
-       xdfile_t *xdf = &xe->xdf2;
-       const char *rchg = xdf->rchg;
-       long ix;
-
-       for (ix = 0; ix < xdf->nrec; ix++) {
-               if (rchg[ix])
-                       continue;
-               if (xdl_emit_record(xdf, ix, "", ecb))
-                       return -1;
-       }
-       return 0;
-}
-
 struct func_line {
        long len;
        char buf[80];
@@ -170,9 +155,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
        long funclineprev = -1;
        struct func_line func_line = { 0 };
 
-       if (xecfg->flags & XDL_EMIT_COMMON)
-               return xdl_emit_common(xe, xscr, ecb, xecfg);
-
        for (xch = xscr; xch; xch = xche->next) {
                xche = xdl_get_hunk(&xch, xecfg);
                if (!xch)
index d98f430..f338ad6 100644 (file)
@@ -641,8 +641,11 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
        result->ptr = NULL;
        result->size = 0;
 
-       if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0 ||
-                       xdl_do_diff(orig, mf2, xpp, &xe2) < 0) {
+       if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) {
+               return -1;
+       }
+       if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) {
+               xdl_free_env(&xe1);
                return -1;
        }
        if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 ||
@@ -654,6 +657,8 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
        if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 ||
            xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 ||
            xdl_build_script(&xe2, &xscr2) < 0) {
+               xdl_free_script(xscr1);
+               xdl_free_env(&xe1);
                xdl_free_env(&xe2);
                return -1;
        }