diff options
-rw-r--r-- | Documentation/RelNotes/2.7.3.txt | 62 | ||||
-rw-r--r-- | Documentation/RelNotes/2.8.0.txt | 21 | ||||
-rw-r--r-- | Documentation/git-ls-files.txt | 2 | ||||
-rw-r--r-- | Documentation/git-rebase.txt | 2 | ||||
-rw-r--r-- | Documentation/git.txt | 3 | ||||
-rw-r--r-- | Documentation/gitignore.txt | 38 | ||||
-rw-r--r-- | Documentation/user-manual.txt | 2 | ||||
-rwxr-xr-x | GIT-VERSION-GEN | 2 | ||||
-rw-r--r-- | builtin/checkout.c | 2 | ||||
-rw-r--r-- | builtin/clone.c | 10 | ||||
-rw-r--r-- | builtin/index-pack.c | 1 | ||||
-rw-r--r-- | cache.h | 10 | ||||
-rw-r--r-- | compat/mingw.c | 2 | ||||
-rw-r--r-- | compat/win32/pthread.h | 2 | ||||
-rw-r--r-- | config.mak.uname | 3 | ||||
-rw-r--r-- | http.c | 6 | ||||
-rw-r--r-- | ref-filter.c | 28 | ||||
-rw-r--r-- | run-command.c | 24 | ||||
-rw-r--r-- | run-command.h | 9 | ||||
-rw-r--r-- | sha1_file.c | 17 | ||||
-rw-r--r-- | submodule.c | 7 | ||||
-rw-r--r-- | t/lib-httpd/apache.conf | 3 | ||||
-rwxr-xr-x | t/t0001-init.sh | 20 | ||||
-rwxr-xr-x | t/t5313-pack-bounds-checks.sh | 179 | ||||
-rwxr-xr-x | t/t5510-fetch.sh | 10 | ||||
-rwxr-xr-x | t/t9700/test.pl | 8 | ||||
-rw-r--r-- | test-run-command.c | 1 | ||||
-rw-r--r-- | trailer.c | 2 |
28 files changed, 395 insertions, 81 deletions
diff --git a/Documentation/RelNotes/2.7.3.txt b/Documentation/RelNotes/2.7.3.txt new file mode 100644 index 0000000000..6adf038915 --- /dev/null +++ b/Documentation/RelNotes/2.7.3.txt @@ -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. diff --git a/Documentation/RelNotes/2.8.0.txt b/Documentation/RelNotes/2.8.0.txt index 290774e61a..14b6c70ed6 100644 --- a/Documentation/RelNotes/2.8.0.txt +++ b/Documentation/RelNotes/2.8.0.txt @@ -233,6 +233,13 @@ Performance, Internal Implementation, Development Support etc. * There is a new DEVELOPER knob that enables many compiler warning options in the Makefile. + * The way the test scripts configure the Apache web server has been + updated to work also for Apache 2.4 running on RedHat derived + distros. + + * Out of maintenance gcc on OSX 10.6 fails to compile the code in + 'master'; work it around by using clang by default on the platform. + Also contains various documentation updates and code clean-ups. @@ -274,6 +281,11 @@ notes for details). listing and sparse checkout selection areas in 2.7.0; the change that is responsible for the regression has been reverted. + * Another try to improve the ignore mechanism that lets you say "this + is excluded" and then later say "oh, no, this part (that is a + subset of the previous part) is not excluded". This has still a + known limitation, though. + * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR (e.g. COMMIT_EDITMSG) that is meant to be left after the command is done. This however did not work well if the repository is set to @@ -365,10 +377,6 @@ notes for details). misbehaved when run from a subdirectory. (merge 17f1365 nd/git-common-dir-fix later to maint). - * Another try to add support to the ignore mechanism that lets you - say "this is excluded" and then later say "oh, no, this part (that - is a subset of the previous part) is not excluded". - * "git worktree add -B <branchname>" did not work. * The "v(iew)" subcommand of the interactive "git am -i" command was @@ -410,6 +418,11 @@ notes for details). but didn't say the reason correctly. (merge 638fa62 js/config-set-in-non-repository later to maint). + * 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. + (merge 7465feb jk/pack-idx-corruption-safety later to maint). + * Other minor clean-ups and documentation updates (merge f459823 ak/extract-argv0-last-dir-sep later to maint). (merge 63ca1c0 ak/git-strip-extension-from-dashed-command later to maint). diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 0e08f567a1..75c3f4157d 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -155,7 +155,7 @@ a space) at the start of each line: <eolinfo> is either "-text", "none", "lf", "crlf", "mixed" or "". + "" means the file is not a regular file, it is not in the index or -not accessable in the working tree. +not accessible in the working tree. + <eolattr> is the attribute that is used when checking out or committing, it is either "", "-text", "text", "text=auto", "text eol=lf", "text eol=crlf". diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 6cca8bb51d..6ed610a031 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -3,7 +3,7 @@ git-rebase(1) NAME ---- -git-rebase - Forward-port local commits to the updated upstream head +git-rebase - Reapply commits on top of another base tip SYNOPSIS -------- diff --git a/Documentation/git.txt b/Documentation/git.txt index 2754af8f77..951b24661e 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -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]. diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index 3ded6fdc99..91d1ce2a89 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -148,7 +148,43 @@ excluded, the following conditions must be met: be in the same .gitignore file. - The directory part in the re-include rules must be literal (i.e. no - wildcards) + wildcards and has to start with a `/`). + +A re-inclusion of a directory makes all files in the directory +unignored. For example, suppose you have files `.gitignore`, +`dir/file1`, `dir/file2`, and `dir/file3`, and have the following in +your `.gitignore`: + +---------------- +# .gitignore is not mentioned in .gitignore +* +!/dir +# dir/file1 is not mentioned in .gitignore +dir/file2 +!dir/file3 +---------------- + +Then: + + - `.gitignore` gets ignored, because it matches the `*` at the top + level; + + - `dir/file1` does not get ignored, because `/dir` marks everything + underneath `dir/` directory to be 're-included' unless otherwise + specified; + + - `dir/file2` gets ignored, because `dir/file2` matches it. + + - `dir/file3` does not get ignored, because `!dir/file3` matches it. + Note that the entry `!dir/file3` is redundant because everything + underneath `dir/` is marked to be 're-included' already. + +Some earlier versions of Git treated `!/dir` above differently in +that it did not cause the paths under it unignored (but merely told +Git that patterns that begin with dir/ should not be ignored), but +this has been corrected to be consistent with `/dir` that says "the +directory `dir/` and everything below are ignored." + EXAMPLES -------- diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index ec6bacfcdf..5e07454572 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -2134,7 +2134,7 @@ browsing the repository using gitweb. The default server when using instaweb is lighttpd. See the file gitweb/INSTALL in the Git source tree and -linkgit:gitweb[1] for instructions on details setting up a permament +linkgit:gitweb[1] for instructions on details setting up a permanent installation with a CGI or Perl capable server. [[how-to-get-a-git-repository-with-minimal-history]] diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index b872b6e7d6..b373d8ae8d 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.8.0-rc0 +DEF_VER=v2.8.0-rc2 LF=' ' diff --git a/builtin/checkout.c b/builtin/checkout.c index cfa66e25eb..efcbd8f6b5 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -662,7 +662,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts, } } else if (new->path) { /* Switch branches. */ if (create_symref("HEAD", new->path, msg.buf) < 0) - die("unable to update HEAD"); + die(_("unable to update HEAD")); if (!opts->quiet) { if (old->path && !strcmp(new->path, old->path)) { if (opts->new_branch_force) diff --git a/builtin/clone.c b/builtin/clone.c index 9ac6c01442..661639255c 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -236,8 +236,8 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git"); if (!len || (len == 1 && *start == '/')) - die("No directory name could be guessed.\n" - "Please specify a directory on the command line"); + die(_("No directory name could be guessed.\n" + "Please specify a directory on the command line")); if (is_bare) dir = xstrfmt("%.*s.git", (int)len, start); @@ -644,7 +644,7 @@ static void update_remote_refs(const struct ref *refs, if (create_symref(head_ref.buf, remote_head_points_at->peer_ref->name, msg) < 0) - die("unable to update %s", head_ref.buf); + die(_("unable to update %s"), head_ref.buf); strbuf_release(&head_ref); } } @@ -656,7 +656,7 @@ static void update_head(const struct ref *our, const struct ref *remote, if (our && skip_prefix(our->name, "refs/heads/", &head)) { /* Local default branch link */ if (create_symref("HEAD", our->name, NULL) < 0) - die("unable to update HEAD"); + die(_("unable to update HEAD")); if (!option_bare) { update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); @@ -750,7 +750,7 @@ static void write_config(struct string_list *config) for (i = 0; i < config->nr; i++) { if (git_config_parse_parameter(config->items[i].string, write_one_config, NULL) < 0) - die("unable to write parameters to config file"); + die(_("unable to write parameters to config file")); } } diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 193908a619..45245199ae 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -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; /* @@ -1370,6 +1370,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 diff --git a/compat/mingw.c b/compat/mingw.c index cfedcf9656..54c82ecf20 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1069,7 +1069,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen free(quoted); } - wargs = xmalloc_array(st_add(st_mult(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); diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index 20b35a283c..b6ed9e7462 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -78,7 +78,7 @@ extern int win32_pthread_join(pthread_t *thread, void **value_ptr); #define pthread_equal(t1, t2) ((t1).tid == (t2).tid) extern pthread_t pthread_self(void); -static inline int pthread_exit(void *ret) +static inline void NORETURN pthread_exit(void *ret) { ExitThread((DWORD)(intptr_t)ret); } diff --git a/config.mak.uname b/config.mak.uname index d6f7980bb9..4c68e078e7 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -102,6 +102,9 @@ ifeq ($(uname_S),Darwin) ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2) NO_STRLCPY = YesPlease endif + ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -eq 10 && echo 1),1) + CC = clang + endif ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 11 && echo 1),1) HAVE_GETDELIM = YesPlease endif @@ -70,6 +70,7 @@ static long curl_low_speed_limit = -1; static long curl_low_speed_time = -1; static int curl_ftp_no_epsv; static const char *curl_http_proxy; +static const char *curl_no_proxy; static const char *http_proxy_authmethod; static struct { const char *name; @@ -624,6 +625,11 @@ static CURL *get_curl_handle(void) } curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host); +#if LIBCURL_VERSION_NUM >= 0x071304 + var_override(&curl_no_proxy, getenv("NO_PROXY")); + var_override(&curl_no_proxy, getenv("no_proxy")); + curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy); +#endif } init_curl_proxy_auth(result); diff --git a/ref-filter.c b/ref-filter.c index bb79d6b9cc..bc551a752c 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -74,14 +74,14 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg) static void body_atom_parser(struct used_atom *atom, const char *arg) { if (arg) - die("%%(body) does not take arguments"); + die(_("%%(body) does not take arguments")); atom->u.contents.option = C_BODY_DEP; } static void subject_atom_parser(struct used_atom *atom, const char *arg) { if (arg) - die("%%(subject) does not take arguments"); + die(_("%%(subject) does not take arguments")); atom->u.contents.option = C_SUB; } @@ -241,7 +241,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep) if (*sp == '*' && sp < ep) sp++; /* deref */ if (ep <= sp) - die("malformed field name: %.*s", (int)(ep-atom), atom); + die(_("malformed field name: %.*s"), (int)(ep-atom), atom); /* Do we have the atom already used elsewhere? */ for (i = 0; i < used_atom_cnt; i++) { @@ -267,7 +267,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep) } if (ARRAY_SIZE(valid_atom) <= i) - die("unknown field name: %.*s", (int)(ep-atom), atom); + die(_("unknown field name: %.*s"), (int)(ep-atom), atom); /* Add it in, including the deref prefix */ at = used_atom_cnt; @@ -421,7 +421,7 @@ int verify_ref_format(const char *format) int at; if (!ep) - return error("malformed format string %s", sp); + return error(_("malformed format string %s"), sp); /* sp points at "%(" and ep points at the closing ")" */ at = parse_ref_filter_atom(sp + 2, ep); cp = ep + 1; @@ -875,12 +875,12 @@ static const char *strip_ref_components(const char *refname, const char *nr_arg) const char *start = refname; if (nr < 1 || *end != '\0') - die(":strip= requires a positive integer argument"); + die(_(":strip= requires a positive integer argument")); while (remaining) { switch (*start++) { case '\0': - die("ref '%s' does not have %ld components to :strip", + die(_("ref '%s' does not have %ld components to :strip"), refname, nr); case '/': remaining--; @@ -1043,7 +1043,7 @@ static void populate_value(struct ref_array_item *ref) else if (skip_prefix(formatp, "strip=", &arg)) refname = strip_ref_components(refname, arg); else - die("unknown %.*s format %s", + die(_("unknown %.*s format %s"), (int)(formatp - name), name, formatp); } @@ -1063,10 +1063,10 @@ static void populate_value(struct ref_array_item *ref) need_obj: buf = get_obj(ref->objectname, &obj, &size, &eaten); if (!buf) - die("missing object %s for %s", + die(_("missing object %s for %s"), sha1_to_hex(ref->objectname), ref->refname); if (!obj) - die("parse_object_buffer failed on %s for %s", + die(_("parse_object_buffer failed on %s for %s"), sha1_to_hex(ref->objectname), ref->refname); grab_values(ref->value, 0, obj, buf, size); @@ -1094,10 +1094,10 @@ static void populate_value(struct ref_array_item *ref) */ buf = get_obj(tagged, &obj, &size, &eaten); if (!buf) - die("missing object %s for %s", + die(_("missing object %s for %s"), sha1_to_hex(tagged), ref->refname); if (!obj) - die("parse_object_buffer failed on %s for %s", + die(_("parse_object_buffer failed on %s for %s"), sha1_to_hex(tagged), ref->refname); grab_values(ref->value, 1, obj, buf, size); if (!eaten) @@ -1370,12 +1370,12 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, unsigned int kind; if (flag & REF_BAD_NAME) { - warning("ignoring ref with broken name %s", refname); + warning(_("ignoring ref with broken name %s"), refname); return 0; } if (flag & REF_ISBROKEN) { - warning("ignoring broken ref %s", refname); + warning(_("ignoring broken ref %s"), refname); return 0; } diff --git a/run-command.c b/run-command.c index 863dad52f1..c72601056c 100644 --- a/run-command.c +++ b/run-command.c @@ -902,35 +902,18 @@ struct parallel_processes { struct strbuf buffered_output; /* of finished children */ }; -static int default_start_failure(struct child_process *cp, - struct strbuf *err, +static int default_start_failure(struct strbuf *err, void *pp_cb, void *pp_task_cb) { - int i; - - strbuf_addstr(err, "Starting a child failed:"); - for (i = 0; cp->argv[i]; i++) - strbuf_addf(err, " %s", cp->argv[i]); - return 0; } static int default_task_finished(int result, - struct child_process *cp, struct strbuf *err, void *pp_cb, void *pp_task_cb) { - int i; - - if (!result) - return 0; - - strbuf_addf(err, "A child failed with return code %d:", result); - for (i = 0; cp->argv[i]; i++) - strbuf_addf(err, " %s", cp->argv[i]); - return 0; } @@ -1048,8 +1031,7 @@ static int pp_start_one(struct parallel_processes *pp) pp->children[i].process.no_stdin = 1; if (start_command(&pp->children[i].process)) { - code = pp->start_failure(&pp->children[i].process, - &pp->children[i].err, + code = pp->start_failure(&pp->children[i].err, pp->data, &pp->children[i].data); strbuf_addbuf(&pp->buffered_output, &pp->children[i].err); @@ -1117,7 +1099,7 @@ static int pp_collect_finished(struct parallel_processes *pp) code = finish_command(&pp->children[i].process); - code = pp->task_finished(code, &pp->children[i].process, + code = pp->task_finished(code, &pp->children[i].err, pp->data, &pp->children[i].data); diff --git a/run-command.h b/run-command.h index 42917e8618..3d1e59e26e 100644 --- a/run-command.h +++ b/run-command.h @@ -159,8 +159,7 @@ typedef int (*get_next_task_fn)(struct child_process *cp, * To send a signal to other child processes for abortion, return * the negative signal number. */ -typedef int (*start_failure_fn)(struct child_process *cp, - struct strbuf *err, +typedef int (*start_failure_fn)(struct strbuf *err, void *pp_cb, void *pp_task_cb); @@ -179,7 +178,6 @@ typedef int (*start_failure_fn)(struct child_process *cp, * the negative signal number. */ typedef int (*task_finished_fn)(int result, - struct child_process *cp, struct strbuf *err, void *pp_cb, void *pp_task_cb); @@ -193,9 +191,8 @@ typedef int (*task_finished_fn)(int result, * (both stdout and stderr) is routed to stderr in a manner that output * from different tasks does not interleave. * - * If start_failure_fn or task_finished_fn are NULL, default handlers - * will be used. The default handlers will print an error message on - * error without issuing an emergency stop. + * start_failure_fn and task_finished_fn can be NULL to omit any + * special handling. */ int run_processes_parallel(int n, get_next_task_fn, diff --git a/sha1_file.c b/sha1_file.c index 02517009c1..d0f2aa029b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -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) @@ -2448,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; @@ -2461,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))); } diff --git a/submodule.c b/submodule.c index 24fb81ac62..62c4356c50 100644 --- a/submodule.c +++ b/submodule.c @@ -705,8 +705,7 @@ static int get_next_submodule(struct child_process *cp, return 0; } -static int fetch_start_failure(struct child_process *cp, - struct strbuf *err, +static int fetch_start_failure(struct strbuf *err, void *cb, void *task_cb) { struct submodule_parallel_fetch *spf = cb; @@ -716,8 +715,8 @@ static int fetch_start_failure(struct child_process *cp, return 0; } -static int fetch_finish(int retvalue, struct child_process *cp, - struct strbuf *err, void *cb, void *task_cb) +static int fetch_finish(int retvalue, struct strbuf *err, + void *cb, void *task_cb) { struct submodule_parallel_fetch *spf = cb; diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 7d15e6d44c..f667e7ce2f 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -64,6 +64,9 @@ LockFile accept.lock <IfModule !mod_mpm_prefork.c> LoadModule mpm_prefork_module modules/mod_mpm_prefork.so </IfModule> +<IfModule !mod_unixd.c> + LoadModule unixd_module modules/mod_unixd.so +</IfModule> </IfVersion> PassEnv GIT_VALGRIND diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 295aa5949a..a5b9e7a4c7 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -88,19 +88,17 @@ test_expect_success 'plain nested in bare through aliased command' ' ' test_expect_success 'No extra GIT_* on alias scripts' ' - ( - env | sed -ne "/^GIT_/s/=.*//p" && - echo GIT_PREFIX && # setup.c - echo GIT_TEXTDOMAINDIR # wrapper-for-bin.sh - ) | sort | uniq >expected && - cat <<-\EOF >script && - #!/bin/sh - env | sed -ne "/^GIT_/s/=.*//p" | sort >actual - exit 0 + write_script script <<-\EOF && + env | + sed -n \ + -e "/^GIT_PREFIX=/d" \ + -e "/^GIT_TEXTDOMAINDIR=/d" \ + -e "/^GIT_/s/=.*//p" | + sort EOF - chmod 755 script && + ./script >expected && git config alias.script \!./script && - ( mkdir sub && cd sub && git script ) && + ( mkdir sub && cd sub && git script >../actual ) && test_cmp expected actual ' diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh new file mode 100755 index 0000000000..a8a587abc3 --- /dev/null +++ b/t/t5313-pack-bounds-checks.sh @@ -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 diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 0c10c856a9..38321d19ef 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -679,10 +679,12 @@ test_expect_success 'fetching with auto-gc does not lock up' ' EOF git clone "file://$D" auto-gc && test_commit test2 && - cd auto-gc && - git config gc.autoPackLimit 1 && - GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 && - ! grep "Should I try again" fetch.out + ( + cd auto-gc && + git config gc.autoPackLimit 1 && + GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 && + ! grep "Should I try again" fetch.out + ) ' test_done diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 7e8c40b97b..1b75c91965 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -17,6 +17,12 @@ BEGIN { use Cwd; use File::Basename; +sub adjust_dirsep { + my $path = shift; + $path =~ s{\\}{/}g; + return $path; +} + BEGIN { use_ok('Git') } # set up @@ -33,7 +39,7 @@ is($r->config_int("test.int"), 2048, "config_int: integer"); is($r->config_int("test.nonexistent"), undef, "config_int: nonexistent"); ok($r->config_bool("test.booltrue"), "config_bool: true"); ok(!$r->config_bool("test.boolfalse"), "config_bool: false"); -is($r->config_path("test.path") =~ s/\\/\//gr, $r->config("test.pathexpanded"), +is(adjust_dirsep($r->config_path("test.path")), $r->config("test.pathexpanded"), "config_path: ~/foo expansion"); is_deeply([$r->config_path("test.pathmulti")], ["foo", "bar"], "config_path: multiple values"); diff --git a/test-run-command.c b/test-run-command.c index fbe0a27ef3..30a64a98dc 100644 --- a/test-run-command.c +++ b/test-run-command.c @@ -41,7 +41,6 @@ static int no_job(struct child_process *cp, } static int task_finished(int result, - struct child_process *cp, struct strbuf *err, void *pp_cb, void *pp_task_cb) @@ -234,7 +234,7 @@ static const char *apply_command(const char *command, const char *arg) cp.use_shell = 1; if (capture_command(&cp, &buf, 1024)) { - error("running trailer command '%s' failed", cmd.buf); + error(_("running trailer command '%s' failed"), cmd.buf); strbuf_release(&buf); result = xstrdup(""); } else { |