From 147190d8e7dd53cb329230630f764020b15d9c21 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 3 Jan 2026 09:54:12 +0800 Subject: [PATCH] vim-patch:partial:9.1.2044: Inefficient use of ga_concat() (#37209) Problem: Inefficient use of ga_concat() Solution: Use ga_concat_len() when the length is already known to avoid use of strlen() (John Marriott). Additionally the following changes are done: os_unix.c: - in function `socket_server_list_sockets()` use a `string_T` for the strings `buf` and `path` for use in `ga_concat_len()` and drop un-needed variable `dir`. quickfix.c: - in function `qf_jump_print_msg()` use a `string_T` for the string `IObuff` for use in `ga_concat_len()`. - in function `qf_range_text()` use a `string_T` for the string `buf` for use in `ga_concat_len()`. register.c: - simplify function `execreg_line_continuation()`. terminal.c: - in function `read_dump_file()` use a `string_T` for the string `prev_char` for use in `ga_concat_len()`. tuple.c: - in function `tuple_join_inner()` use a `string_T` for the string `s` for use in `ga_concat_len()`. Also, change local struct `join_T` to use `string_T`. vim9type.c: - in functions `type_name_tuple()` and `type_name_func()` use a `string_T` for the string `arg_type` for use in `ga_concat_len()`. closes: vim/vim#19038 https://github.com/vim/vim/commit/a7e671fbb9fa2af9ad6c4ba9a7a881df431cd02b Skip tuple. Co-authored-by: John Marriott --- src/nvim/eval/encode.c | 6 +++--- src/nvim/eval/window.c | 13 +++++++------ src/nvim/quickfix.c | 31 +++++++++++++++---------------- src/nvim/register.c | 22 ++++++++++++---------- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index bfb1cab619..76edb22d01 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -333,9 +333,9 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s if (i_ > 0 && (i_ & 3) == 0) { \ ga_append(gap, '.'); \ } \ - vim_snprintf((char *)numbuf, ARRAY_SIZE(numbuf), "%02X", \ - (int)tv_blob_get(blob_, i_)); \ - ga_concat(gap, numbuf); \ + size_t numbuflen = vim_snprintf_safelen(numbuf, ARRAY_SIZE(numbuf), "%02X", \ + (int)tv_blob_get(blob_, i_)); \ + ga_concat_len(gap, numbuf, numbuflen); \ } \ } \ } while (0) diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 9c794b29a5..218920965c 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -29,6 +29,7 @@ #include "nvim/option_vars.h" #include "nvim/os/fs.h" #include "nvim/pos_defs.h" +#include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/vim_defs.h" #include "nvim/window.h" @@ -854,12 +855,12 @@ void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (!win_has_winnr(wp, curtab)) { continue; } - snprintf(buf, sizeof(buf), "%dresize %d|", winnr, - wp->w_height); - ga_concat(&ga, buf); - snprintf(buf, sizeof(buf), "vert %dresize %d|", winnr, - wp->w_width); - ga_concat(&ga, buf); + size_t buflen = vim_snprintf_safelen(buf, sizeof(buf), + "%dresize %d|", winnr, wp->w_height); + ga_concat_len(&ga, buf, buflen); + buflen = vim_snprintf_safelen(buf, sizeof(buf), + "vert %dresize %d|", winnr, wp->w_width); + ga_concat_len(&ga, buf, buflen); winnr++; } } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 8644baa307..86cfcb84f5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3077,12 +3077,13 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf update_screen(); } } - vim_snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, - qf_get_curlist(qi)->qf_count, - qf_ptr->qf_cleared ? _(" (line deleted)") : "", - qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); + size_t IObufflen = vim_snprintf_safelen(IObuff, IOSIZE, + _("(%d of %d)%s%s: "), qf_index, + qf_get_curlist(qi)->qf_count, + qf_ptr->qf_cleared ? _(" (line deleted)") : "", + qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); // Add the message, skipping leading whitespace and newlines. - ga_concat(gap, IObuff); + ga_concat_len(gap, IObuff, IObufflen); qf_fmt_text(gap, skipwhite(qf_ptr->qf_text)); ga_append(gap, NUL); @@ -3486,26 +3487,24 @@ static void qf_fmt_text(garray_T *gap, const char *restrict text) /// of a quickfix entry to the grow array "gap". static void qf_range_text(garray_T *gap, const qfline_T *qfp) { - char *const buf = IObuff; - const size_t bufsize = IOSIZE; + String buf = cbuf_as_string(IObuff, 0); - vim_snprintf(buf, bufsize, "%" PRIdLINENR, qfp->qf_lnum); - size_t len = strlen(buf); + buf.size = vim_snprintf_safelen(buf.data, IOSIZE, "%" PRIdLINENR, qfp->qf_lnum); if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) { - vim_snprintf(buf + len, bufsize - len, "-%" PRIdLINENR, qfp->qf_end_lnum); - len += strlen(buf + len); + buf.size += vim_snprintf_safelen(buf.data + buf.size, IOSIZE - buf.size, + "-%" PRIdLINENR, qfp->qf_end_lnum); } if (qfp->qf_col > 0) { - vim_snprintf(buf + len, bufsize - len, " col %d", qfp->qf_col); - len += strlen(buf + len); + buf.size += vim_snprintf_safelen(buf.data + buf.size, IOSIZE - buf.size, + " col %d", qfp->qf_col); if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) { - vim_snprintf(buf + len, bufsize - len, "-%d", qfp->qf_end_col); - len += strlen(buf + len); + buf.size += vim_snprintf_safelen(buf.data + buf.size, IOSIZE - buf.size, + "-%d", qfp->qf_end_col); } } - ga_concat_len(gap, buf, len); + ga_concat_len(gap, buf.data, buf.size); } /// Display information (list number, list size and the title) about a diff --git a/src/nvim/register.c b/src/nvim/register.c index 9f3de9ea84..6cbee49d2a 100644 --- a/src/nvim/register.c +++ b/src/nvim/register.c @@ -570,9 +570,9 @@ static void put_reedit_in_typebuf(int silent) /// processed next is returned in idx. static char *execreg_line_continuation(String *lines, size_t *idx) { - size_t i = *idx; - assert(i > 0); - const size_t cmd_end = i; + size_t cmd_start = *idx; + assert(cmd_start > 0); + const size_t cmd_end = cmd_start; garray_T ga; ga_init(&ga, (int)sizeof(char), 400); @@ -580,32 +580,34 @@ static char *execreg_line_continuation(String *lines, size_t *idx) // search backwards to find the first line of this command. // Any line not starting with \ or "\ is the start of the // command. - while (--i > 0) { - char *p = skipwhite(lines[i].data); + while (--cmd_start > 0) { + char *p = skipwhite(lines[cmd_start].data); if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) { break; } } - const size_t cmd_start = i; // join all the lines - ga_concat(&ga, lines[cmd_start].data); + String *tmp = &lines[cmd_start]; + ga_concat_len(&ga, tmp->data, tmp->size); for (size_t j = cmd_start + 1; j <= cmd_end; j++) { - char *p = skipwhite(lines[j].data); + tmp = &lines[j]; + char *p = skipwhite(tmp->data); if (*p == '\\') { // Adjust the growsize to the current length to // speed up concatenating many lines. if (ga.ga_len > 400) { ga_set_growsize(&ga, MIN(ga.ga_len, 8000)); } - ga_concat(&ga, p + 1); + p++; + ga_concat_len(&ga, p, (size_t)(tmp->data + tmp->size - p)); } } ga_append(&ga, NUL); char *str = xmemdupz(ga.ga_data, (size_t)ga.ga_len); ga_clear(&ga); - *idx = i; + *idx = cmd_start; return str; }