Skip to contentSkip to conversation

FIX: use utf8_strnwidth for line_prefix in diff.c

PATCH In review Md Isfarul Haque via GitGitGadget 4 participants 9 messages Jan 24, 2024 – Jan 25, 2024

lore
Share & tools
lore
#0 lore raw

cover FIX: use utf8_strnwidth for line_prefix in diff.c

This patch adresses diff.c:2721 and proposes the fix using a new function.

Md Isfarul Haque (2):
FIX: use utf8_strnwidth for line_prefix in diff.c FIX memory leak in one branch

 diff.c | 19 +++++++++++++++++--
 diff.h |  1 +
 2 files changed, 18 insertions(+), 2 deletions(-)

base-commit: e02ecfcc534e2021aae29077a958dd11c3897e4c
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1653%2FInnocentZero%2Fdiff_needswork-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1653/InnocentZero/diff_needswork-v1
Pull-Request: https://github.com/git/git/pull/1653

Signature · 1 line
gitgitgadget
#1 lore raw

PATCH 1/2 FIX: use utf8_strnwidth for line_prefix in diff.c

From: Md Isfarul Haque <[email protected]>

This patch adresses diff.c:2721 and proposes the fix using a new function.

---
 diff.c | 18 ++++++++++++++++--
 diff.h |  1 +
 2 files changed, 17 insertions(+), 2 deletions(-)
diff.c +16 -2
index a89a6a6128a..e3223b8ce5b 100644
@@ -2300,6 +2300,20 @@ const char *diff_line_prefix(struct diff_options *opt)
 	return msgbuf->buf;
 }
 
+const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)
+{
+	struct strbuf *msgbuf = (struct strbuf *)malloc(sizeof(*msgbuf));
+	if (!opt->output_prefix){
+		msgbuf->buf = "";
+		msgbuf->len = 0;
+		msgbuf->alloc = 1;
+	}
+	else {
+		msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
+	}
+	return msgbuf;
+}
+
 static unsigned long sane_truncate_line(char *line, unsigned long len)
 {
 	const char *cp;
@@ -2635,7 +2649,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	int width, name_width, graph_width, number_width = 0, bin_width = 0;
 	const char *reset, *add_c, *del_c;
 	int extra_shown = 0;
-	const char *line_prefix = diff_line_prefix(options);
+	const struct strbuf *line_prefix = diff_line_prefix_buf(options);
 	struct strbuf out = STRBUF_INIT;
 
 	if (data->nr == 0)
@@ -2718,7 +2732,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	 * used to correctly count the display width instead of strlen().
 	 */
 	if (options->stat_width == -1)
-		width = term_columns() - strlen(line_prefix);
+		width = term_columns() - utf8_strnwidth(line_prefix->buf, line_prefix->len, 1);
 	else
 		width = options->stat_width ? options->stat_width : 80;
 	number_width = decimal_width(max_change) > number_width ?
diff.h +1 -0
index 66bd8aeb293..6eb8dc9a97e 100644
@@ -460,6 +460,7 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix);
 
 const char *diff_line_prefix(struct diff_options *);
 
+const struct strbuf *diff_line_prefix_buf(struct diff_options *);
 
 extern const char mime_boundary_leader[];
 
Signature · 1 line
gitgitgadget
#2 lore raw
Quoted 4 lines · Md Isfarul Haque via GitGitGadget

From: Md Isfarul Haque <[email protected]>

This patch adresses diff.c:2721 and proposes the fix using a new function.

Please give more details here about what is currently at diff.c:2721 and what the patch is fixing, as lines at diff.c:2721 could move to a different location if some changes are made to diff.c before your patches get merged or after they get merged.

Also if the patch is addressing an issue in a code comment I would expect the corresponding code comment to be removed by the patch.

About the subject, maybe "diff: use utf8_strnwidth() for line_prefix" is already better.

Quoted 11 lines
---
 diff.c | 18 ++++++++++++++++--
 diff.h |  1 +
 2 files changed, 17 insertions(+), 2 deletions(-)
diff.c +0 -0
index a89a6a6128a..e3223b8ce5b 100644

diff.c const char *diff_line_prefix(struct diff_options *opt) · line 2303

Quoted 4 lines
diff.c +1 -0
@@ -2300,6 +2300,20 @@ const char *diff_line_prefix(struct diff_options *opt)
        return msgbuf->buf;
 }
 
+const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)

This function seems to be used only in diff.c, so it could be static.

#3 lore raw
Quoted 7 lines · Christian Couder
Quoted 4 lines · Md Isfarul Haque via GitGitGadget

From: Md Isfarul Haque <[email protected]>

This patch adresses diff.c:2721 and proposes the fix using a new function.

Quoted 7 lines

Please give more details here about what is currently at diff.c:2721 and what the patch is fixing, as lines at diff.c:2721 could move to a different location if some changes are made to diff.c before your patches get merged or after they get merged.

Also if the patch is addressing an issue in a code comment I would expect the corresponding code comment to be removed by the patch.

