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

Re: [PATCH] mem-pool: use st_add() in mem_pool_strvfmt()

From
Jeff King <peff@peff.net>
Date
Apr 3, 2024, 20:48 UTC
Message-ID
<20240403204836.GC1949464@coredump.intra.peff.net>
In-Reply-To
<b48fd3ee-2975-481f-aa0e-8ec4d07ea705@web.de>
On Wed, Apr 03, 2024 at 12:01:13PM +0200, René Scharfe wrote:
Show 16 quoted lines
> > For mksnpath(), though, I
> > suspect that trying to format a very long name could result in the
> > output being full of uninitialized bytes.
> >
> > It only has one caller, which creates "foo~1" when we got EEXIST from
> > "foo". So I doubt you can get up to too much mischief with it. But it
> > could easily be replaced by mkpathdup() (or even a reusable strbuf
> > outside the loop if you really wanted to hyper-optimize)
> >
> > And then we could get rid of mksnpath() entirely, and its horrible
> > bad_path failure mode.
> 
> mkpath() would be perfect but unusable in multiple threads.  Cleaning
> up after mkpathdup() is a bit iffy in that caller.  strbuf would be a
> bit much in that error path, I think, and you might have to export or
> reimplement strbuf_cleanup_path().

Yeah, I'd prefer not to go to mkpath(), even though that's the simplest thing, just because we should be reducing the subtle non-reentrant parts of the code over time. I don't think the cleanup handling for mkpathdup() is too bad:

diff --git a/apply.c b/apply.c
index 432837a674..15dfe607ff 100644
--- a/apply.c
+++ b/apply.c
@@ -4502,20 +4502,25 @@ static int create_one_file(struct apply_state *state,
 		unsigned int nr = getpid();
 
 		for (;;) {
-			char newpath[PATH_MAX];
-			mksnpath(newpath, sizeof(newpath), "%s~%u", path, nr);
+			char *newpath = mkpathdup("%s~%u", path, nr);
 			res = try_create_file(state, newpath, mode, buf, size);
-			if (res < 0)
+			if (res < 0) {
+				free(newpath);
 				return -1;
+			}
 			if (!res) {
-				if (!rename(newpath, path))
+				if (!rename(newpath, path)) {
+					free(newpath);
 					return 0;
+				}
 				unlink_or_warn(newpath);
+				free(newpath);
 				break;
 			}
 			if (errno != EEXIST)
 				break;
 			++nr;
+			free(newpath);
 		}
 	}
 	return error_errno(_("unable to write file '%s' mode %o"),

It even gets a little easier if you hoist it to a strbuf outside the
loop, as you don't need to free on each loop iteration. That seems worth
it to me to get rid of a function that IMHO is mis-designed (it is
really only useful if you assume paths are bounded by PATH_MAX, which we
know isn't always true).

> > diff --git a/usage.c b/usage.c
> > index 09f0ed509b..5baab98fa3 100644
> > --- a/usage.c
> > +++ b/usage.c
> > @@ -19,8 +19,10 @@ static void vreportf(const char *prefix, const char *err, va_list params)
> >  	}
> >  	memcpy(msg, prefix, prefix_len);
> >  	p = msg + prefix_len;
> > -	if (vsnprintf(p, pend - p, err, params) < 0)
> > +	if (vsnprintf(p, pend - p, err, params) < 0) {
> > +		if (snprintf(p, pend - p, "could not format error: %s", err) < 0)
> >  		*p = '\0'; /* vsnprintf() failed, clip at prefix */
> > +	}
> >
> >  	for (; p != pend - 1 && *p; p++) {
> >  		if (iscntrl(*p) && *p != '\t' && *p != '\n')
> >
> > Though most of the rest of the function is not that useful (it is mostly
> > removing unreadable chars, and hopefully we do not have any of those in
> > our format strings!).
> 
> For warnings and usage messages this would keep the prefix and not
> die.  This would look a bit strange, no?
> 
> 	usage: could not format error: TERRIBLE MESSAGE!

Sure, but I think any solution here is going to look strange. Keep in
mind that we're trying to improve the case where we print _nothing_
useful at all. If you do see this on a non-fatal message, the subsequent
messages may be informative. E.g.:

  error: could not format error: unable to open loose object %s
  fatal: bad object HEAD~12

is probably better than just exiting after the first.

> Yes, showing errno doesn't add that much value.  Except in this case it
> shows that there's something going on that I don't understand.  Dare I
> dig deeper?  Probably not..

Well, let us know if you do. ;)

-Peff
Previous: René ScharfeNext: Jeff King
Message 6 of 9 in “mem-pool: use st_add() in mem_pool_strvfmt()”
  1. mem-pool: use st_add() in mem_pool_strvfmt()René Scharfe, Mar 31, 2024
  2. Jeff KingApr 1, 2024
  3. René ScharfeApr 2, 2024
  4. Jeff KingApr 3, 2024
  5. René ScharfeApr 3, 2024
  6. Jeff KingApr 3, 2024
  7. Jeff KingApr 3, 2024
  8. René ScharfeApr 5, 2024
  9. Jeff KingApr 5, 2024

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.