refactor: add xmemcpyz() and use it in place of some xstrlcpy() (#28422)

Problem:  Using xstrlcpy() when the exact length of the string to be
          copied is known is not ideal because it requires adding 1 to
          the length and an unnecessary strlen().
Solution: Add xmemcpyz() and use it in place of such xstrlcpy() calls.
This commit is contained in:
zeertzjq 2024-04-20 19:31:00 +08:00 committed by GitHub
parent 4d52b0cf67
commit 0ea38c9a53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 61 additions and 46 deletions

View File

@ -185,7 +185,7 @@ information.
mch_memmove memmove
vim_memset copy_chars copy_spaces memset
vim_strbyte strchr
vim_strncpy strncpy xstrlcpy
vim_strncpy strncpy xstrlcpy/xmemcpyz
vim_strcat strncat xstrlcat
VIM_ISWHITE ascii_iswhite
IS_WHITE_OR_NUL ascii_iswhite_or_nul

View File

@ -1989,12 +1989,12 @@ def CheckLanguage(filename, clean_lines, linenum, error):
match = Search(r'\b(strncpy|STRNCPY)\b', line)
if match:
error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcpy or snprintf instead of %s (unless this is from Vim)'
'Use xstrlcpy, xmemcpyz or snprintf instead of %s (unless this is from Vim)'
% match.group(1))
match = Search(r'\b(strcpy)\b', line)
if match:
error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcpy or snprintf instead of %s' % match.group(1))
'Use xstrlcpy, xmemcpyz or snprintf instead of %s' % match.group(1))
match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line)
if match:
error(filename, linenum, 'runtime/printf', 4,

View File

@ -1490,7 +1490,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
leader = xmalloc((size_t)bytes);
allocated = leader; // remember to free it later
xstrlcpy(leader, saved_line, (size_t)lead_len + 1);
xmemcpyz(leader, saved_line, (size_t)lead_len);
// TODO(vim): handle multi-byte and double width chars
for (int li = 0; li < comment_start; li++) {

View File

@ -1294,7 +1294,7 @@ char *addstar(char *fname, size_t len, int context)
}
} else {
retval = xmalloc(len + 4);
xstrlcpy(retval, fname, len + 1);
xmemcpyz(retval, fname, len);
// Don't add a star to *, ~, ~user, $var or `cmd`.
// * would become **, which walks the whole tree.
@ -2938,7 +2938,7 @@ void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regmatch, ch
static void expand_shellcmd_onedir(char *buf, char *s, size_t l, char *pat, char ***matches,
int *numMatches, int flags, hashtab_T *ht, garray_T *gap)
{
xstrlcpy(buf, s, l + 1);
xmemcpyz(buf, s, l);
add_pathsep(buf);
l = strlen(buf);
xstrlcpy(buf + l, pat, MAXPATHL - l);

View File

@ -345,7 +345,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg)
char *p = xmalloc(len);
((char **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
xstrlcpy(p + 7, start, (size_t)(end - start) + 1);
xmemcpyz(p + 7, start, (size_t)(end - start));
if (strstr(p + 7, "a:") == NULL) {
// No a: variables are used for sure.
flags |= FC_NOARGS;

View File

@ -1138,7 +1138,7 @@ static char *get_view_file(char c)
}
*s++ = '=';
*s++ = c;
xstrlcpy(s, ".vim", 5);
xmemcpyz(s, S_LEN(".vim"));
xfree(sname);
return retval;

View File

@ -291,7 +291,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL) {
// Make the start dir an absolute path name.
xstrlcpy(ff_expand_buffer, rel_fname, len + 1);
xmemcpyz(ff_expand_buffer, rel_fname, len);
search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, false);
} else {
search_ctx->ffsc_start_dir = xmemdupz(rel_fname, len);

View File

@ -1617,7 +1617,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark
STRCPY(newline, line);
// Append the marker to the end of the line
if (p == NULL || line_is_comment) {
xstrlcpy(newline + line_len, marker, markerlen + 1);
xmemcpyz(newline + line_len, marker, markerlen);
added = markerlen;
} else {
STRCPY(newline + line_len, cms);

View File

@ -271,7 +271,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle
size_t len;
if (buf->bh_space >= (size_t)slen) {
len = strlen(buf->bh_curr->b_str);
xstrlcpy(buf->bh_curr->b_str + len, s, (size_t)slen + 1);
xmemcpyz(buf->bh_curr->b_str + len, s, (size_t)slen);
buf->bh_space -= (size_t)slen;
} else {
if (slen < MINIMAL_SIZE) {
@ -281,7 +281,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle
}
buffblock_T *p = xmalloc(offsetof(buffblock_T, b_str) + len + 1);
buf->bh_space = len - (size_t)slen;
xstrlcpy(p->b_str, s, (size_t)slen + 1);
xmemcpyz(p->b_str, s, (size_t)slen);
p->b_next = buf->bh_curr->b_next;
buf->bh_curr->b_next = p;

View File

@ -347,7 +347,7 @@ static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len
if (rhs_lua == LUA_NOREF) {
mapargs->orig_rhs_len = orig_rhs_len;
mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char));
xstrlcpy(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
xmemcpyz(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len);
if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
mapargs->rhs = xcalloc(1, sizeof(char)); // single NUL-char
mapargs->rhs_len = 0;
@ -477,7 +477,7 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa
return 1;
}
char lhs_to_replace[256];
xstrlcpy(lhs_to_replace, to_parse, orig_lhs_len + 1);
xmemcpyz(lhs_to_replace, to_parse, orig_lhs_len);
size_t orig_rhs_len = strlen(rhs_start);
if (!set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len,

View File

@ -202,7 +202,7 @@ void *xmallocz(size_t size)
}
void *ret = xmalloc(total_size);
((char *)ret)[size] = 0;
((char *)ret)[size] = '\0';
return ret;
}
@ -222,6 +222,21 @@ void *xmemdupz(const void *data, size_t len)
return memcpy(xmallocz(len), data, len);
}
/// Duplicates `len` bytes of `src` to `dst` and zero terminates it.
/// and returns a pointer to the allocated memory. If the allocation fails,
/// the program dies.
///
/// @see {xstrlcpy}
/// @param[out] dst Buffer to store the result.
/// @param[in] src Buffer to be copied.
/// @param[in] len Number of bytes to be copied.
void *xmemcpyz(void *dst, const void *src, size_t len)
{
memcpy(dst, src, len);
((char *)dst)[len] = '\0';
return dst;
}
#ifndef HAVE_STRNLEN
size_t xstrnlen(const char *s, size_t n)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE

View File

@ -2476,7 +2476,7 @@ int op_change(oparg_T *oap)
// Subsequent calls to ml_get() flush the firstline data - take a
// copy of the inserted text.
char *ins_text = xmalloc((size_t)ins_len + 1);
xstrlcpy(ins_text, firstline + bd.textcol, (size_t)ins_len + 1);
xmemcpyz(ins_text, firstline + bd.textcol, (size_t)ins_len);
for (linenr_T linenr = oap->start.lnum + 1; linenr <= oap->end.lnum;
linenr++) {
block_prep(oap, &bd, linenr, true);

View File

@ -1195,7 +1195,7 @@ bool os_setenv_append_path(const char *fname)
const char *tail = path_tail_with_sep((char *)fname);
size_t dirlen = (size_t)(tail - fname);
assert(tail >= fname && dirlen + 1 < sizeof(os_buf));
xstrlcpy(os_buf, fname, dirlen + 1);
xmemcpyz(os_buf, fname, dirlen);
const char *path = os_getenv("PATH");
const size_t pathlen = path ? strlen(path) : 0;
const size_t newlen = pathlen + dirlen + 2;

View File

@ -374,7 +374,7 @@ static bool is_executable_in_path(const char *name, char **abspath)
char *e = xstrchrnul(p, ENV_SEPCHAR);
// Combine the $PATH segment with `name`.
xstrlcpy(buf, p, (size_t)(e - p) + 1);
xmemcpyz(buf, p, (size_t)(e - p));
(void)append_path(buf, name, buf_len);
#ifdef MSWIN

View File

@ -198,7 +198,7 @@ char *get_xdg_home(const XDGVarType idx)
assert(appname_len < (IOSIZE - sizeof("-data")));
if (dir) {
xstrlcpy(IObuff, appname, appname_len + 1);
xmemcpyz(IObuff, appname, appname_len);
#if defined(MSWIN)
if (idx == kXDGDataHome || idx == kXDGStateHome) {
xstrlcat(IObuff, "-data", IOSIZE);

View File

@ -2445,7 +2445,7 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize)
if (dir_len + 1 > sizeof(NameBuff)) {
continue;
}
xstrlcpy(NameBuff, dir, dir_len + 1);
xmemcpyz(NameBuff, dir, dir_len);
xstrlcat(NameBuff, PATHSEPSTR, sizeof(NameBuff));
xstrlcat(NameBuff, argv0, sizeof(NameBuff));
if (os_can_exe(NameBuff, NULL, false)) {

View File

@ -2379,7 +2379,7 @@ char *reg_submatch(int no)
// Within one line: take form start to end col.
len = rsm.sm_mmatch->endpos[no].col - rsm.sm_mmatch->startpos[no].col;
if (round == 2) {
xstrlcpy(retval, s, (size_t)len + 1);
xmemcpyz(retval, s, (size_t)len);
}
len++;
} else {

View File

@ -1628,14 +1628,14 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_
const char *appname = get_appname();
size_t appname_len = strlen(appname);
assert(appname_len < (IOSIZE - sizeof("-data")));
xstrlcpy(IObuff, appname, appname_len + 1);
xmemcpyz(IObuff, appname, appname_len);
#if defined(MSWIN)
if (type == kXDGDataHome || type == kXDGStateHome) {
xstrlcat(IObuff, "-data", IOSIZE);
appname_len += 5;
}
#endif
xstrlcpy(dest, IObuff, appname_len + 1);
xmemcpyz(dest, IObuff, appname_len);
dest += appname_len;
if (suf1 != NULL) {
*dest++ = PATHSEP;

View File

@ -811,7 +811,7 @@ static void find_word(matchinf_T *mip, int mode)
if (ptr == mip->mi_word) {
spell_casefold(mip->mi_win, ptr, wlen, fword, MAXWLEN);
} else {
xstrlcpy(fword, ptr, (size_t)endlen[endidxcnt] + 1);
xmemcpyz(fword, ptr, (size_t)endlen[endidxcnt]);
}
}
if (!can_compound(slang, fword, mip->mi_compflags)) {
@ -1810,7 +1810,7 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count)
} else if (len >= MAXWLEN) {
return;
} else {
xstrlcpy(buf, word, (size_t)len + 1);
xmemcpyz(buf, word, (size_t)len);
p = buf;
}
@ -1868,7 +1868,7 @@ int init_syl_tab(slang_T *slang)
}
syl_item_T *syl = GA_APPEND_VIA_PTR(syl_item_T, &slang->sl_syl_items);
xstrlcpy(syl->sy_chars, s, (size_t)l + 1);
xmemcpyz(syl->sy_chars, s, (size_t)l);
syl->sy_len = l;
}
return OK;
@ -2253,7 +2253,7 @@ static void use_midword(slang_T *lp, win_T *wp)
char *bp = xstrnsave(wp->w_s->b_spell_ismw_mb, (size_t)n + (size_t)l);
xfree(wp->w_s->b_spell_ismw_mb);
wp->w_s->b_spell_ismw_mb = bp;
xstrlcpy(bp + n, p, (size_t)l + 1);
xmemcpyz(bp + n, p, (size_t)l);
}
p += l;
}

