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 <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/structs.h b/src/structs.h
index 47999a9..66d57e0 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -397,6 +397,8 @@
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 eec0e0b..2e598d3 100644
--- a/src/testdir/test_undo.vim
+++ b/src/testdir/test_undo.vim
@@ -149,7 +149,7 @@
" Drop created windows
set ul&
new
- only!
+ bw!
endfunc
func Test_global_local_undolevels()
@@ -193,6 +193,7 @@
" Drop created windows
set ul&
new
+ bw! one two
only!
endfunc
@@ -253,7 +254,7 @@
later 1h
call assert_equal('123-abc', getline(1))
- close!
+ bw!
endfunc
func Test_undolist()
@@ -274,7 +275,16 @@
call feedkeys('achange3\<Esc>', '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 @@
call assert_equal('', getline(1))
norm! U
call assert_equal('change1change2', getline(1))
- close!
+ bw!
endfunc
func Test_undojoin()
@@ -393,7 +403,7 @@
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 8c2783a..52df939 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -361,6 +361,7 @@
{
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 @@
{
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 @@
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 @@
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 @@
{
// 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 @@
{
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 @@
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 @@
{
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 @@
// 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 @@
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 @@
{
// 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 @@
}
array[i].ul_line = line;
array[i].ul_len = line_len + 1;
+ array[i].ul_textlen = line_len;
}
return uep;
}
@@ -1862,6 +1861,7 @@
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 @@
{
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 @@
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 @@
{
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 @@
msg(_("Nothing to undo"));
else
{
+ int i;
+
sort_strings((char_u **)ga.ga_data, ga.ga_len);
msg_start();
@@ -3481,6 +3486,7 @@
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 @@
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 7d02e6c..7e95a46 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 843,
+/**/
842,
/**/
841,