Skip to content

Commit bac9c06

Browse files
committed
Merge branch 'jk/git-connection-deadlock-fix' into maint-1.7.4
* jk/git-connection-deadlock-fix: test core.gitproxy configuration send-pack: avoid deadlock on git:// push with failed pack-objects connect: let callers know if connection is a socket connect: treat generic proxy processes like ssh processes Conflicts: connect.c
2 parents 34df9fe + c7730e6 commit bac9c06

File tree

4 files changed

+67
-14
lines changed

4 files changed

+67
-14
lines changed

builtin/send-pack.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ int send_pack(struct send_pack_args *args,
344344
ref->status = REF_STATUS_NONE;
345345
if (args->stateless_rpc)
346346
close(out);
347+
if (git_connection_is_socket(conn))
348+
shutdown(fd[0], SHUT_WR);
347349
if (use_sideband)
348350
finish_async(&demux);
349351
return -1;

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
946946
extern char *git_getpass(const char *prompt);
947947
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
948948
extern int finish_connect(struct child_process *conn);
949+
extern int git_connection_is_socket(struct child_process *conn);
949950
extern int path_match(const char *path, int nr, char **match);
950951
struct extra_have_objects {
951952
int nr, alloc;

connect.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -395,26 +395,28 @@ static int git_use_proxy(const char *host)
395395
return (git_proxy_command && *git_proxy_command);
396396
}
397397

398-
static void git_proxy_connect(int fd[2], char *host)
398+
static struct child_process *git_proxy_connect(int fd[2], char *host)
399399
{
400400
const char *port = STR(DEFAULT_GIT_PORT);
401-
const char *argv[4];
402-
struct child_process proxy;
401+
const char **argv;
402+
struct child_process *proxy;
403403

404404
get_host_and_port(&host, &port);
405405

406+
argv = xmalloc(sizeof(*argv) * 4);
406407
argv[0] = git_proxy_command;
407408
argv[1] = host;
408409
argv[2] = port;
409410
argv[3] = NULL;
410-
memset(&proxy, 0, sizeof(proxy));
411-
proxy.argv = argv;
412-
proxy.in = -1;
413-
proxy.out = -1;
414-
if (start_command(&proxy))
411+
proxy = xcalloc(1, sizeof(*proxy));
412+
proxy->argv = argv;
413+
proxy->in = -1;
414+
proxy->out = -1;
415+
if (start_command(proxy))
415416
die("cannot start proxy %s", argv[0]);
416-
fd[0] = proxy.out; /* read from proxy stdout */
417-
fd[1] = proxy.in; /* write to proxy stdin */
417+
fd[0] = proxy->out; /* read from proxy stdout */
418+
fd[1] = proxy->in; /* write to proxy stdin */
419+
return proxy;
418420
}
419421

420422
#define MAX_CMD_LEN 1024
@@ -455,7 +457,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
455457
char *host, *path;
456458
char *end;
457459
int c;
458-
struct child_process *conn;
460+
struct child_process *conn = &no_fork;
459461
enum protocol protocol = PROTO_LOCAL;
460462
int free_path = 0;
461463
char *port = NULL;
@@ -540,7 +542,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
540542
*/
541543
char *target_host = xstrdup(host);
542544
if (git_use_proxy(host))
543-
git_proxy_connect(fd, host);
545+
conn = git_proxy_connect(fd, host);
544546
else
545547
git_tcp_connect(fd, host, flags);
546548
/*
@@ -558,7 +560,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
558560
free(url);
559561
if (free_path)
560562
free(path);
561-
return &no_fork;
563+
return conn;
562564
}
563565

564566
conn = xcalloc(1, sizeof(*conn));
@@ -607,10 +609,15 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
607609
return conn;
608610
}
609611

612+
int git_connection_is_socket(struct child_process *conn)
613+
{
614+
return conn == &no_fork;
615+
}
616+
610617
int finish_connect(struct child_process *conn)
611618
{
612619
int code;
613-
if (!conn || conn == &no_fork)
620+
if (!conn || git_connection_is_socket(conn))
614621
return 0;
615622

616623
code = finish_command(conn);

t/t5532-fetch-proxy.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/sh
2+
3+
test_description='fetching via git:// using core.gitproxy'
4+
. ./test-lib.sh
5+
6+
test_expect_success 'setup remote repo' '
7+
git init remote &&
8+
(cd remote &&
9+
echo content >file &&
10+
git add file &&
11+
git commit -m one
12+
)
13+
'
14+
15+
cat >proxy <<'EOF'
16+
#!/bin/sh
17+
echo >&2 "proxying for $*"
18+
cmd=`perl -e '
19+
read(STDIN, $buf, 4);
20+
my $n = hex($buf) - 4;
21+
read(STDIN, $buf, $n);
22+
my ($cmd, $other) = split /\0/, $buf;
23+
# drop absolute-path on repo name
24+
$cmd =~ s{ /}{ };
25+
print $cmd;
26+
'`
27+
echo >&2 "Running '$cmd'"
28+
exec $cmd
29+
EOF
30+
chmod +x proxy
31+
test_expect_success 'setup local repo' '
32+
git remote add fake git://example.com/remote &&
33+
git config core.gitproxy ./proxy
34+
'
35+
36+
test_expect_success 'fetch through proxy works' '
37+
git fetch fake &&
38+
echo one >expect &&
39+
git log -1 --format=%s FETCH_HEAD >actual &&
40+
test_cmp expect actual
41+
'
42+
43+
test_done

0 commit comments

Comments
 (0)