Merge branch 'js/realpath-pathdup-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 16 Mar 2017 20:56:43 +0000 (13:56 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Mar 2017 20:57:00 +0000 (13:57 -0700)
Git v2.12 was shipped with an embarrassing breakage where various
operations that verify paths given from the user stopped dying when
seeing an issue, and instead later triggering segfault.
... and then to down to 'maint'.

* js/realpath-pathdup-fix:
real_pathdup(): fix callsites that wanted it to die on error
t1501: demonstrate NULL pointer access with invalid GIT_WORK_TREE

13 files changed:
.travis.yml
bisect.c
ci/run-linux32-build.sh [new file with mode: 0755]
config.mak.uname
git-add--interactive.perl
http.c
line-log.c
progress.c
t/lib-httpd/apache.conf
t/t3701-add-interactive.sh
t/t4211-line-log.sh
t/t5550-http-fetch-dumb.sh
transport.c
index 9c63c8c3f6807841df13161f76d476deca0d94fd..591cc57b80aa415be9c20b3c0dc746d792e68071 100644 (file)
@@ -39,6 +39,27 @@ env:
 
 matrix:
   include:
+    - env: Linux32
+      os: linux
+      services:
+        - docker
+      before_install:
+        - docker pull daald/ubuntu32:xenial
+      before_script:
+      script:
+        - >
+          docker run
+          --interactive
+          --env DEFAULT_TEST_TARGET
+          --env GIT_PROVE_OPTS
+          --env GIT_TEST_OPTS
+          --env GIT_TEST_CLONE_2GB
+          --volume "${PWD}:/usr/src/git"
+          daald/ubuntu32:xenial
+          /usr/src/git/ci/run-linux32-build.sh $(id -u $USER)
+        # Use the following command to debug the docker build locally:
+        # $ docker run -itv "${PWD}:/usr/src/git" --entrypoint /bin/bash daald/ubuntu32:xenial
+        # root@container:/# /usr/src/git/ci/run-linux32-build.sh
     - env: Documentation
       os: linux
       compiler: clang
index 8e63c40d274d7693b0c41e702cbe9ed03b1d12ae..30808cadf7613d73cae2e4caaedd922ba9a48ca0 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -940,7 +940,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
        struct commit_list *tried;
        int reaches = 0, all = 0, nr, steps;
        const unsigned char *bisect_rev;
-       char steps_msg[32];
+       char *steps_msg;
 
        read_bisect_terms(&term_bad, &term_good);
        if (read_bisect_refs())
@@ -990,14 +990,15 @@ int bisect_next_all(const char *prefix, int no_checkout)
 
        nr = all - reaches - 1;
        steps = estimate_bisect_steps(all);
-       xsnprintf(steps_msg, sizeof(steps_msg),
-                 Q_("(roughly %d step)", "(roughly %d steps)", steps),
-                 steps);
+
+       steps_msg = xstrfmt(Q_("(roughly %d step)", "(roughly %d steps)",
+                 steps), steps);
        /* TRANSLATORS: the last %s will be replaced with
           "(roughly %d steps)" translation */
        printf(Q_("Bisecting: %d revision left to test after this %s\n",
                  "Bisecting: %d revisions left to test after this %s\n",
                  nr), nr, steps_msg);
+       free(steps_msg);
 
        return bisect_checkout(bisect_rev, no_checkout);
 }
diff --git a/ci/run-linux32-build.sh b/ci/run-linux32-build.sh
new file mode 100755 (executable)
index 0000000..e30fb2c
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Build and test Git in a 32-bit environment
+#
+# Usage:
+#   run-linux32-build.sh [host-user-id]
+#
+
+# Update packages to the latest available versions
+linux32 --32bit i386 sh -c '
+    apt update >/dev/null &&
+    apt install -y build-essential libcurl4-openssl-dev libssl-dev \
+       libexpat-dev gettext python >/dev/null
+' &&
+
+# If this script runs inside a docker container, then all commands are
+# usually executed as root. Consequently, the host user might not be
+# able to access the test output files.
+# If a host user id is given, then create a user "ci" with the host user
+# id to make everything accessible to the host user.
+HOST_UID=$1 &&
+CI_USER=$USER &&
+test -z $HOST_UID || (CI_USER="ci" && useradd -u $HOST_UID $CI_USER) &&
+
+# Build and test
+linux32 --32bit i386 su -m -l $CI_USER -c '
+    cd /usr/src/git &&
+    make --jobs=2 &&
+    make --quiet test
+'
index 447f36ac2e31dd4d11e90f326b114a78fdba8df0..a07936da8b24f639059d1f024d3cb888068e0faf 100644 (file)
@@ -515,7 +515,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
        NO_PYTHON = YesPlease
