[PATCH v2] utf8: use size_t for string width methods and callee sites.
From: Hardik Kumar <hidden>
Date: 2026-07-26 19:57:32
Subsystem:
the rest · Maintainer:
Linus Torvalds
utf8_strwidth() and utf8_strnwidth() return int, even though the return value is always non-negative: - utf8_strnwidth() accumulates the width into a size_t and otherwise returns its size_t len parameter, - utf8_strwidth() just forwards its result. Change their signatures to return size_t instead. Update the types of the variables the said method is used to avoid potential UB caused by implicit conversion from size_t to int. The returned values from `utf8_strwidth()` are casted to int at places where it was falling tests or required other changes. Signed-off-by: Hardik Kumar <redacted> --- Changes in v2: - reworked types for utf8_strwidth and its sites of usage. - removed redundant parens around `string`. - updated commit message for better explaining the patch. builtin/blame.c | 4 ++-- builtin/branch.c | 2 +- builtin/repo.c | 10 +++++----- column.c | 2 +- diff.c | 7 ++++--- gettext.c | 2 +- gettext.h | 2 +- pretty.c | 5 +++-- utf8.c | 13 ++++--------- utf8.h | 4 ++-- wt-status.c | 8 ++++---- 11 files changed, 28 insertions(+), 31 deletions(-)
diff --git a/builtin/blame.c b/builtin/blame.c
index 48d5251..2d24b63 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c@@ -564,7 +564,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, name = ci.author_mail.buf; else name = ci.author.buf; - pad = longest_author - utf8_strwidth(name); + pad = longest_author - cast_size_t_to_int(utf8_strwidth(name)); printf(" (%s%*s %10s", name, pad, "", format_time(ci.author_time,
@@ -668,7 +668,7 @@ static void find_alignment(struct blame_scoreboard *sb, int *option) for (e = sb->ent; e; e = e->next) { struct blame_origin *suspect = e->suspect; - int num; + size_t num; size_t marks_count = count_marks(e, *option); if (max_marks_count < marks_count)
diff --git a/builtin/branch.c b/builtin/branch.c
index dede60d..514ba64 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c@@ -354,7 +354,7 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus) for (i = 0; i < refs->nr; i++) { struct ref_array_item *it = refs->items[i]; const char *desc = it->refname; - int w; + size_t w; skip_prefix(it->refname, "refs/heads/", &desc); skip_prefix(it->refname, "refs/remotes/", &desc);
diff --git a/builtin/repo.c b/builtin/repo.c
index 84e012f..47b9191 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c@@ -367,7 +367,7 @@ static void stats_table_vaddf(struct stats_table *table, struct strbuf buf = STRBUF_INIT; struct string_list_item *item; char *formatted_name; - int name_width; + size_t name_width; strbuf_vaddf(&buf, format, ap); formatted_name = strbuf_detach(&buf, NULL);
@@ -387,12 +387,12 @@ static void stats_table_vaddf(struct stats_table *table, string_list_append_nodup(&table->annotations, strbuf_detach(&buf, NULL)); } if (entry->value) { - int value_width = utf8_strwidth(entry->value); + size_t value_width = utf8_strwidth(entry->value); if (value_width > table->value_col_width) table->value_col_width = value_width; } if (entry->unit) { - int unit_width = utf8_strwidth(entry->unit); + size_t unit_width = utf8_strwidth(entry->unit); if (unit_width > table->unit_col_width) table->unit_col_width = unit_width; }
@@ -582,8 +582,8 @@ static void stats_table_print_structure(const struct stats_table *table) { const char *name_col_title = _("Repository structure"); const char *value_col_title = _("Value"); - int title_name_width = utf8_strwidth(name_col_title); - int title_value_width = utf8_strwidth(value_col_title); + size_t title_name_width = utf8_strwidth(name_col_title); + size_t title_value_width = utf8_strwidth(value_col_title); int name_col_width = table->name_col_width; int value_col_width = table->value_col_width; int unit_col_width = table->unit_col_width;
diff --git a/column.c b/column.c
index 93fae31..6b7f921 100644
--- a/column.c
+++ b/column.c@@ -24,7 +24,7 @@ struct column_data { }; /* return length of 's' in letters, ANSI escapes stripped */ -static int item_length(const char *s) +static size_t item_length(const char *s) { return utf8_strnwidth(s, strlen(s), 1); }
diff --git a/diff.c b/diff.c
index 589c196..4887958 100644
--- a/diff.c
+++ b/diff.c@@ -2952,7 +2952,8 @@ static int utf8_ish_width(const char **start) static void show_stats(struct diffstat_t *data, struct diff_options *options) { - int i, len, add, del, adds = 0, dels = 0; + int i, add, del, adds = 0, dels = 0; + size_t len; uintmax_t max_change = 0, max_len = 0; int total_files = data->nr, count; int width, name_width, graph_width, number_width = 0, bin_width = 0;
@@ -3037,7 +3038,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) * making the line longer than the maximum width. */ if (options->stat_width == -1) - width = term_columns() - utf8_strnwidth(line_prefix, strlen(line_prefix), 1); + width = term_columns() - cast_size_t_to_int(utf8_strnwidth(line_prefix, strlen(line_prefix), 1)); else width = options->stat_width ? options->stat_width : 80; number_width = decimal_width(max_change) > number_width ?
@@ -3123,7 +3124,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) if (slash) name = slash; } - padding = len - utf8_strwidth(name); + padding = len - cast_size_t_to_int(utf8_strwidth(name)); if (padding < 0) padding = 0;
diff --git a/gettext.c b/gettext.c
index 8d08a61..4d5d05e 100644
--- a/gettext.c
+++ b/gettext.c@@ -129,7 +129,7 @@ void git_setup_gettext(void) } /* return the number of columns of string 's' in current locale */ -int gettext_width(const char *s) +size_t gettext_width(const char *s) { static int is_utf8 = -1; if (is_utf8 == -1)
diff --git a/gettext.h b/gettext.h
index 484cafa..f161a21 100644
--- a/gettext.h
+++ b/gettext.h@@ -31,7 +31,7 @@ #ifndef NO_GETTEXT extern int git_gettext_enabled; void git_setup_gettext(void); -int gettext_width(const char *s); +size_t gettext_width(const char *s); #else #define git_gettext_enabled (0) static inline void git_setup_gettext(void)
diff --git a/pretty.c b/pretty.c
index d8a9f37..f7d392d 100644
--- a/pretty.c
+++ b/pretty.c@@ -1805,11 +1805,12 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ { struct strbuf local_sb = STRBUF_INIT; size_t total_consumed = 0; - int len, padding = c->padding; + int padding = c->padding; + size_t len; if (padding < 0) { const char *start = strrchr(sb->buf, '\n'); - int occupied; + size_t occupied; if (!start) start = sb->buf; occupied = utf8_strnwidth(start, strlen(start), 1);
diff --git a/utf8.c b/utf8.c
index 96460cc..cefaefe 100644
--- a/utf8.c
+++ b/utf8.c@@ -208,7 +208,7 @@ int utf8_width(const char **start, size_t *remainder_p) * string, assuming that the string is utf8. Returns strlen() instead * if the string does not look like a valid utf8 string. */ -int utf8_strnwidth(const char *string, size_t len, int skip_ansi) +size_t utf8_strnwidth(const char *string, size_t len, int skip_ansi) { const char *orig = string; size_t width = 0;
@@ -225,15 +225,10 @@ int utf8_strnwidth(const char *string, size_t len, int skip_ansi) if (glyph_width > 0) width += glyph_width; } - - /* - * TODO: fix the interface of this function and `utf8_strwidth()` to - * return `size_t` instead of `int`. - */ - return cast_size_t_to_int(string ? width : len); + return string ? width : len; } -int utf8_strwidth(const char *string) +size_t utf8_strwidth(const char *string) { return utf8_strnwidth(string, strlen(string), 0); }
@@ -821,7 +816,7 @@ void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int wid const char *s) { size_t slen = strlen(s); - int display_len = utf8_strnwidth(s, slen, 0); + size_t display_len = utf8_strnwidth(s, slen, 0); int utf8_compensation = slen - display_len; if (display_len >= width) {
diff --git a/utf8.h b/utf8.h
index cf8ecb0..531e968 100644
--- a/utf8.h
+++ b/utf8.h@@ -7,8 +7,8 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */ size_t display_mode_esc_sequence_len(const char *s); int utf8_width(const char **start, size_t *remainder_p); -int utf8_strnwidth(const char *string, size_t len, int skip_ansi); -int utf8_strwidth(const char *string); +size_t utf8_strnwidth(const char *string, size_t len, int skip_ansi); +size_t utf8_strwidth(const char *string); int is_utf8(const char *text); int is_encoding_utf8(const char *name); int same_encoding(const char *, const char *);
diff --git a/wt-status.c b/wt-status.c
index 58461e0..0e1e32d 100644
--- a/wt-status.c
+++ b/wt-status.c@@ -331,9 +331,9 @@ static int maxwidth(const char *(*label)(int), int minval, int maxval) for (i = minval; i <= maxval; i++) { const char *s = label(i); - int len = s ? utf8_strwidth(s) : 0; + size_t len = s ? utf8_strwidth(s) : 0; if (len > result) - result = len; + result = cast_size_t_to_int(len); } return result; }
@@ -360,7 +360,7 @@ static void wt_longstatus_print_unmerged_data(struct wt_status *s, status_printf(s, color(WT_STATUS_HEADER, s), "\t"); how = wt_status_unmerged_status_string(d->stagemask); - len = label_width - utf8_strwidth(how); + len = label_width - cast_size_t_to_int(utf8_strwidth(how)); status_printf_more(s, c, "%s%.*s%s\n", how, len, padding, one); strbuf_release(&onebuf); }
@@ -429,7 +429,7 @@ static void wt_longstatus_print_change_data(struct wt_status *s, what = wt_status_diff_status_string(status); if (!what) BUG("unhandled diff status %c", status); - len = label_width - utf8_strwidth(what); + len = label_width - cast_size_t_to_int(utf8_strwidth(what)); assert(len >= 0); if (one_name != two_name) status_printf_more(s, c, "%s%.*s%s -> %s",
--
2.55.0