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

[PATCH 5/6] format-patch: return an allocated string from log_write_email_headers()

From
Jeff King <peff@peff.net>
Date
Mar 20, 2024, 00:35 UTC
Message-ID
<20240320003533.GE904136@coredump.intra.peff.net>
In-Reply-To
<20240320002555.GB903718@coredump.intra.peff.net>

When pretty-printing a commit in the email format, we have to fill in the "after subject" field of the pretty_print_context with any extra headers the user provided (e.g., from "--to" or "--cc" options) plus any special MIME headers.

We return an out-pointer that sometimes points to a newly heap-allocated string and sometimes not. To avoid leaking, we store the allocated version in a buffer with static lifetime, which is ugly. Worse, as we extend the header feature, we'll end up having to repeat this ugly pattern.

Instead, let's have our out-pointer pass ownership back to the caller, and duplicate the string when necessary. This does mean one extra allocation per commit when you use extra headers, but in the context of format-patch which is showing diffs, I don't think that's even measurable.

Signed-off-by: Jeff King <peff@peff.net>
---
I don't think the extra allocation is a big deal, but if we do, there
are some other options:
  - instead of an out-pointer we could take a strbuf, and the caller
    could reset and reuse a strbuf for each commit
  - the after_subject stuff could become a callback; we discussed this a
    long time ago (I had no recollection of the thread until finding it
    in the archive just now):
      https://lore.kernel.org/git/20170325211149.yyvocmdfw4zbjyoi@sigill.intra.peff.net/
  - this log_write_email_headers() function prints part of its output to
    stdout, and shoves part of it into the after_subject field to be
    shown by the pretty-printer. I wonder if it could just format the
    subject itself (though that would make "rev-list --format=email"
    even more awkward, I guess).
 builtin/log.c |  1 +
 log-tree.c    | 11 ++++++-----
 log-tree.h    |  2 +-
 pretty.h      |  2 +-
 4 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/builtin/log.c b/builtin/log.c
index 071a7f3131..c0a8bb95e9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1370,6 +1370,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 			   encoding, need_8bit_cte);
 	fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
+	free(pp.after_subject);
 	strbuf_release(&sb);
 
 	shortlog_init(&log);
diff --git a/log-tree.c b/log-tree.c
index a50f79ec60..5092a75958 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -470,11 +470,11 @@ void fmt_output_email_subject(struct strbuf *sb, struct rev_info *opt)
 }
 
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
-			     const char **extra_headers_p,
+			     char **extra_headers_p,
 			     int *need_8bit_cte_p,
 			     int maybe_multipart)
 {
-	const char *extra_headers = opt->extra_headers;
+	char *extra_headers = xstrdup_or_null(opt->extra_headers);
 	const char *name = oid_to_hex(opt->zero_commit ?
 				      null_oid() : &commit->object.oid);
 
@@ -496,12 +496,11 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 		graph_show_oneline(opt->graph);
 	}
 	if (opt->mime_boundary && maybe_multipart) {
-		static struct strbuf subject_buffer = STRBUF_INIT;
+		struct strbuf subject_buffer = STRBUF_INIT;
 		static struct strbuf buffer = STRBUF_INIT;
 		struct strbuf filename =  STRBUF_INIT;
 		*need_8bit_cte_p = -1; /* NEVER */
 
-		strbuf_reset(&subject_buffer);
 		strbuf_reset(&buffer);
 
 		strbuf_addf(&subject_buffer,
@@ -519,7 +518,8 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 			 extra_headers ? extra_headers : "",
 			 mime_boundary_leader, opt->mime_boundary,
 			 mime_boundary_leader, opt->mime_boundary);
-		extra_headers = subject_buffer.buf;
+		free(extra_headers);
+		extra_headers = strbuf_detach(&subject_buffer, NULL);
 
 		if (opt->numbered_files)
 			strbuf_addf(&filename, "%d", opt->nr);
@@ -854,6 +854,7 @@ void show_log(struct rev_info *opt)
 
 	strbuf_release(&msgbuf);
 	free(ctx.notes_message);
+	free(ctx.after_subject);
 
 	if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
 		struct diff_queue_struct dq;
diff --git a/log-tree.h b/log-tree.h
index 41c776fea5..94978e2c83 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -29,7 +29,7 @@ void format_decorations(struct strbuf *sb, const struct commit *commit,
 			int use_color, const struct decoration_options *opts);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
-			     const char **extra_headers_p,
+			     char **extra_headers_p,
 			     int *need_8bit_cte_p,
 			     int maybe_multipart);
 void load_ref_decorations(struct decoration_filter *filter, int flags);
