path: root/builtin/receive-pack.c
diff options
authorJeff King <>2013-04-19 21:24:29 (GMT)
committerJunio C Hamano <>2013-04-19 21:43:24 (GMT)
commit49ecfa13fe6fb9ccb7c4771126872515340c328b (patch)
tree6b4bf8187a81075b5facf3fbbf2c99d95b000acf /builtin/receive-pack.c
parent04a74b6cfa5ef4870263f84ac94a488d9f2ef14a (diff)
receive-pack: close sideband fd on early pack errors
Since commit a22e6f8 (receive-pack: send pack-processing stderr over sideband, 2012-09-21), receive-pack will start an async sideband thread to copy the stderr from our index-pack or unpack-objects child to the client. We hand the thread's input descriptor to unpack(), which puts it in the "err" member of the "struct child_process". After unpack() returns, we use finish_async() to reap the sideband thread. The thread is only ready to die when it gets EOF on its pipe, which is connected to the err descriptor. So we expect all of the write ends of that pipe to be closed as part of unpack(). Normally, this works fine. After start_command forks, it closes the parent copy of the descriptor. Then once the child exits (whether it was successful or not), that closes the only remaining writer. However, there is one code-path in unpack() that does not handle this. Before we decide which of unpack-objects or index-pack to use, we read the pack header ourselves to see how many objects it contains. If there is an error here, we exit without running either sub-command, the pipe descriptor remains open, and we are in a deadlock, waiting for the sideband thread to die (which is in turn waiting for us to close the pipe). We can fix this by making sure that unpack() always closes the pipe before returning. Signed-off-by: Jeff King <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'builtin/receive-pack.c')
1 files changed, 4 insertions, 1 deletions
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index ff781fe..ce42c0a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -807,8 +807,11 @@ static const char *unpack(int err_fd)
: 0);
hdr_err = parse_pack_header(&hdr);
- if (hdr_err)
+ if (hdr_err) {
+ if (err_fd > 0)
+ close(err_fd);
return hdr_err;
+ }
snprintf(hdr_arg, sizeof(hdr_arg),
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));