I understand and apologize for the mess-up. I will keep it in mind next time.

Quoted 17 lines

About the subject, maybe "diff: use utf8_strnwidth() for line_prefix" is already better.

Quoted 14 lines
---
 diff.c | 18 ++++++++++++++++--
 diff.h |  1 +
 2 files changed, 17 insertions(+), 2 deletions(-)
diff.c +0 -0
index a89a6a6128a..e3223b8ce5b 100644
@@ -2300,6 +2300,20 @@ const char *diff_line_prefix(struct diff_options *opt)
        return msgbuf->buf;
 }
 
Quoted 3 lines

diff.c const char *diff_line_prefix(struct diff_options *opt) · line 2303

Quoted 1 line
diff.c +1 -0
+const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)

This function seems to be used only in diff.c, so it could be static.

As Junio pointed out, I will probably use the existing function with slight modifications and use it. Besides, having unnecessary allocations and frees will probably only add overhead.

Signature · 2 lines
Thanks and regards
Md. Isfarul Haque
#4 lore raw
In reply to Md Isfarul Haque via GitGitGadget
Quoted 3 lines · Md Isfarul Haque via GitGitGadget

From: Md Isfarul Haque <[email protected]>

This patch adresses diff.c:2721 and proposes the fix using a new function.

Once the issue has fully been addressed, it is expected that the NEEDSWORK comment there would be removed, making this proposed log message useless. Make it a habit to write a log message that is self-contained enough to help readers (including yourself in the future when you have forgotten the details of what you did in this commit).

diff.c const char *diff_line_prefix(struct diff_options *opt) · line 2304

Quoted 2 lines
diff.c +2 -0
+const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)
+{

Given that there is only one caller of this function in the same file, I do not see a reason why this needs to be extern and exported in diff.h (actually I do not see a need for this helper at all).

When dealing with a string buffer, it is much more common in this codebase for the caller to prepare a strbuf (often on its stack) and pass a pointer to it to helper functions. I.e.

	static void prepare_diff_line_prefix_buf(struct strbuf *buf,
						struct diff_options *opt)
	{
		... stuff whatever you need into the string buffer ...
                strbuf_add(buf, ...);
	}

	/* in show_stats() */
	struct strbuf line_prefix = STRBUF_INIT;
	...
	prepare_diff_line_prefix_buf(&line_prefix, options);
	... use line_prefix and ...
	... release the resource before returning ...
	strbuf_release(&line_prefix);

is more common and less prone to resource leak over time.

Quoted 10 lines
diff.c +1 -1
@@ -2635,7 +2649,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	int width, name_width, graph_width, number_width = 0, bin_width = 0;
 	const char *reset, *add_c, *del_c;
 	int extra_shown = 0;
-	const char *line_prefix = diff_line_prefix(options);
+	const struct strbuf *line_prefix = diff_line_prefix_buf(options);
 	struct strbuf out = STRBUF_INIT;
 
 	if (data->nr == 0)

diff.c static void show_stats(struct diffstat_t *data, struct diff_options *options) · line 2735

Quoted 5 lines
diff.c +1 -1
@@ -2718,7 +2732,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	 * used to correctly count the display width instead of strlen().
 	 */
 	if (options->stat_width == -1)
-		width = term_columns() - strlen(line_prefix);
+		width = term_columns() - utf8_strnwidth(line_prefix->buf, line_prefix->len, 1);

I do not see the need for any of the diff_line_prefix_buf() related changes, only to do this change. You have a const char *line_prefix at this point, and utf8_strnwidth() wants to know its length, so what you need is to massage the parameter to match what it wants. Perhaps even something simple and dumb like

	utf8_strnwidth(line_prefix, strlen(line_prefix), 1);

might be sufficient to replace strlen(line_prefix) in the original?

This patch hopefully will change the behaviour of the command. A patch needs to also protect the change from future breakages by adding a test or two to demonstrate the desired behaviour. Such a test should pass with the code change in the patch, and should fail when the code change in the patch gets reverted.

Thanks.

#5 lore raw
Quoted 4 lines · Junio C Hamano
Quoted 2 lines · Md Isfarul Haque via GitGitGadget

From: Md Isfarul Haque <[email protected]>

Quoted 9 lines
Quoted 1 line

This patch adresses diff.c:2721 and proposes the fix using a new function.

Once the issue has fully been addressed, it is expected that the NEEDSWORK comment there would be removed, making this proposed log message useless. Make it a habit to write a log message that is self-contained enough to help readers (including yourself in the future when you have forgotten the details of what you did in this commit).

I understand. Sorry for the mess-up. I will keep it in mind the next time.

Quoted 26 lines

diff.c const char *diff_line_prefix(struct diff_options *opt) · line 2304

Quoted 2 lines
diff.c +2 -0
+const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)
+{

Given that there is only one caller of this function in the same file, I do not see a reason why this needs to be extern and exported in diff.h (actually I do not see a need for this helper at all).

When dealing with a string buffer, it is much more common in this codebase for the caller to prepare a strbuf (often on its stack) and pass a pointer to it to helper functions. I.e.

	static void prepare_diff_line_prefix_buf(struct strbuf *buf,
						struct diff_options *opt)
	{
		... stuff whatever you need into the string buffer ...
                strbuf_add(buf, ...);
	}

	/* in show_stats() */
	struct strbuf line_prefix = STRBUF_INIT;
	...
	prepare_diff_line_prefix_buf(&line_prefix, options);
	... use line_prefix and ...
	... release the resource before returning ...
	strbuf_release(&line_prefix);
Quoted 2 lines

is more common and less prone to resource leak over time.

Ah, this is indeed very neat. Didn't strike me. I'm not extremely familiar with the codebase and was unaware of this practice. I will follow this pattern in the future.

Quoted 22 lines
Quoted 10 lines
diff.c +1 -1
@@ -2635,7 +2649,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	int width, name_width, graph_width, number_width = 0, bin_width = 0;
 	const char *reset, *add_c, *del_c;
 	int extra_shown = 0;
-	const char *line_prefix = diff_line_prefix(options);
+	const struct strbuf *line_prefix = diff_line_prefix_buf(options);
 	struct strbuf out = STRBUF_INIT;
 
 	if (data->nr == 0)

diff.c static void show_stats(struct diffstat_t *data, struct diff_options *options) · line 2735

Quoted 5 lines
diff.c +1 -1
@@ -2718,7 +2732,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 	 * used to correctly count the display width instead of strlen().
 	 */
 	if (options->stat_width == -1)
-		width = term_columns() - strlen(line_prefix);
+		width = term_columns() - utf8_strnwidth(line_prefix->buf, line_prefix->len, 1);

I do not see the need for any of the diff_line_prefix_buf() related changes, only to do this change. You have a const char *line_prefix at this point, and utf8_strnwidth() wants to know its length, so what you need is to massage the parameter to match what it wants. Perhaps even something simple and dumb like

Quoted 3 lines
	utf8_strnwidth(line_prefix, strlen(line_prefix), 1);

might be sufficient to replace strlen(line_prefix) in the original?

It was more of a force of habit on my end, since I usually do not use functions that do not have a limit on the length they are reading. However, considering that the string is generated by another function and is most likely safe as it was used earlier, I will implement this suggestion.

Quoted 7 lines

This patch hopefully will change the behaviour of the command. A patch needs to also protect the change from future breakages by adding a test or two to demonstrate the desired behaviour. Such a test should pass with the code change in the patch, and should fail when the code change in the patch gets reverted.

Alright. Where should I add the test? A new/existing test in t/t4013 or t4124-log-graph-octopus.sh?

Signature · 2 lines
Thanks and regards,
Md Isfarul Haque
#6 lore raw

PATCH 2/2 FIX memory leak in one branch

In reply to Md Isfarul Haque via GitGitGadget

From: Md Isfarul Haque <[email protected]>

---
 diff.c | 1 +
 1 file changed, 1 insertion(+)
diff.c +1 -0
index e3223b8ce5b..9fa00103a6b 100644
@@ -2309,6 +2309,7 @@ const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)
 		msgbuf->alloc = 1;
 	}
 	else {
+		free(msgbuf);
 		msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
 	}
 	return msgbuf;