-       BLK_SHA1 = YesPlease
        ETAGS_TARGET = ETAGS
        NO_INET_PTON = YesPlease
        NO_INET_NTOP = YesPlease
index 982593c89e2f253c2fa4d626c0c00fde7935aead..f5c816e273318709e90a9f5e9a47143a3842f8e3 100755 (executable)
@@ -92,7 +92,7 @@ sub colored {
 }
 
 # command line options
-my $cmd;
+my $patch_mode_only;
 my $patch_mode;
 my $patch_mode_revision;
 
@@ -1299,7 +1299,7 @@ sub patch_update_cmd {
                }
                return 0;
        }
-       if ($patch_mode) {
+       if ($patch_mode_only) {
                @them = @mods;
        }
        else {
@@ -1721,7 +1721,7 @@ sub process_args {
                die sprintf(__("invalid argument %s, expecting --"),
                               $arg) unless $arg eq "--";
                %patch_mode_flavour = %{$patch_modes{$patch_mode}};
-               $cmd = 1;
+               $patch_mode_only = 1;
        }
        elsif ($arg ne "--") {
                die sprintf(__("invalid argument %s, expecting --"), $arg);
@@ -1758,7 +1758,7 @@ sub main_loop {
 
 process_args();
 refresh();
-if ($cmd) {
+if ($patch_mode_only) {
        patch_update_cmd();
 }
 else {
diff --git a/http.c b/http.c
index 90a1c0f1131c4a5fcbc50d6cc81c1be9cef3cd71..96d84bbed3f66153cc3d817f2b342dc5d1600574 100644 (file)
--- a/http.c
+++ b/http.c
@@ -109,7 +109,7 @@ static int curl_save_cookies;
 struct credential http_auth = CREDENTIAL_INIT;
 static int http_proactive_auth;
 static const char *user_agent;
-static int curl_empty_auth;
+static int curl_empty_auth = -1;
 
 enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
 
@@ -125,6 +125,14 @@ static struct credential cert_auth = CREDENTIAL_INIT;
 static int ssl_cert_password_required;
 #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
 static unsigned long http_auth_methods = CURLAUTH_ANY;
+static int http_auth_methods_restricted;
+/* Modes for which empty_auth cannot actually help us. */
+static unsigned long empty_auth_useless =
+       CURLAUTH_BASIC
+#ifdef CURLAUTH_DIGEST_IE
+       | CURLAUTH_DIGEST_IE
+#endif
+       | CURLAUTH_DIGEST;
 #endif
 
 static struct curl_slist *pragma_header;
@@ -333,7 +341,10 @@ static int http_options(const char *var, const char *value, void *cb)
                return git_config_string(&user_agent, var, value);
 
        if (!strcmp("http.emptyauth", var)) {
-               curl_empty_auth = git_config_bool(var, value);
+               if (value && !strcmp("auto", value))
+                       curl_empty_auth = -1;
+               else
+                       curl_empty_auth = git_config_bool(var, value);
                return 0;
        }
 
@@ -382,10 +393,37 @@ static int http_options(const char *var, const char *value, void *cb)
        return git_default_config(var, value, cb);
 }
 
+static int curl_empty_auth_enabled(void)
+{
+       if (curl_empty_auth >= 0)
+               return curl_empty_auth;
+
+#ifndef LIBCURL_CAN_HANDLE_AUTH_ANY
+       /*
+        * Our libcurl is too old to do AUTH_ANY in the first place;
+        * just default to turning the feature off.
+        */
+#else
+       /*
+        * In the automatic case, kick in the empty-auth
+        * hack as long as we would potentially try some
+        * method more exotic than "Basic" or "Digest".
+        *
+        * But only do this when this is our second or
+        * subsequent request, as by then we know what
+        * methods are available.
+        */
+       if (http_auth_methods_restricted &&
+           (http_auth_methods & ~empty_auth_useless))
+               return 1;
+#endif
+       return 0;
+}
+
 static void init_curl_http_auth(CURL *result)
 {
        if (!http_auth.username || !*http_auth.username) {
-               if (curl_empty_auth)
+               if (curl_empty_auth_enabled())
                        curl_easy_setopt(result, CURLOPT_USERPWD, ":");
                return;
        }
@@ -1079,7 +1117,7 @@ struct active_request_slot *get_active_slot(void)
 #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
        curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
 #endif
-       if (http_auth.password || curl_empty_auth)
+       if (http_auth.password || curl_empty_auth_enabled())
                init_curl_http_auth(slot->curl);
 
        return slot;
@@ -1347,6 +1385,10 @@ static int handle_curl_result(struct slot_results *results)
                } else {
 #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
                        http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
+                       if (results->auth_avail) {
+                               http_auth_methods &= results->auth_avail;
+                               http_auth_methods_restricted = 1;
+                       }
 #endif
                        return HTTP_REAUTH;
                }
@@ -1727,6 +1769,9 @@ static int http_request_reauth(const char *url,
 {
        int ret = http_request(url, result, target, options);
 
+       if (ret != HTTP_OK && ret != HTTP_REAUTH)
+               return ret;
+
        if (options && options->effective_url && options->base_url) {
                if (update_url_from_redirect(options->base_url,
                                             url, options->effective_url)) {
index 65f3558b3be695ce5259df9a2da4f28e95b35b71..a23b910471b6c3195e18aad3cbdf225ae200cca0 100644 (file)
@@ -43,9 +43,10 @@ void range_set_release(struct range_set *rs)
 static void range_set_copy(struct range_set *dst, struct range_set *src)
 {
        range_set_init(dst, src->nr);
-       memcpy(dst->ranges, src->ranges, src->nr*sizeof(struct range_set));
+       COPY_ARRAY(dst->ranges, src->ranges, src->nr);
        dst->nr = src->nr;
 }
+
 static void range_set_move(struct range_set *dst, struct range_set *src)
 {
        range_set_release(dst);
@@ -144,7 +145,7 @@ void sort_and_merge_range_set(struct range_set *rs)
 static void range_set_union(struct range_set *out,
                             struct range_set *a, struct range_set *b)
 {
-       int i = 0, j = 0, o = 0;
+       int i = 0, j = 0;
        struct range *ra = a->ranges;
        struct range *rb = b->ranges;
        /* cannot make an alias of out->ranges: it may change during grow */
@@ -167,16 +168,15 @@ static void range_set_union(struct range_set *out,
                        new = &rb[j++];
                if (new->start == new->end)
                        ; /* empty range */
-               else if (!o || out->ranges[o-1].end < new->start) {
+               else if (!out->nr || out->ranges[out->nr-1].end < new->start) {
                        range_set_grow(out, 1);
-                       out->ranges[o].start = new->start;
-                       out->ranges[o].end = new->end;
-                       o++;
-               } else if (out->ranges[o-1].end < new->end) {
-                       out->ranges[o-1].end = new->end;
+                       out->ranges[out->nr].start = new->start;
+                       out->ranges[out->nr].end = new->end;
+                       out->nr++;
+               } else if (out->ranges[out->nr-1].end < new->end) {
+                       out->ranges[out->nr-1].end = new->end;
                }
        }
-       out->nr = o;
 }
 
 /*
index 76a88c573f7895bbf388ab4335faa1b86c3975d3..29378caa05336efe15cdf2a9473ca6cbe2bcfa14 100644 (file)
@@ -243,21 +243,18 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
        *p_progress = NULL;
        if (progress->last_value != -1) {
                /* Force the last update */
-               char buf[128], *bufp;
-               size_t len = strlen(msg) + 5;
+               char *buf;
                struct throughput *tp = progress->throughput;
 
-               bufp = (len < sizeof(buf)) ? buf : xmallocz(len);
                if (tp) {
                        unsigned int rate = !tp->avg_misecs ? 0 :
                                        tp->avg_bytes / tp->avg_misecs;
                        throughput_string(&tp->display, tp->curr_total, rate);
                }
                progress_update = 1;
-               xsnprintf(bufp, len + 1, ", %s.\n", msg);
-               display(progress, progress->last_value, bufp);
-               if (buf != bufp)
-                       free(bufp);
+               buf = xstrfmt(", %s.\n", msg);
+               display(progress, progress->last_value, buf);
+               free(buf);
        }
        clear_progress_signal();
        if (progress->throughput)
index 69174c6e3110d5e214c048aceccf07232b813ce7..0642ae7e6ef0fbbd9e7eacdebd061d258c8b4222 100644 (file)
@@ -133,6 +133,15 @@ RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
 RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302]
 RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302]
 
+# redir-to/502/x?y -> really-redir-to?path=502/x&qs=y which returns 502
+# redir-to/x?y -> really-redir-to?path=x&qs=y -> x?y
+RewriteCond %{QUERY_STRING} ^(.*)$
+RewriteRule ^/redir-to/(.*)$ /really-redir-to?path=$1&qs=%1 [R=302]
+RewriteCond %{QUERY_STRING} ^path=502/(.*)&qs=(.*)$
+RewriteRule ^/really-redir-to$ - [R=502,L]
+RewriteCond %{QUERY_STRING} ^path=(.*)&qs=(.*)$
+RewriteRule ^/really-redir-to$ /%1?%2 [R=302]
+
 # The first rule issues a client-side redirect to something
 # that _doesn't_ look like a git repo. The second rule is a
 # server-side rewrite, so that it turns out the odd-looking
index 5ffe78e920c4aa292a6c16e2aa8078ede4ab065c..aaa258daa376ab6d18d71a04a517840e1b55d094 100755 (executable)
@@ -394,4 +394,22 @@ test_expect_success 'diffs can be colorized' '
        grep "$(printf "\\033")" output
 '
 
+test_expect_success 'patch-mode via -i prompts for files' '
+       git reset --hard &&
+
+       echo one >file &&
+       echo two >test &&
+       git add -i <<-\EOF &&
+       patch
+       test
+
+       y
+       quit
+       EOF
+
+       echo test >expect &&
+       git diff --cached --name-only >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 9d87777b5994910dda971b57fd67b733ee9b5398..d0377fae5c832bcd4df37f3bc2ab4a8708f70251 100755 (executable)
@@ -106,4 +106,14 @@ test_expect_success '-L with --output' '
        test_line_count = 70 log
 '
 
+test_expect_success 'range_set_union' '
+       test_seq 500 > c.c &&
+       git add c.c &&
+       git commit -m "many lines" &&
+       test_seq 1000 > c.c &&
+       git add c.c &&
+       git commit -m "modify many lines" &&
+       git log $(for x in $(test_seq 200); do echo -L $((2*x)),+1:c.c; done)
+'
+
 test_done
index aeb3a63f7c07caa3f53ff4da5096dc51493dd4e3..2d3b1e9f937219b84069d9d0b1ce17129e87d110 100755 (executable)
@@ -378,5 +378,14 @@ test_expect_success 'http-alternates triggers not-from-user protocol check' '
                clone $HTTPD_URL/dumb/evil.git evil-user
 '
 
+test_expect_success 'can redirect through non-"info/refs?service=git-upload-pack" URL' '
+       git clone "$HTTPD_URL/redir-to/dumb/repo.git"
+'
+
+test_expect_success 'print HTTP error when any intermediate redirect throws error' '
+       test_must_fail git clone "$HTTPD_URL/redir-to/502" 2> stderr &&
+       test_i18ngrep "unable to access.*/redir-to/502" stderr
+'
+
 stop_httpd
 test_done
index d72e0894840fc384d67339b549a9a6bce7ba03ec..b6c5652d6cb5eb9b0c1d3ed80ad5034ce7f9b5dc 100644 (file)
@@ -1221,7 +1221,7 @@ static int refs_from_alternate_cb(struct alternate_object_database *e,
        const struct ref *extra;
        struct alternate_refs_data *cb = data;
 
-       other = real_pathdup(e->path);
+       other = real_pathdup(e->path, 1);
        len = strlen(other);
 
        while (other[len-1] == '/')