Merge branch 'jk/push-deadlock-regression-fix'
authorJunio C Hamano <gitster@pobox.com>
Tue, 14 Mar 2017 22:23:20 +0000 (15:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 14 Mar 2017 22:23:20 +0000 (15:23 -0700)
"git push" had a handful of codepaths that could lead to a deadlock
when unexpected error happened, which has been fixed.

* jk/push-deadlock-regression-fix:
send-pack: report signal death of pack-objects
send-pack: read "unpack" status even on pack-objects failure
send-pack: improve unpack-status error messages
send-pack: use skip_prefix for parsing unpack status
send-pack: extract parsing of "unpack" response
receive-pack: fix deadlock when we cannot create tmpdir

1  2 
builtin/receive-pack.c
diff --combined builtin/receive-pack.c
index 9ed8fbbfad71daf45381dbccf0aebe4a5b9af03d,eb6d25a14951426c1a0ad00dafe3b228739391cb..f2c6953a39f6c1369725494cfc36b108cdb097a6
@@@ -21,7 -21,6 +21,7 @@@
  #include "sigchain.h"
  #include "fsck.h"
  #include "tmp-objdir.h"
 +#include "oidset.h"
  
  static const char * const receive_pack_usage[] = {
        N_("git receive-pack <git-dir>"),
@@@ -251,9 -250,8 +251,9 @@@ static void show_ref(const char *path, 
  }
  
  static int show_ref_cb(const char *path_full, const struct object_id *oid,
 -                     int flag, void *unused)
 +                     int flag, void *data)
  {
 +      struct oidset *seen = data;
        const char *path = strip_namespace(path_full);
  
        if (ref_is_hidden(path, path_full))
        /*
         * Advertise refs outside our current namespace as ".have"
         * refs, so that the client can use them to minimize data
 -       * transfer but will otherwise ignore them. This happens to
 -       * cover ".have" that are thrown in by add_one_alternate_ref()
 -       * to mark histories that are complete in our alternates as
 -       * well.
 +       * transfer but will otherwise ignore them.
         */
 -      if (!path)
 +      if (!path) {
 +              if (oidset_insert(seen, oid))
 +                      return 0;
                path = ".have";
 +      } else {
 +              oidset_insert(seen, oid);
 +      }
        show_ref(path, oid->hash);
        return 0;
  }
  
 -static int show_one_alternate_sha1(const unsigned char sha1[20], void *unused)
 +static void show_one_alternate_ref(const char *refname,
 +                                 const struct object_id *oid,
 +                                 void *data)
  {
 -      show_ref(".have", sha1);
 -      return 0;
 -}
 +      struct oidset *seen = data;
  
 -static void collect_one_alternate_ref(const struct ref *ref, void *data)
 -{
 -      struct sha1_array *sa = data;
 -      sha1_array_append(sa, ref->old_oid.hash);
 +      if (oidset_insert(seen, oid))
 +              return;
 +
 +      show_ref(".have", oid->hash);
  }
  
  static void write_head_info(void)
  {
 -      struct sha1_array sa = SHA1_ARRAY_INIT;
 +      static struct oidset seen = OIDSET_INIT;
  
 -      for_each_alternate_ref(collect_one_alternate_ref, &sa);
 -      sha1_array_for_each_unique(&sa, show_one_alternate_sha1, NULL);
 -      sha1_array_clear(&sa);
 -      for_each_ref(show_ref_cb, NULL);
 +      for_each_ref(show_ref_cb, &seen);
 +      for_each_alternate_ref(show_one_alternate_ref, &seen);
 +      oidset_clear(&seen);
        if (!sent_capabilities)
                show_ref("capabilities^{}", null_sha1);
  
@@@ -798,8 -795,8 +798,8 @@@ static char *refuse_unconfigured_deny_m
           "with what you pushed, and will require 'git reset --hard' to match\n"
           "the work tree to HEAD.\n"
           "\n"
 -         "You can set 'receive.denyCurrentBranch' configuration variable to\n"
 -         "'ignore' or 'warn' in the remote repository to allow pushing into\n"
 +         "You can set the 'receive.denyCurrentBranch' configuration variable\n"
 +         "to 'ignore' or 'warn' in the remote repository to allow pushing into\n"
           "its current branch; however, this is not recommended unless you\n"
           "arranged to update its work tree to match what you pushed in some\n"
           "other way.\n"
@@@ -1667,8 -1664,11 +1667,11 @@@ static const char *unpack(int err_fd, s
        }
  
        tmp_objdir = tmp_objdir_create();
-       if (!tmp_objdir)
+       if (!tmp_objdir) {
+               if (err_fd > 0)
+                       close(err_fd);
                return "unable to create temporary object directory";
+       }
        child.env = tmp_objdir_env(tmp_objdir);
  
        /*
@@@ -1945,7 -1945,8 +1948,7 @@@ int cmd_receive_pack(int argc, const ch
                run_receive_hook(commands, "post-receive", 1,
                                 &push_options);
                run_update_post_hook(commands);
 -              if (push_options.nr)
 -                      string_list_clear(&push_options, 0);
 +              string_list_clear(&push_options, 0);
                if (auto_gc) {
                        const char *argv_gc_auto[] = {
                                "gc", "--auto", "--quiet", NULL,