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

[PATCH] tempfile: avoid "ferror | fclose" trick

From
Jeff King <peff@peff.net>
Date
Feb 16, 2017, 21:31 UTC
Message-ID
<20170216213140.xqw7gzjimhvg7tcm@sigill.intra.peff.net>
In-Reply-To
<20170216164359.k2ab7laqqvusfsm2@sigill.intra.peff.net>
On Thu, Feb 16, 2017 at 11:43:59AM -0500, Jeff King wrote:
Show 14 quoted lines
> On Thu, Feb 16, 2017 at 11:10:18AM +0100, Andreas Schwab wrote:
> 
> > >> 	int xfclose(FILE *fp)
> > >> 	{
> > >> 		return ferror(fp) | fclose(fp);
> > >> 	}
> > >
> > > Yes, that's exactly what I had in mind (might be worth calling out the
> > > bitwise-OR, though, just to make it clear it's not a typo).
> > 
> > Since the order of evaluation is unspecified, it would be better to
> > force sequencing ferror before fclose.
> 
> Good point. Arguably the call in tempfile.c is buggy.
Here's a fix.

I think close_tempfile() suffers from the same errno problem discussed earlier in this thread (i.e., that after calling it, you may get an error return with a random, unrelated errno value if ferror() failed but fclose() did not).

-- >8 --
Subject: [PATCH] tempfile: avoid "ferror | fclose" trick

The current code wants to record an error condition from either ferror() or fclose(), but makes sure that we always call both functions. So it can't use logical-OR "||", which would short-circuit when ferror() is true. Instead, it uses bitwise-OR "|" to evaluate both functions and set one or more bits in the "err" flag if they reported a failure.

Unlike logical-OR, though, bitwise-OR does not introduce a sequence point, and the order of evaluation for its operands is unspecified. So a compiler would be free to generate code which calls fclose() first, and then ferror() on the now-freed filehandle.

There's no indication that this has happened in practice, but let's write it out in a way that follows the standard.

Noticed-by: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Jeff King <peff@peff.net>
---
 tempfile.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/tempfile.c b/tempfile.c
index 2990c9242..ffcc27237 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -247,12 +247,8 @@ int close_tempfile(struct tempfile *tempfile)
 	tempfile->fd = -1;
 	if (fp) {
 		tempfile->fp = NULL;
-
-		/*
-		 * Note: no short-circuiting here; we want to fclose()
-		 * in any case!
-		 */
-		err = ferror(fp) | fclose(fp);
+		err = ferror(fp);
+		err |= fclose(fp);
 	} else {
 		err = close(fd);
 	}
-- 
2.12.0.rc1.559.gd292418bf
Previous: Jeff KingNext: Michael Haggerty
Message 11 of 24 in “Confusing git messages when disk is full.”
  1. Jáchym BarvínekFeb 12, 2017
  2. Jeff KingFeb 15, 2017
  3. Junio C HamanoFeb 15, 2017
  4. Jeff KingFeb 15, 2017
  5. Junio C HamanoFeb 15, 2017
  6. Jeff KingFeb 15, 2017
  7. Junio C HamanoFeb 15, 2017
  8. Jeff KingFeb 15, 2017
  9. Andreas SchwabFeb 16, 2017
  10. Jeff KingFeb 16, 2017
  11. tempfile: avoid "ferror | fclose" trickJeff King, Feb 16, 2017
  12. Michael HaggertyFeb 17, 2017
  13. Jeff KingFeb 17, 2017
  14. Michael HaggertyFeb 17, 2017
  15. Jeff KingFeb 17, 2017
  16. Jeff KingFeb 17, 2017
  17. Junio C HamanoFeb 17, 2017
  18. Jeff KingFeb 17, 2017
  19. Junio C HamanoFeb 17, 2017
  20. Jeff KingFeb 17, 2017
  21. Junio C HamanoFeb 17, 2017
  22. Jeff KingFeb 17, 2017
  23. Junio C HamanoFeb 17, 2017
  24. Jeff KingFeb 17, 2017

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.