View File

@ -2859,7 +2859,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags
if (flag != 0) {
// Find the flag in the hashtable. If it was used before, use
// the existing ID. Otherwise add a new entry.
xstrlcpy(key, prevp, (size_t)(p - prevp) + 1);
xmemcpyz(key, prevp, (size_t)(p - prevp));
hashitem_T *hi = hash_find(&aff->af_comp, key);
if (!HASHITEM_EMPTY(hi)) {
id = HI2CI(hi)->ci_newID;
@ -3263,7 +3263,7 @@ static int get_pfxlist(afffile_T *affile, char *afflist, char *store_afflist)
if (get_affitem(affile->af_flagtype, &p) != 0) {
// A flag is a postponed prefix flag if it appears in "af_pref"
// and its ID is not zero.
xstrlcpy(key, prevp, (size_t)(p - prevp) + 1);
xmemcpyz(key, prevp, (size_t)(p - prevp));
hashitem_T *hi = hash_find(&affile->af_pref, key);
if (!HASHITEM_EMPTY(hi)) {
int id = HI2AH(hi)->ah_newID;
@ -3293,7 +3293,7 @@ static void get_compflags(afffile_T *affile, char *afflist, char *store_afflist)
char *prevp = p;
if (get_affitem(affile->af_flagtype, &p) != 0) {
// A flag is a compound flag if it appears in "af_comp".
xstrlcpy(key, prevp, (size_t)(p - prevp) + 1);
xmemcpyz(key, prevp, (size_t)(p - prevp));
hashitem_T *hi = hash_find(&affile->af_comp, key);
if (!HASHITEM_EMPTY(hi)) {
store_afflist[cnt++] = (char)(uint8_t)HI2CI(hi)->ci_newID;
@ -3481,7 +3481,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
// Obey a "COMPOUNDFORBIDFLAG" of the affix: don't
// use the compound flags.
if (use_pfxlist != NULL && ae->ae_compforbid) {
xstrlcpy(pfx_pfxlist, use_pfxlist, (size_t)use_pfxlen + 1);
xmemcpyz(pfx_pfxlist, use_pfxlist, (size_t)use_pfxlen);
use_pfxlist = pfx_pfxlist;
}
@ -5576,7 +5576,7 @@ static void init_spellfile(void)
if (aspath) {
// Use directory of an entry with path, e.g., for
// "/dir/lg.utf-8.spl" use "/dir".
xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(lstart - curbuf->b_s.b_p_spl));
xmemcpyz(buf, curbuf->b_s.b_p_spl, (size_t)(lstart - curbuf->b_s.b_p_spl - 1));
} else {
// Copy the path from 'runtimepath' to buf[].
copy_option_part(&rtp, buf, MAXPATHL, ",");
@ -5585,7 +5585,7 @@ static void init_spellfile(void)
// Use the first language name from 'spelllang' and the
// encoding used in the first loaded .spl file.
if (aspath) {
xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl + 1));
xmemcpyz(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl));
} else {
// Create the "spell" directory if it doesn't exist yet.
l = (int)strlen(buf);

View File

@ -561,7 +561,7 @@ void spell_suggest(int count)
xstrlcpy(wcopy, stp->st_word, MAXWLEN + 1);
int el = sug.su_badlen - stp->st_orglen;
if (el > 0 && stp->st_wordlen + el <= MAXWLEN) {
xstrlcpy(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen, (size_t)el + 1);
xmemcpyz(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen, (size_t)el);
}
vim_snprintf(IObuff, IOSIZE, "%2d", i + 1);
if (cmdmsg_rl) {
@ -733,7 +733,7 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc
if (su->su_badlen >= MAXWLEN) {
su->su_badlen = MAXWLEN - 1; // just in case
}
xstrlcpy(su->su_badword, su->su_badptr, (size_t)su->su_badlen + 1);
xmemcpyz(su->su_badword, su->su_badptr, (size_t)su->su_badlen);
spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword,
MAXWLEN);
@ -1367,9 +1367,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun
compflags[sp->ts_complen] = (uint8_t)((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
xstrlcpy(preword + sp->ts_prewordlen,
xmemcpyz(preword + sp->ts_prewordlen,
tword + sp->ts_splitoff,
(size_t)(sp->ts_twordlen - sp->ts_splitoff) + 1);
(size_t)(sp->ts_twordlen - sp->ts_splitoff));
// Verify CHECKCOMPOUNDPATTERN rules.
if (match_checkcompoundpattern(preword, sp->ts_prewordlen,
@ -2646,8 +2646,8 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char *ba
// Add part of the bad word to the good word, so that we soundfold
// what replaces the bad word.
STRCPY(goodword, stp->st_word);
xstrlcpy(goodword + stp->st_wordlen,
su->su_badptr + su->su_badlen - lendiff, (size_t)lendiff + 1);
xmemcpyz(goodword + stp->st_wordlen,
su->su_badptr + su->su_badlen - lendiff, (size_t)lendiff);
pgood = goodword;
} else {
pgood = stp->st_word;

View File

@ -2733,7 +2733,7 @@ static int check_keyword_id(char *const line, const int startcol, int *const end
// Must make a copy of the keyword, so we can add a NUL and make it
// lowercase.
char keyword[MAXKEYWLEN + 1]; // assume max. keyword len is 80
xstrlcpy(keyword, kwp, (size_t)kwlen + 1);
xmemcpyz(keyword, kwp, (size_t)kwlen);
keyentry_T *kp = NULL;
@ -4949,7 +4949,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list,
do {
for (end = p; *end && !ascii_iswhite(*end) && *end != ','; end++) {}
char *const name = xmalloc((size_t)(end - p) + 3); // leave room for "^$"
xstrlcpy(name + 1, p, (size_t)(end - p) + 1);
xmemcpyz(name + 1, p, (size_t)(end - p));
if (strcmp(name + 1, "ALLBUT") == 0
|| strcmp(name + 1, "ALL") == 0
|| strcmp(name + 1, "TOP") == 0

View File

@ -1002,7 +1002,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches)
if (len > 128) {
len = 128;
}
xstrlcpy(tag_name, tagp.tagname, (size_t)len + 1);
xmemcpyz(tag_name, tagp.tagname, (size_t)len);
tag_name[len] = NUL;
// Save the tag file name
@ -1468,7 +1468,7 @@ static bool findtags_in_help_init(findtags_state_T *st)
// language name in help_lang[].
i = (int)strlen(st->tag_fname);
if (i > 3 && st->tag_fname[i - 3] == '-') {
xstrlcpy(st->help_lang, st->tag_fname + i - 2, 3);
xmemcpyz(st->help_lang, st->tag_fname + i - 2, 2);
} else {
STRCPY(st->help_lang, "en");
}
@ -2015,7 +2015,7 @@ static void findtags_add_match(findtags_state_T *st, tagptrs_T *tagpp, findtags_
if (tagpp->command + 2 < temp_end) {
len = (size_t)(temp_end - tagpp->command - 2);
mfp = xmalloc(len + 2);
xstrlcpy(mfp, tagpp->command + 2, len + 1);
xmemcpyz(mfp, tagpp->command + 2, len);
} else {
mfp = NULL;
}
@ -2023,7 +2023,7 @@ static void findtags_add_match(findtags_state_T *st, tagptrs_T *tagpp, findtags_
} else {
len = (size_t)(tagpp->tagname_end - tagpp->tagname);
mfp = xmalloc(sizeof(char) + len + 1);
xstrlcpy(mfp, tagpp->tagname, len + 1);
xmemcpyz(mfp, tagpp->tagname, len);
// if wanted, re-read line to get long form too
if (State & MODE_INSERT) {
@ -3268,7 +3268,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char *start
if (len > MAXPATHL - 1) {
len = MAXPATHL - 1;
}
xstrlcpy(buf, start, (size_t)len + 1);
xmemcpyz(buf, start, (size_t)len);
}
buf[len] = NUL;
int retval = tv_dict_add_str(dict, field_name, strlen(field_name), buf);