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

Re: [PATCH v2 2/4] builtin/archive: close file descriptor on dup2() failure

From
Jeff King <peff@peff.net>
Date
Jul 22, 2025, 08:24 UTC
Message-ID
<20250722082451.GB862006@coredump.intra.peff.net>
In-Reply-To
<20250722081219.1086866-3-lhywkd22@gmail.com>
On Tue, Jul 22, 2025 at 08:12:17AM +0000, Hoyoung Lee wrote:
> In create_output_file(), the file descriptor returned by xopen()
> was not closed if dup2() failed. This leads to a potential resource
> leak. Ensure the file descriptor is closed regardless of whether
> dup2() succeeds or fails.

The other patches in this series made sense to me, but I don't think this one does. It is not really a "leak" in the sense that output_fd is still on the stack when we exit (via the die_errno() call).

That may sound pedantic, but we have run into the same question with memory leaks. If we are not unwinding the stack, then we can never fully clean up the program state. E.g., with:

  void foo(void)
  {
	int fd = open(...);
	if (bar() < 0)
		die(...);
  }

it is tempting to think that you should close(fd) to clean up your state. But now imagine that bar(), instead of returning an error, itself exits the program, like this:

  void bar(void)
  {
	if (baz() < 0)
		die(...);
  }
It _can't_ close "fd" because it doesn't even know about it!

So when we consider whether something is leaking, I think it only makes sense in terms of unwinding the stack. And likewise any automated tools we use should consider that.

Show 12 quoted lines
> diff --git a/builtin/archive.c b/builtin/archive.c
> index 13ea7308c8..c919a39f90 100644
> --- a/builtin/archive.c
> +++ b/builtin/archive.c
> @@ -14,6 +14,7 @@ static void create_output_file(const char *output_file)
>  	int output_fd = xopen(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
>  	if (output_fd != 1) {
>  		if (dup2(output_fd, 1) < 0)
> +			close(output_fd);
>  			die_errno(_("could not redirect output"));
>  		else
>  			close(output_fd);

So I don't think this patch makes sense, but also...does this even compile? You did not add braces around the conditional block, so we'll call close() on failure but we won't call die_errno() anymore. And the else is no longer coupled to the if (because of the unrelated die statement in between), which should cause the compiler to barf.

-Peff
Previous: Hoyoung LeeNext: Hoyoung Lee
Message 4 of 12 in “Fix resource leaks in various helpers and builtin commands”
  1. 0/4 Fix resource leaks in various helpers and builtin commandsHoyoung Lee, Jul 22, 2025
  2. 1/4 t/helper/test-truncate: close file descriptor after truncationHoyoung Lee, Jul 22, 2025
  3. 2/4 builtin/archive: close file descriptor on dup2() failureHoyoung Lee, Jul 22, 2025
  4. Jeff KingJul 22, 2025
  5. 3/4 t/helper/test-delta: close fd if fstat() fails after open()Hoyoung Lee, Jul 22, 2025
  6. Eric SunshineJul 22, 2025
  7. Jeff KingJul 22, 2025
  8. 4/4 t/helper/test-delta: close fd if fstat() fails after second open()Hoyoung Lee, Jul 22, 2025
  9. Jeff KingJul 22, 2025
  10. Jeff KingJul 22, 2025
  11. Junio C HamanoJul 22, 2025
  12. Jeff KingJul 22, 2025

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.