From fd1a838d364b62a9211af23c47e0eab8d54ea452 Mon Sep 17 00:00:00 2001 From: John Marriott Date: Wed, 6 Nov 2024 21:21:50 +0100 Subject: [PATCH] patch 9.1.0843: too many strlen() calls in undo.c Problem: too many strlen() calls in undo.c Solution: refactor code and remove strlen() calls, update test_undo.vim and close remaining open swap files (John Marriott) closes: #15995 Signed-off-by: John Marriott Signed-off-by: Christian Brabandt --- src/structs.h | 2 ++ src/testdir/test_undo.vim | 20 +++++++++--- src/undo.c | 65 ++++++++++++++++++++++----------------- src/version.c | 2 ++ 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/structs.h b/src/structs.h index 47999a9538..66d57e02d8 100644 --- a/src/structs.h +++ b/src/structs.h @@ -397,6 +397,8 @@ typedef struct { char_u *ul_line; // text of the line long ul_len; // length of the line including NUL, plus text // properties + colnr_T ul_textlen; // length of the line excluding NUL and any text + // properties } undoline_T; typedef struct u_entry u_entry_T; diff --git a/src/testdir/test_undo.vim b/src/testdir/test_undo.vim index eec0e0bc06..2e598d35c2 100644 --- a/src/testdir/test_undo.vim +++ b/src/testdir/test_undo.vim @@ -149,7 +149,7 @@ func Test_undotree_bufnr() " Drop created windows set ul& new - only! + bw! endfunc func Test_global_local_undolevels() @@ -193,6 +193,7 @@ func Test_global_local_undolevels() " Drop created windows set ul& new + bw! one two only! endfunc @@ -253,7 +254,7 @@ func Test_undo_del_chars() later 1h call assert_equal('123-abc', getline(1)) - close! + bw! endfunc func Test_undolist() @@ -274,7 +275,16 @@ func Test_undolist() call feedkeys('achange3\', 'xt') let a = execute('undolist') call assert_match("^\nnumber changes when *saved\n *2 *2 *.*\n *3 *2 .*$", a) - close! + + " 3 save number + if has("persistent_undo") + setl undofile + w Xundolist.txt + defer delete('Xundolist.txt') + let lastline = execute('undolist')->split("\n")[-1] + call assert_match("ago 1", lastline) + endif + bw! endfunc func Test_U_command() @@ -286,7 +296,7 @@ func Test_U_command() call assert_equal('', getline(1)) norm! U call assert_equal('change1change2', getline(1)) - close! + bw! endfunc func Test_undojoin() @@ -393,7 +403,7 @@ func Test_insert_expr() call feedkeys("u", 'x') call assert_equal(['a', 'b', 'c', '12', 'd'], getline(2, '$')) - close! + bw! endfunc func Test_undofile_earlier() diff --git a/src/undo.c b/src/undo.c index 8c2783acd5..52df9394fc 100644 --- a/src/undo.c +++ b/src/undo.c @@ -361,6 +361,7 @@ u_save_line(undoline_T *ul, linenr_T lnum) { char_u *line = ml_get(lnum); + ul->ul_textlen = ml_get_len(lnum); if (curbuf->b_ml.ml_line_len == 0) { ul->ul_len = 1; @@ -793,14 +794,10 @@ u_compute_hash(char_u *hash) { context_sha256_T ctx; linenr_T lnum; - char_u *p; sha256_start(&ctx); for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) - { - p = ml_get(lnum); - sha256_update(&ctx, p, (UINT32_T)(STRLEN(p) + 1)); - } + sha256_update(&ctx, ml_get(lnum), (UINT32_T)(ml_get_len(lnum) + 1)); sha256_finish(&ctx, hash); } @@ -820,8 +817,10 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) char_u *undo_file_name = NULL; int dir_len; char_u *p; + size_t plen; stat_T st; char_u *ffname = buf_ffname; + size_t ffnamelen; #ifdef HAVE_READLINK char_u fname_buf[MAXPATHL]; #endif @@ -836,6 +835,7 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) ffname = fname_buf; #endif + ffnamelen = STRLEN(ffname); // Loop over 'undodir'. When reading find the first file that exists. // When not reading use the first directory that exists or ".". dirp = p_udir; @@ -846,23 +846,24 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) { // Use same directory as the ffname, // "dir/name" -> "dir/.name.un~" - undo_file_name = vim_strnsave(ffname, STRLEN(ffname) + 5); + undo_file_name = vim_strnsave(ffname, ffnamelen + 5); if (undo_file_name == NULL) break; p = gettail(undo_file_name); + plen = (size_t)(ffnamelen - (p - undo_file_name)); #ifdef VMS // VMS can not handle more than one dot in the filenames // use "dir/name" -> "dir/_un_name" - add _un_ // at the beginning to keep the extension - mch_memmove(p + 4, p, STRLEN(p) + 1); + mch_memmove(p + 4, p, plen + 1); mch_memmove(p, "_un_", 4); #else // Use same directory as the ffname, // "dir/name" -> "dir/.name.un~" - mch_memmove(p + 1, p, STRLEN(p) + 1); + mch_memmove(p + 1, p, plen + 1); *p = '.'; - STRCAT(p, ".un~"); + STRCPY(p + plen + 1, ".un~"); #endif } else @@ -872,7 +873,7 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) { if (munged_name == NULL) { - munged_name = vim_strsave(ffname); + munged_name = vim_strnsave(ffname, ffnamelen); if (munged_name == NULL) return NULL; for (p = munged_name; *p != NUL; MB_PTR_ADV(p)) @@ -1189,7 +1190,6 @@ read_string_decrypt(bufinfo_T *bi, int len) static int serialize_header(bufinfo_T *bi, char_u *hash) { - long len; buf_T *buf = bi->bi_buf; FILE *fp = bi->bi_fp; char_u time_buf[8]; @@ -1205,6 +1205,7 @@ serialize_header(bufinfo_T *bi, char_u *hash) { char_u *header; int header_len; + long len; undo_write_bytes(bi, (long_u)UF_VERSION_CRYPT, 2); bi->bi_state = crypt_create_for_writing(crypt_get_method_nr(buf), @@ -1244,11 +1245,9 @@ serialize_header(bufinfo_T *bi, char_u *hash) // buffer-specific data undo_write_bytes(bi, (long_u)buf->b_ml.ml_line_count, 4); - len = buf->b_u_line_ptr.ul_line == NULL - ? 0L : (long)STRLEN(buf->b_u_line_ptr.ul_line); - undo_write_bytes(bi, (long_u)len, 4); - if (len > 0 && fwrite_crypt(bi, buf->b_u_line_ptr.ul_line, (size_t)len) - == FAIL) + undo_write_bytes(bi, (long_u)buf->b_u_line_ptr.ul_textlen, 4); + if (buf->b_u_line_ptr.ul_textlen > 0 && fwrite_crypt(bi, buf->b_u_line_ptr.ul_line, + (size_t)buf->b_u_line_ptr.ul_textlen) == FAIL) return FAIL; undo_write_bytes(bi, (long_u)buf->b_u_line_lnum, 4); undo_write_bytes(bi, (long_u)buf->b_u_line_colnr, 4); @@ -1415,7 +1414,6 @@ serialize_uep( u_entry_T *uep) { int i; - size_t len; undo_write_bytes(bi, (long_u)uep->ue_top, 4); undo_write_bytes(bi, (long_u)uep->ue_bot, 4); @@ -1425,10 +1423,10 @@ serialize_uep( { // Text is written without the text properties, since we cannot restore // the text property types. - len = STRLEN(uep->ue_array[i].ul_line); - if (undo_write_bytes(bi, (long_u)len, 4) == FAIL) + if (undo_write_bytes(bi, (long_u)uep->ue_array[i].ul_textlen, 4) == FAIL) return FAIL; - if (len > 0 && fwrite_crypt(bi, uep->ue_array[i].ul_line, len) == FAIL) + if (uep->ue_array[i].ul_textlen > 0 + && fwrite_crypt(bi, uep->ue_array[i].ul_line, uep->ue_array[i].ul_textlen) == FAIL) return FAIL; } return OK; @@ -1484,6 +1482,7 @@ unserialize_uep(bufinfo_T *bi, int *error, char_u *file_name) } array[i].ul_line = line; array[i].ul_len = line_len + 1; + array[i].ul_textlen = line_len; } return uep; } @@ -1862,6 +1861,7 @@ u_read_undo(char_u *name, char_u *hash, char_u *orig_name UNUSED) CLEAR_FIELD(bi); line_ptr.ul_len = 0; + line_ptr.ul_textlen = 0; line_ptr.ul_line = NULL; if (name == NULL) @@ -1986,6 +1986,7 @@ u_read_undo(char_u *name, char_u *hash, char_u *orig_name UNUSED) { line_ptr.ul_line = read_string_decrypt(&bi, str_len); line_ptr.ul_len = str_len + 1; + line_ptr.ul_textlen = str_len; } line_lnum = (linenr_T)undo_read_4c(&bi); line_colnr = (colnr_T)undo_read_4c(&bi); @@ -3098,7 +3099,7 @@ ex_undolist(exarg_T *eap UNUSED) int mark; int nomark; int changes = 1; - int i; + int len; /* * 1: walk the tree to find all leafs, put the info in "ga". @@ -3117,18 +3118,20 @@ ex_undolist(exarg_T *eap UNUSED) { if (ga_grow(&ga, 1) == FAIL) break; - vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ", + len = vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ", uhp->uh_seq, changes); - add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), - uhp->uh_time); + add_time(IObuff + len, IOSIZE - len, uhp->uh_time); + + // we have to call STRLEN() here because add_time() does not report + // the number of characters added. + len += STRLEN(IObuff + len); if (uhp->uh_save_nr > 0) { - while (STRLEN(IObuff) < 33) - STRCAT(IObuff, " "); - vim_snprintf_add((char *)IObuff, IOSIZE, - " %3ld", uhp->uh_save_nr); + int n = (len >= 33) ? 0 : 33 - len; + + len += vim_snprintf((char *)IObuff + len, IOSIZE - len, "%*.*s %3ld", n, n, " ", uhp->uh_save_nr); } - ((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strsave(IObuff); + ((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strnsave(IObuff, len); } uhp->uh_walk = mark; @@ -3175,6 +3178,8 @@ ex_undolist(exarg_T *eap UNUSED) msg(_("Nothing to undo")); else { + int i; + sort_strings((char_u **)ga.ga_data, ga.ga_len); msg_start(); @@ -3481,6 +3486,7 @@ u_clearall(buf_T *buf) buf->b_u_numhead = 0; buf->b_u_line_ptr.ul_line = NULL; buf->b_u_line_ptr.ul_len = 0; + buf->b_u_line_ptr.ul_textlen = 0; buf->b_u_line_lnum = 0; } @@ -3540,6 +3546,7 @@ u_clearline(void) VIM_CLEAR(curbuf->b_u_line_ptr.ul_line); curbuf->b_u_line_ptr.ul_len = 0; + curbuf->b_u_line_ptr.ul_textlen = 0; curbuf->b_u_line_lnum = 0; } diff --git a/src/version.c b/src/version.c index 7d02e6cf7d..7e95a46a77 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 843, /**/ 842, /**/