diff --git a/pretty.h b/pretty.h
index 021bc1d658..9cc9e5d42b 100644
--- a/pretty.h
+++ b/pretty.h
@@ -35,7 +35,7 @@ struct pretty_print_context {
 	 */
 	enum cmit_fmt fmt;
 	int abbrev;
-	const char *after_subject;
+	char *after_subject;
 	int preserve_subject;
 	struct date_mode date_mode;
 	unsigned date_mode_explicit:1;
-- 
2.44.0.643.g35f318e502
Previous: Kristoffer HaugsbakkNext: Kristoffer Haugsbakk
Message 23 of 34 in “format-patch: teach `--header-cmd`”
  1. 0/3 format-patch: teach `--header-cmd`Kristoffer Haugsbakk, Mar 7, 2024
  2. 1/3 log-tree: take ownership of pointerKristoffer Haugsbakk, Mar 7, 2024
  3. Jeff KingMar 12, 2024
  4. Kristoffer HaugsbakkMar 12, 2024
  5. Jeff KingMar 13, 2024
  6. Kristoffer HaugsbakkMar 13, 2024
  7. 2/3 format-patch: teach `--header-cmd`Kristoffer Haugsbakk, Mar 7, 2024
  8. Kristoffer HaugsbakkMar 8, 2024
  9. Jean-Noël AvilaMar 11, 2024
  10. Kristoffer HaugsbakkMar 12, 2024
  11. 3/3 format-patch: check if header output looks validKristoffer Haugsbakk, Mar 7, 2024
  12. 0/3 format-patch: teach `--header-cmd`Kristoffer Haugsbakk, Mar 19, 2024
  13. 1/3 revision: add a per-email field to rev-infoKristoffer Haugsbakk, Mar 19, 2024
  14. Jeff KingMar 19, 2024
  15. Kristoffer HaugsbakkMar 19, 2024
  16. Jeff KingMar 20, 2024
  17. 1/6 shortlog: stop setting pp.print_email_subjectJeff King, Mar 20, 2024
  18. 2/6 pretty: split oneline and email subject printingJeff King, Mar 20, 2024
  19. Kristoffer HaugsbakkMar 22, 2024
  20. 3/6 pretty: drop print_email_subject flagJeff King, Mar 20, 2024
  21. 4/6 log: do not set up extra_headers for non-email formatsJeff King, Mar 20, 2024
  22. Kristoffer HaugsbakkMar 22, 2024
  23. 5/6 format-patch: return an allocated string from log_write_email_headers()Jeff King, Mar 20, 2024
  24. Kristoffer HaugsbakkMar 22, 2024
  25. 6/6 format-patch: simplify after-subject MIME header handlingJeff King, Mar 20, 2024
  26. Kristoffer HaugsbakkMar 22, 2024
  27. Jeff KingMar 20, 2024
  28. Kristoffer HaugsbakkMar 22, 2024
  29. 7/6 format-patch: fix leak of empty header stringJeff King, Mar 22, 2024
  30. Kristoffer HaugsbakkMar 22, 2024
  31. Junio C HamanoMar 22, 2024
  32. Kristoffer HaugsbakkMar 22, 2024
  33. 2/3 format-patch: teach `--header-cmd`Kristoffer Haugsbakk, Mar 19, 2024
  34. 3/3 format-patch: check if header output looks validKristoffer Haugsbakk, Mar 19, 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.