diff mbox series

[5/5] diff: store graph prefix buf in git_graph struct

Message ID 20241003211317.GE11328@coredump.intra.peff.net (mailing list archive)
State Accepted
Commit 1164e270b5af80516625b628945ec7365d992055
Headers show
Series diff output_prefix cleanups | expand

Commit Message

Jeff King Oct. 3, 2024, 9:13 p.m. UTC
The diffopt output_prefix interface makes it the callback's job to
handle ownership of the memory it returns, keeping it valid while
callers are using it and then eventually freeing it when we are done
diffing.

In diff_output_prefix_callback() we handle this with a static strbuf,
effectively "leaking" it when the diff is done (but not triggering any
leak detectors because it's technically still reachable). This has not
been a big problem in practice, but it is a problem for libification:
two diffs running in the same process could stomp on each other's prefix
buffers.

Since we only need the strbuf when we are formatting graph padding, we
can give ownership of the strbuf to the git_graph struct, letting us
free it when that struct is no longer in use.

Signed-off-by: Jeff King <peff@peff.net>
---
 graph.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Comments

Junio C Hamano Oct. 3, 2024, 11:43 p.m. UTC | #1
Jeff King <peff@peff.net> writes:

> Since we only need the strbuf when we are formatting graph padding, we
> can give ownership of the strbuf to the git_graph struct, letting us
> free it when that struct is no longer in use.
>
>  static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
>  {
>  	struct git_graph *graph = data;
> -	static struct strbuf msgbuf = STRBUF_INIT;
>  
>  	assert(opt);
>  
>  	if (!graph)
>  		return opt->line_prefix;
>  
> -	strbuf_reset(&msgbuf);

Oooh, I love this change.  The fewer file scope statics (or global
states in general) we have, the better ;-).
Patrick Steinhardt Oct. 4, 2024, 4:32 a.m. UTC | #2
On Thu, Oct 03, 2024 at 04:43:40PM -0700, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
> 
> > Since we only need the strbuf when we are formatting graph padding, we
> > can give ownership of the strbuf to the git_graph struct, letting us
> > free it when that struct is no longer in use.
> >
> >  static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
> >  {
> >  	struct git_graph *graph = data;
> > -	static struct strbuf msgbuf = STRBUF_INIT;
> >  
> >  	assert(opt);
> >  
> >  	if (!graph)
> >  		return opt->line_prefix;
> >  
> > -	strbuf_reset(&msgbuf);
> 
> Oooh, I love this change.  The fewer file scope statics (or global
> states in general) we have, the better ;-).

True, thanks for going the extra mile here! The other patches look good
to me, as well.

Patrick
diff mbox series

Patch

diff --git a/graph.c b/graph.c
index 0d200ca77f..bf000fdbe1 100644
--- a/graph.c
+++ b/graph.c
@@ -309,24 +309,28 @@  struct git_graph {
 	 * stored as an index into the array column_colors.
 	 */
 	unsigned short default_column_color;
+
+	/*
+	 * Scratch buffer for generating prefixes to be used with
+	 * diff_output_prefix_callback().
+	 */
+	struct strbuf prefix_buf;
 };
 
 static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
 {
 	struct git_graph *graph = data;
-	static struct strbuf msgbuf = STRBUF_INIT;
 
 	assert(opt);
 
 	if (!graph)
 		return opt->line_prefix;
 
-	strbuf_reset(&msgbuf);
+	strbuf_reset(&graph->prefix_buf);
 	if (opt->line_prefix)
-		strbuf_addstr(&msgbuf, opt->line_prefix);
-	if (graph)
-		graph_padding_line(graph, &msgbuf);
-	return msgbuf.buf;
+		strbuf_addstr(&graph->prefix_buf, opt->line_prefix);
+	graph_padding_line(graph, &graph->prefix_buf);
+	return graph->prefix_buf.buf;
 }
 
 static const struct diff_options *default_diffopt;
@@ -396,6 +400,7 @@  struct git_graph *graph_init(struct rev_info *opt)
 	 * The diff output prefix callback, with this we can make
 	 * all the diff output to align with the graph lines.
 	 */
+	strbuf_init(&graph->prefix_buf, 0);
 	opt->diffopt.output_prefix = diff_output_prefix_callback;
 	opt->diffopt.output_prefix_data = graph;
 
@@ -411,6 +416,7 @@  void graph_clear(struct git_graph *graph)
 	free(graph->new_columns);
 	free(graph->mapping);
 	free(graph->old_mapping);
+	strbuf_release(&graph->prefix_buf);
 	free(graph);
 }