From: John Marriott Date: Thu, 19 Feb 2026 17:25:27 +0000 (+0000) Subject: patch 9.2.0031: Inefficient use of ga_concat() X-Git-Tag: v9.2.0031^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed202035b1904c84d92adb76d7e1a95b7540e048;p=thirdparty%2Fvim.git patch 9.2.0031: Inefficient use of ga_concat() Problem: Inefficient use of ga_concat() Solution: Use ga_concat_len() when the length is already known to avoid use of strlen() (John Marriott). closes: #19422 Co-authored-by: Hirohito Higashi Signed-off-by: John Marriott Signed-off-by: Christian Brabandt --- diff --git a/src/clientserver.c b/src/clientserver.c index 028da5c063..3d801bbf0f 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -674,12 +674,16 @@ build_drop_cmd( int i; char_u *inicmd = NULL; char_u *p; - char_u *cdp; + string_T cdp; char_u *cwd; // reset wildignore temporarily - const char *wig[] = - { ":let g:_wig=&wig|set wig=", - ":let &wig=g:_wig|unlet g:_wig"}; +# define STRING_INIT(s) \ + {(char_u *)(s), STRLEN_LITERAL(s)} + const string_T wig[] = { + STRING_INIT(":let g:_wig=&wig|set wig="), + STRING_INIT(":let &wig=g:_wig|unlet g:_wig") + }; +# undef STRING_INIT if (filec > 0 && filev[0][0] == '+') { @@ -700,7 +704,7 @@ build_drop_cmd( vim_free(cwd); return NULL; } - cdp = vim_strsave_escaped_ext(cwd, + cdp.string = vim_strsave_escaped_ext(cwd, # ifdef BACKSLASH_IN_FILENAME (char_u *)"", // rem_backslash() will tell what chars to escape # else @@ -708,20 +712,20 @@ build_drop_cmd( # endif '\\', TRUE); vim_free(cwd); - if (cdp == NULL) + if (cdp.string == NULL) return NULL; + cdp.length = STRLEN(cdp.string); ga_init2(&ga, 1, 100); - ga_concat(&ga, (char_u *)":cd "); - ga_concat(&ga, cdp); + GA_CONCAT_LITERAL(&ga, ":cd "); + ga_concat_len(&ga, cdp.string, cdp.length); // reset wildignorecase temporarily - ga_concat(&ga, (char_u *)wig[0]); + ga_concat_len(&ga, wig[0].string, wig[0].length); // Call inputsave() so that a prompt for an encryption key works. - ga_concat(&ga, (char_u *) - ":if exists('*inputsave')|call inputsave()|endif|"); + GA_CONCAT_LITERAL(&ga, ":if exists('*inputsave')|call inputsave()|endif|"); if (tabs) - ga_concat(&ga, (char_u *)"tab "); - ga_concat(&ga, (char_u *)"drop"); + GA_CONCAT_LITERAL(&ga, "tab "); + GA_CONCAT_LITERAL(&ga, "drop"); for (i = 0; i < filec; i++) { // On Unix the shell has already expanded the wildcards, don't want to @@ -739,16 +743,15 @@ build_drop_cmd( vim_free(ga.ga_data); return NULL; } - ga_concat(&ga, (char_u *)" "); + GA_CONCAT_LITERAL(&ga, " "); ga_concat(&ga, p); vim_free(p); } - ga_concat(&ga, (char_u *) - "|if exists('*inputrestore')|call inputrestore()|endif"); + GA_CONCAT_LITERAL(&ga, "|if exists('*inputrestore')|call inputrestore()|endif"); // The :drop commands goes to Insert mode when 'insertmode' is set, use // CTRL-\ CTRL-N again. - ga_concat(&ga, (char_u *)""); + GA_CONCAT_LITERAL(&ga, ""); // Switch back to the correct current directory (prior to temporary path // switch) unless 'autochdir' is set, in which case it will already be @@ -761,34 +764,34 @@ build_drop_cmd( // cd - // endif // endif - ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|"); + GA_CONCAT_LITERAL(&ga, ":if !exists('+acd')||!&acd|if haslocaldir()|"); # ifdef MSWIN // in case :set shellslash is set, need to normalize the directory separators // '/' is not valid in a filename so replacing '/' by '\\' should be safe - ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd()->tr('/','\\') ==# '"); + GA_CONCAT_LITERAL(&ga, "cd -|lcd -|elseif getcwd()->tr('/','\\') ==# '"); # else - ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '"); + GA_CONCAT_LITERAL(&ga, "cd -|lcd -|elseif getcwd() ==# '"); # endif - ga_concat(&ga, cdp); - ga_concat(&ga, (char_u *)"'|cd -|endif|endif"); - vim_free(cdp); + ga_concat_len(&ga, cdp.string, cdp.length); + GA_CONCAT_LITERAL(&ga, "'|cd -|endif|endif"); + vim_free(cdp.string); // reset wildignorecase - ga_concat(&ga, (char_u *)wig[1]); + ga_concat_len(&ga, wig[1].string, wig[1].length); if (sendReply) - ga_concat(&ga, (char_u *)":call SetupRemoteReplies()"); - ga_concat(&ga, (char_u *)":"); + GA_CONCAT_LITERAL(&ga, ":call SetupRemoteReplies()"); + GA_CONCAT_LITERAL(&ga, ":"); if (inicmd != NULL) { // Can't use after "inicmd", because a "startinsert" would cause // the following commands to be inserted as text. Use a "|", // hopefully "inicmd" does allow this... ga_concat(&ga, inicmd); - ga_concat(&ga, (char_u *)"|"); + GA_CONCAT_LITERAL(&ga, "|"); } // Bring the window to the foreground, goto Insert mode when 'im' set and // clear command line. - ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f"); + GA_CONCAT_LITERAL(&ga, "cal foreground()|if &im|star|en|redr|f"); ga_append(&ga, NUL); return ga.ga_data; } diff --git a/src/json.c b/src/json.c index d70d3b6c55..8b0b050b8a 100644 --- a/src/json.c +++ b/src/json.c @@ -96,6 +96,7 @@ json_encode_lsp_msg(typval_T *val) { garray_T ga; garray_T lspga; + size_t IObufflen; ga_init2(&ga, 1, 4000); if (json_encode_gap(&ga, val, 0) == FAIL) @@ -104,10 +105,10 @@ json_encode_lsp_msg(typval_T *val) ga_init2(&lspga, 1, 4000); // Header according to LSP specification. - vim_snprintf((char *)IObuff, IOSIZE, + IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE, "Content-Length: %u\r\n\r\n", ga.ga_len - 1); - ga_concat(&lspga, IObuff); + ga_concat_len(&lspga, IObuff, IObufflen); ga_concat_len(&lspga, ga.ga_data, ga.ga_len); ga_clear(&ga); return lspga.ga_data; @@ -145,7 +146,7 @@ write_string(garray_T *gap, char_u *str) if (res == NULL) { - ga_concat(gap, (char_u *)"\"\""); + GA_CONCAT_LITERAL(gap, "\"\""); return; } @@ -199,16 +200,21 @@ write_string(garray_T *gap, char_u *str) ga_append(gap, c); break; default: - vim_snprintf((char *)numbuf, NUMBUFLEN, "\\u%04lx", - (long)c); - ga_concat(gap, numbuf); + { + size_t numbuflen; + + numbuflen = vim_snprintf_safelen((char *)numbuf, + sizeof(numbuf), "\\u%04lx", (long)c); + ga_concat_len(gap, numbuf, numbuflen); + } } res += 1; } else { - int l = utf_ptr2len(res); + int l = utf_ptr2len(res); + size_t numbuflen; if (l > 1) { @@ -222,8 +228,9 @@ write_string(garray_T *gap, char_u *str) ga_concat_len(gap, from, res - from); from = res + 1; - numbuf[utf_char2bytes(0xFFFD, numbuf)] = NUL; - ga_concat(gap, numbuf); + numbuflen = utf_char2bytes(0xFFFD, numbuf); + numbuf[numbuflen] = NUL; + ga_concat_len(gap, numbuf, numbuflen); res += l; } @@ -276,8 +283,8 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) case VAR_BOOL: switch ((long)val->vval.v_number) { - case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; - case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; + case VVAL_FALSE: GA_CONCAT_LITERAL(gap, "false"); break; + case VVAL_TRUE: GA_CONCAT_LITERAL(gap, "true"); break; } break; @@ -289,14 +296,18 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) // empty item break; // FALLTHROUGH - case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; + case VVAL_NULL: GA_CONCAT_LITERAL(gap, "null"); break; } break; case VAR_NUMBER: - vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld", - (varnumber_T)val->vval.v_number); - ga_concat(gap, numbuf); + { + size_t numbuflen; + + numbuflen = vim_snprintf_safelen((char *)numbuf, sizeof(numbuf), + "%lld", (varnumber_T)val->vval.v_number); + ga_concat_len(gap, numbuf, numbuflen); + } break; case VAR_STRING: @@ -318,17 +329,19 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) case VAR_BLOB: b = val->vval.v_blob; if (b == NULL || b->bv_ga.ga_len == 0) - ga_concat(gap, (char_u *)"[]"); + GA_CONCAT_LITERAL(gap, "[]"); else { ga_append(gap, '['); for (i = 0; i < b->bv_ga.ga_len; i++) { + size_t numbuflen; + if (i > 0) - ga_concat(gap, (char_u *)","); - vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", - blob_get(b, i)); - ga_concat(gap, numbuf); + GA_CONCAT_LITERAL(gap, ","); + numbuflen = vim_snprintf_safelen((char *)numbuf, sizeof(numbuf), + "%d", blob_get(b, i)); + ga_concat_len(gap, numbuf, numbuflen); } ga_append(gap, ']'); } @@ -337,11 +350,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) case VAR_LIST: l = val->vval.v_list; if (l == NULL) - ga_concat(gap, (char_u *)"[]"); + GA_CONCAT_LITERAL(gap, "[]"); else { if (l->lv_copyID == copyID) - ga_concat(gap, (char_u *)"[]"); + GA_CONCAT_LITERAL(gap, "[]"); else { listitem_T *li; @@ -373,11 +386,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) case VAR_TUPLE: tuple = val->vval.v_tuple; if (tuple == NULL) - ga_concat(gap, (char_u *)"[]"); + GA_CONCAT_LITERAL(gap, "[]"); else { if (tuple->tv_copyID == copyID) - ga_concat(gap, (char_u *)"[]"); + GA_CONCAT_LITERAL(gap, "[]"); else { int len = TUPLE_LEN(tuple); @@ -409,11 +422,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) case VAR_DICT: d = val->vval.v_dict; if (d == NULL) - ga_concat(gap, (char_u *)"{}"); + GA_CONCAT_LITERAL(gap, "{}"); else { if (d->dv_copyID == copyID) - ga_concat(gap, (char_u *)"{}"); + GA_CONCAT_LITERAL(gap, "{}"); else { int first = TRUE; @@ -451,20 +464,22 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) case VAR_FLOAT: #if defined(HAVE_MATH_H) if (isnan(val->vval.v_float)) - ga_concat(gap, (char_u *)"NaN"); + GA_CONCAT_LITERAL(gap, "NaN"); else if (isinf(val->vval.v_float)) { if (val->vval.v_float < 0.0) - ga_concat(gap, (char_u *)"-Infinity"); + GA_CONCAT_LITERAL(gap, "-Infinity"); else - ga_concat(gap, (char_u *)"Infinity"); + GA_CONCAT_LITERAL(gap, "Infinity"); } else #endif { - vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", - val->vval.v_float); - ga_concat(gap, numbuf); + size_t numbuflen; + + numbuflen = vim_snprintf_safelen((char *)numbuf, sizeof(numbuf), + "%g", val->vval.v_float); + ga_concat_len(gap, numbuf, numbuflen); } break; case VAR_UNKNOWN: @@ -612,9 +627,11 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote) if (res != NULL) { char_u buf[NUMBUFLEN]; + size_t buflen; - buf[utf_char2bytes((int)nr, buf)] = NUL; - ga_concat(&ga, buf); + buflen = utf_char2bytes((int)nr, buf); + buf[buflen] = NUL; + ga_concat_len(&ga, buf, buflen); } break; default: diff --git a/src/list.c b/src/list.c index c3d7b5a2b8..253b1be9ff 100644 --- a/src/list.c +++ b/src/list.c @@ -1466,7 +1466,7 @@ list2string(typval_T *tv, int copyID, int restore_copyID) } typedef struct join_S { - char_u *s; + string_T s; char_u *tofree; } join_T; @@ -1482,37 +1482,39 @@ list_join_inner( { int i; join_T *p; - int len; int sumlen = 0; int first = TRUE; char_u *tofree; char_u numbuf[NUMBUFLEN]; listitem_T *item; - char_u *s; + string_T s; + size_t seplen; // Stringify each item in the list. CHECK_LIST_MATERIALIZE(l); for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) { - s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, + s.string = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, echo_style, restore_copyID, !echo_style); - if (s == NULL) + if (s.string == NULL) return FAIL; - len = (int)STRLEN(s); - sumlen += len; + s.length = STRLEN(s.string); + sumlen += (int)s.length; (void)ga_grow(join_gap, 1); p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++); - if (tofree != NULL || s != numbuf) + if (tofree != NULL || s.string != numbuf) { - p->s = s; + p->s.string = s.string; + p->s.length = s.length; p->tofree = tofree; } else { - p->s = vim_strnsave(s, len); - p->tofree = p->s; + p->s.string = vim_strnsave(s.string, s.length); + p->s.length = s.length; + p->tofree = p->s.string; } line_breakcheck(); @@ -1522,8 +1524,9 @@ list_join_inner( // Allocate result buffer with its total size, avoid re-allocation and // multiple copy operations. Add 2 for a tailing ']' and NUL. + seplen = STRLEN(sep); if (join_gap->ga_len >= 2) - sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1); + sumlen += (int)seplen * (join_gap->ga_len - 1); if (ga_grow(gap, sumlen + 2) == FAIL) return FAIL; @@ -1532,11 +1535,11 @@ list_join_inner( if (first) first = FALSE; else - ga_concat(gap, sep); + ga_concat_len(gap, sep, seplen); p = ((join_T *)join_gap->ga_data) + i; - if (p->s != NULL) - ga_concat(gap, p->s); + if (p->s.string != NULL) + ga_concat_len(gap, p->s.string, p->s.length); line_breakcheck(); } @@ -1836,8 +1839,11 @@ f_list2str(typval_T *argvars, typval_T *rettv) FOR_ALL_LIST_ITEMS(l, li) { - buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL; - ga_concat(&ga, buf); + size_t buflen; + + buflen = (size_t)(*char2bytes)(tv_get_number(&li->li_tv), buf); + buf[buflen] = NUL; + ga_concat_len(&ga, buf, buflen); } ga_append(&ga, NUL); } diff --git a/src/macros.h b/src/macros.h index 3e2c1c568b..9007b5b37a 100644 --- a/src/macros.h +++ b/src/macros.h @@ -424,6 +424,7 @@ #define GA_GROW_FAILS(gap, n) unlikely((((gap)->ga_maxlen - (gap)->ga_len < (n)) ? ga_grow_inner((gap), (n)) : OK) == FAIL) // Inlined version of ga_grow() with optimized condition that it succeeds. #define GA_GROW_OK(gap, n) likely((((gap)->ga_maxlen - (gap)->ga_len < (n)) ? ga_grow_inner((gap), (n)) : OK) == OK) +#define GA_CONCAT_LITERAL(gap, s) ga_concat_len((gap), (char_u *)(s), STRLEN_LITERAL(s)) #ifndef MIN # define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/src/testing.c b/src/testing.c index dd8dc8e512..75e5edfc71 100644 --- a/src/testing.c +++ b/src/testing.c @@ -21,7 +21,6 @@ static void prepare_assert_error(garray_T *gap) { - char buf[NUMBUFLEN]; char_u *sname = estack_sfile(ESTACK_NONE); ga_init2(gap, 1, 100); @@ -29,15 +28,18 @@ prepare_assert_error(garray_T *gap) { ga_concat(gap, sname); if (SOURCING_LNUM > 0) - ga_concat(gap, (char_u *)" "); + GA_CONCAT_LITERAL(gap, " "); } if (SOURCING_LNUM > 0) { - sprintf(buf, "line %ld", (long)SOURCING_LNUM); - ga_concat(gap, (char_u *)buf); + char buf[NUMBUFLEN]; + size_t buflen; + + buflen = vim_snprintf_safelen(buf, sizeof(buf), "line %ld", (long)SOURCING_LNUM); + ga_concat_len(gap, (char_u *)buf, buflen); } if (sname != NULL || SOURCING_LNUM > 0) - ga_concat(gap, (char_u *)": "); + GA_CONCAT_LITERAL(gap, ": "); vim_free(sname); } @@ -54,28 +56,31 @@ ga_concat_esc(garray_T *gap, char_u *p, int clen) { mch_memmove(buf, p, clen); buf[clen] = NUL; - ga_concat(gap, buf); + ga_concat_len(gap, buf, clen); return; } switch (*p) { - case BS: ga_concat(gap, (char_u *)"\\b"); break; - case ESC: ga_concat(gap, (char_u *)"\\e"); break; - case FF: ga_concat(gap, (char_u *)"\\f"); break; - case NL: ga_concat(gap, (char_u *)"\\n"); break; - case TAB: ga_concat(gap, (char_u *)"\\t"); break; - case CAR: ga_concat(gap, (char_u *)"\\r"); break; - case '\\': ga_concat(gap, (char_u *)"\\\\"); break; + case BS: GA_CONCAT_LITERAL(gap, "\\b"); break; + case ESC: GA_CONCAT_LITERAL(gap, "\\e"); break; + case FF: GA_CONCAT_LITERAL(gap, "\\f"); break; + case NL: GA_CONCAT_LITERAL(gap, "\\n"); break; + case TAB: GA_CONCAT_LITERAL(gap, "\\t"); break; + case CAR: GA_CONCAT_LITERAL(gap, "\\r"); break; + case '\\': GA_CONCAT_LITERAL(gap, "\\\\"); break; default: - if (*p < ' ' || *p == 0x7f) - { - vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p); - ga_concat(gap, buf); - } - else - ga_append(gap, *p); - break; + if (*p < ' ' || *p == 0x7f) + { + size_t buflen; + + buflen = vim_snprintf_safelen((char *)buf, sizeof(buf), + "\\x%02x", *p); + ga_concat_len(gap, buf, buflen); + } + else + ga_append(gap, *p); + break; } } @@ -91,11 +96,12 @@ ga_concat_shorten_esc(garray_T *gap, char_u *str) int c; int clen; char_u buf[NUMBUFLEN]; + size_t buflen; int same_len; if (str == NULL) { - ga_concat(gap, (char_u *)"NULL"); + GA_CONCAT_LITERAL(gap, "NULL"); return; } @@ -112,12 +118,13 @@ ga_concat_shorten_esc(garray_T *gap, char_u *str) } if (same_len > 20) { - ga_concat(gap, (char_u *)"\\["); + GA_CONCAT_LITERAL(gap, "\\["); ga_concat_esc(gap, p, clen); - ga_concat(gap, (char_u *)" occurs "); - vim_snprintf((char *)buf, NUMBUFLEN, "%d", same_len); - ga_concat(gap, buf); - ga_concat(gap, (char_u *)" times]"); + GA_CONCAT_LITERAL(gap, " occurs "); + buflen = vim_snprintf_safelen((char *)buf, sizeof(buf), + "%d", same_len); + ga_concat_len(gap, buf, buflen); + GA_CONCAT_LITERAL(gap, " times]"); p = s; } else @@ -154,15 +161,15 @@ fill_assert_error( { ga_concat(gap, echo_string(opt_msg_tv, &tofree, numbuf, 0)); vim_free(tofree); - ga_concat(gap, (char_u *)": "); + GA_CONCAT_LITERAL(gap, ": "); } if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) - ga_concat(gap, (char_u *)"Pattern "); + GA_CONCAT_LITERAL(gap, "Pattern "); else if (atype == ASSERT_NOTEQUAL) - ga_concat(gap, (char_u *)"Expected not equal to "); + GA_CONCAT_LITERAL(gap, "Expected not equal to "); else - ga_concat(gap, (char_u *)"Expected "); + GA_CONCAT_LITERAL(gap, "Expected "); if (exp_str == NULL) { // When comparing dictionaries, drop the items that are equal, so that @@ -227,29 +234,30 @@ fill_assert_error( else { if (atype == ASSERT_FAILS) - ga_concat(gap, (char_u *)"'"); + GA_CONCAT_LITERAL(gap, "'"); ga_concat_shorten_esc(gap, exp_str); if (atype == ASSERT_FAILS) - ga_concat(gap, (char_u *)"'"); + GA_CONCAT_LITERAL(gap, "'"); } if (atype != ASSERT_NOTEQUAL) { if (atype == ASSERT_MATCH) - ga_concat(gap, (char_u *)" does not match "); + GA_CONCAT_LITERAL(gap, " does not match "); else if (atype == ASSERT_NOTMATCH) - ga_concat(gap, (char_u *)" does match "); + GA_CONCAT_LITERAL(gap, " does match "); else - ga_concat(gap, (char_u *)" but got "); + GA_CONCAT_LITERAL(gap, " but got "); ga_concat_shorten_esc(gap, tv2string(got_tv, &tofree, numbuf, 0)); vim_free(tofree); if (omitted != 0) { - char buf[100]; + char buf[100]; + size_t buflen; - vim_snprintf(buf, 100, " - %d equal item%s omitted", - omitted, omitted == 1 ? "" : "s"); - ga_concat(gap, (char_u *)buf); + buflen = vim_snprintf_safelen(buf, sizeof(buf), + " - %d equal item%s omitted", omitted, omitted == 1 ? "" : "s"); + ga_concat_len(gap, (char_u *)buf, buflen); } } @@ -368,9 +376,9 @@ assert_beeps(typval_T *argvars, int no_beep) { prepare_assert_error(&ga); if (no_beep) - ga_concat(&ga, (char_u *)"command did beep: "); + GA_CONCAT_LITERAL(&ga, "command did beep: "); else - ga_concat(&ga, (char_u *)"command did not beep: "); + GA_CONCAT_LITERAL(&ga, "command did not beep: "); ga_concat(&ga, cmd); assert_error(&ga); ga_clear(&ga); @@ -427,16 +435,18 @@ assert_equalfile(typval_T *argvars) char line1[200]; char line2[200]; int lineidx = 0; + size_t IObufflen; if (fname1 == NULL || fname2 == NULL) return 0; IObuff[0] = NUL; + IObufflen = 0; fd1 = mch_fopen((char *)fname1, READBIN); if (fd1 == NULL) { - vim_snprintf((char *)IObuff, IOSIZE, (char *)e_cant_read_file_str, - fname1); + IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE, + (char *)e_cant_read_file_str, fname1); } else { @@ -444,8 +454,8 @@ assert_equalfile(typval_T *argvars) if (fd2 == NULL) { fclose(fd1); - vim_snprintf((char *)IObuff, IOSIZE, (char *)e_cant_read_file_str, - fname2); + IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE, + (char *)e_cant_read_file_str, fname2); } else { @@ -460,12 +470,16 @@ assert_equalfile(typval_T *argvars) if (c1 == EOF) { if (c2 != EOF) + { STRCPY(IObuff, "first file is shorter"); + IObufflen = 21; + } break; } else if (c2 == EOF) { STRCPY(IObuff, "second file is shorter"); + IObufflen = 22; break; } else @@ -475,9 +489,8 @@ assert_equalfile(typval_T *argvars) ++lineidx; if (c1 != c2) { - vim_snprintf((char *)IObuff, IOSIZE, - "difference at byte %ld, line %ld", - count, linecount); + IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE, + "difference at byte %ld, line %ld", count, linecount); break; } } @@ -499,7 +512,7 @@ assert_equalfile(typval_T *argvars) } } - if (IObuff[0] != NUL) + if (IObufflen > 0) { garray_T ga; prepare_assert_error(&ga); @@ -510,21 +523,21 @@ assert_equalfile(typval_T *argvars) ga_concat(&ga, echo_string(&argvars[2], &tofree, numbuf, 0)); vim_free(tofree); - ga_concat(&ga, (char_u *)": "); + GA_CONCAT_LITERAL(&ga, ": "); } - ga_concat(&ga, IObuff); + ga_concat_len(&ga, IObuff, IObufflen); if (lineidx > 0) { line1[lineidx] = NUL; line2[lineidx] = NUL; - ga_concat(&ga, (char_u *)" after \""); - ga_concat(&ga, (char_u *)line1); + GA_CONCAT_LITERAL(&ga, " after \""); + ga_concat_len(&ga, (char_u *)line1, lineidx); if (STRCMP(line1, line2) != 0) { - ga_concat(&ga, (char_u *)"\" vs \""); - ga_concat(&ga, (char_u *)line2); + GA_CONCAT_LITERAL(&ga, "\" vs \""); + ga_concat_len(&ga, (char_u *)line2, lineidx); } - ga_concat(&ga, (char_u *)"\""); + GA_CONCAT_LITERAL(&ga, "\""); } assert_error(&ga); ga_clear(&ga); @@ -576,7 +589,7 @@ f_assert_exception(typval_T *argvars, typval_T *rettv) if (*get_vim_var_str(VV_EXCEPTION) == NUL) { prepare_assert_error(&ga); - ga_concat(&ga, (char_u *)"v:exception is not set"); + GA_CONCAT_LITERAL(&ga, "v:exception is not set"); assert_error(&ga); ga_clear(&ga); rettv->vval.v_number = 1; @@ -630,7 +643,7 @@ f_assert_fails(typval_T *argvars, typval_T *rettv) if (called_emsg == called_emsg_before) { prepare_assert_error(&ga); - ga_concat(&ga, (char_u *)"command did not fail: "); + GA_CONCAT_LITERAL(&ga, "command did not fail: "); assert_append_cmd_or_arg(&ga, argvars, cmd); assert_error(&ga); ga_clear(&ga); @@ -749,7 +762,7 @@ f_assert_fails(typval_T *argvars, typval_T *rettv) } fill_assert_error(&ga, &argvars[2], expected_str, &argvars[error_found_index], &actual_tv, ASSERT_FAILS); - ga_concat(&ga, (char_u *)": "); + GA_CONCAT_LITERAL(&ga, ": "); assert_append_cmd_or_arg(&ga, argvars, cmd); assert_error(&ga); ga_clear(&ga); diff --git a/src/version.c b/src/version.c index 5df5e5dcc5..b929dea0fb 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 31, /**/ 30, /**/