Signature · 1 line
gitgitgadget
#7 lore raw

Re: [PATCH 2/2] FIX memory leak in one branch

Quoted 6 lines · Md Isfarul Haque via GitGitGadget

From: Md Isfarul Haque <[email protected]>

---
 diff.c | 1 +
 1 file changed, 1 insertion(+)

We do not need to see that you are just as human as other developers and are prone to make mistakes that you need to fix it in a follow-up. In other words, please do not introduce a bug in [1/2] only to be fixed in [2/2]. By squashing these two patches into one, you can pretend as if you are a perfect developer and never leaked memory ;-).

diff.c const struct strbuf *diff_line_prefix_buf(struct diff_options *opt) · line 2315

Quoted 12 lines
diff.c +1 -0
index e3223b8ce5b..9fa00103a6b 100644
@@ -2309,6 +2309,7 @@ const struct strbuf *diff_line_prefix_buf(struct diff_options *opt)
 		msgbuf->alloc = 1;
 	}
 	else {
+		free(msgbuf);
 		msgbuf = opt->output_prefix(opt, opt->output_prefix_data);
 	}
 	return msgbuf;

But as I said, I do not see a need for this helper function in the first place, so...

#8 lore raw
In reply to Md Isfarul Haque via GitGitGadget
Quoted 1 line · Md Isfarul Haque via GitGitGadget

This patch adresses diff.c:2721 and proposes the fix using a new function.

Yay. My favorite long-time pet-peeve topic.

Quoted 4 lines

Md Isfarul Haque (2):
FIX: use utf8_strnwidth for line_prefix in diff.c FIX memory leak in one branch

Our convention does not use "FIX" and other prefix on the subject. Please check Documentation/SubmittingPatches.

Thanks.