git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] status: read submodule process output before calling wait()

From
Jeff King <peff@peff.net>
Date
Mar 22, 2015, 08:07 UTC
Message-ID
<20150322080708.GA3456@peff.net>
In-Reply-To
<20150322074455.GA1303@peff.net>
On Sun, Mar 22, 2015 at 03:44:55AM -0400, Jeff King wrote:
Show 6 quoted lines
> The status code tries to read the output of "git submodule
> summary" over a pipe by waiting for the program to finish
> and then reading its output, like this:
> 
>   run_command(&sm_summary);
>   len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);

By the way, I spotted this code as bogus immediately upon seeing it (though certainly it helped to know there was a deadlock in the area, which had me thinking about such things). So I wondered if it could have been easy to catch in review, but its introduction was a little bit subtle.

The original run_command invocation came in ac8d5af (builtin-status: submodule summary support, 2008-04-12), which just let the sub-process dump its stdout to the same descriptor that the rest of the status output was going to. So the use of run_command there was fine. It was later, in 3ba7407 (submodule summary: ignore --for-status option, 2013-09-06), that we started post-processing the output and it became buggy. But that's harder to see in review.

> Besides being a violation of the run-command API (which
> makes no promises about the state of the struct after
> run_command returns),

This may be overly harsh of me. Certainly we make no guarantees (and things like the dynamic "args" and "env_array" are cleaned up automatically after finish_command returns), but I would not be surprised if there are other spots that treat "struct child_process" as transparent rather than as a black box.

It's really the run_command + pipe construct that is really the danger here. I wonder if we should do something like this:

diff --git a/run-command.c b/run-command.c
index 3afb124..78807de 100644
--- a/run-command.c
+++ b/run-command.c
@@ -557,7 +557,12 @@ int finish_command(struct child_process *cmd)
 
 int run_command(struct child_process *cmd)
 {
-	int code = start_command(cmd);
+	int code;
+
+	if (cmd->out < 0)
+		die("BUG: run_command with a pipe can cause deadlock");
+
+	code = start_command(cmd);
 	if (code)
 		return code;
 	return finish_command(cmd);

It seems to catch at least one other dubious construct.

-Peff
Previous: Jeff KingNext: Jeff King
Message 3 of 26 in “status hangs trying to get submodule summary”
  1. Wincent ColaiutaMar 22, 2015
  2. status: read submodule process output before calling wait()Jeff King, Mar 22, 2015
  3. Jeff KingMar 22, 2015
  4. 0/7 introduce strbuf_read_cmd to avoid deadlocksJeff King, Mar 22, 2015
  5. 1/7 wt-status: don't flush before running "submodule status"Jeff King, Mar 22, 2015
  6. 2/7 wt_status: fix signedness mismatch in strbuf_read callJeff King, Mar 22, 2015
  7. 3/7 strbuf: introduce strbuf_read_cmd helperJeff King, Mar 22, 2015
  8. Eric SunshineMar 22, 2015
  9. Junio C HamanoMar 22, 2015
  10. Junio C HamanoMar 22, 2015
  11. 0/7 introduce capture_command to avoid deadlocksJeff King, Mar 23, 2015
  12. 1/7 wt-status: don't flush before running "submodule status"Jeff King, Mar 23, 2015
  13. 2/7 wt_status: fix signedness mismatch in strbuf_read callJeff King, Mar 23, 2015
  14. 3/7 run-command: introduce capture_command helperJeff King, Mar 23, 2015
  15. 4/7 wt-status: use capture_commandJeff King, Mar 23, 2015
  16. 5/7 submodule: use capture_commandJeff King, Mar 23, 2015
  17. 6/7 trailer: use capture_commandJeff King, Mar 23, 2015
  18. 7/7 run-command: forbid using run_command with piped outputJeff King, Mar 23, 2015
  19. Junio C HamanoMar 23, 2015
  20. Jeff KingMar 22, 2015
  21. Junio C HamanoMar 22, 2015
  22. Jeff KingMar 22, 2015
  23. 4/7 wt-status: use strbuf_read_cmdJeff King, Mar 22, 2015
  24. 5/7 submodule: use strbuf_read_cmdJeff King, Mar 22, 2015
  25. 6/7 trailer: use strbuf_read_cmdJeff King, Mar 22, 2015
  26. 7/7 run-command: forbid using run_command with piped outputJeff King, Mar 22, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.