patch 9.1.1291: too many strlen() calls in buffer.c Commit: https://github.com/vim/vim/commit/ec032de6465f159bd57c22d464e0f4815f3aefc7 Author: John Marriott <basil...@internode.on.net> Date: Thu Apr 10 21:34:19 2025 +0200
patch 9.1.1291: too many strlen() calls in buffer.c Problem: too many strlen() calls in buffer.c Solution: refactor buffer.c and remove strlen() calls (John Marriott) closes: #17063 Signed-off-by: John Marriott <basil...@internode.on.net> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/src/buffer.c b/src/buffer.c index 90ca59678..955800e3a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -45,7 +45,7 @@ static int buf_same_ino(buf_T *buf, stat_T *stp); static int otherfile_buf(buf_T *buf, char_u *ffname); #endif static int value_changed(char_u *str, char_u **last); -static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file); +static int append_arg_number(win_T *wp, char_u *buf, size_t buflen, int add_file); static void free_buffer(buf_T *); static void free_buffer_stuff(buf_T *buf, int free_options); static int bt_nofileread(buf_T *buf); @@ -72,6 +72,19 @@ static int buf_free_count = 0; static int top_file_num = 1; // highest file number static garray_T buf_reuse = GA_EMPTY; // file numbers to recycle +/* + * Calculate the percentage that `part` is of the `whole`. + */ + static int +calc_percentage(long part, long whole) +{ + // With 32 bit longs and more than 21,474,836 lines multiplying by 100 + // causes an overflow, thus for large numbers divide instead. + return (part > 1000000L) + ? (int)(part / (whole / 100L)) + : (int)((part * 100L) / whole); +} + /* * Return the highest possible buffer number. */ @@ -454,7 +467,7 @@ static hashtab_T buf_hashtab; static void buf_hashtab_add(buf_T *buf) { - sprintf((char *)buf->b_key, "%x", buf->b_fnum); + vim_snprintf((char *)buf->b_key, sizeof(buf->b_key), "%x", buf->b_fnum); if (hash_add(&buf_hashtab, buf->b_key, "create buffer") == FAIL) emsg(_(e_buffer_cannot_be_registered)); } @@ -3088,7 +3101,7 @@ buflist_findnr(int nr) if (nr == 0) nr = curwin->w_alt_fnum; - sprintf((char *)key, "%x", nr); + vim_snprintf((char *)key, sizeof(key), "%x", nr); hi = hash_find(&buf_hashtab, key); if (!HASHITEM_EMPTY(hi)) @@ -3385,6 +3398,8 @@ buflist_list(exarg_T *eap) for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next) #endif { + char_u *name; + #ifdef FEAT_TERMINAL job_running = term_job_running(buf->b_term); job_none_open = term_none_open(buf->b_term); @@ -3413,8 +3428,9 @@ buflist_list(exarg_T *eap) || (vim_strchr(eap->arg, '#') && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum))) continue; - if (buf_spname(buf) != NULL) - vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1); + name = buf_spname(buf); + if (name != NULL) + vim_strncpy(NameBuff, name, MAXPATHL - 1); else home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE); if (message_filtered(NameBuff)) @@ -3439,7 +3455,7 @@ buflist_list(exarg_T *eap) ro_char = !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '); msg_putchar(' '); - len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", + len = (int)vim_snprintf_safelen((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", buf->b_fnum, buf->b_p_bl ? ' ' : 'u', buf == curbuf ? '%' : @@ -3449,8 +3465,6 @@ buflist_list(exarg_T *eap) ro_char, changed_char, NameBuff); - if (len > IOSIZE - 20) - len = IOSIZE - 20; // put "line 999" in column 40 or after the file name i = 40 - vim_strsize(IObuff); @@ -3850,83 +3864,81 @@ fileinfo( int dont_truncate) { char_u *name; - int n; - char *p; char *buffer; - size_t len; + size_t bufferlen = 0; buffer = alloc(IOSIZE); if (buffer == NULL) return; if (fullname > 1) // 2 CTRL-G: include buffer number - { - vim_snprintf(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum); - p = buffer + STRLEN(buffer); - } - else - p = buffer; + bufferlen = vim_snprintf_safelen(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum); + + buffer[bufferlen++] = '"'; - *p++ = '"'; - if (buf_spname(curbuf) != NULL) - vim_strncpy((char_u *)p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1); + name = buf_spname(curbuf); + if (name != NULL) + bufferlen += vim_snprintf_safelen(buffer + bufferlen, + IOSIZE - bufferlen, "%s", name); else { if (!fullname && curbuf->b_fname != NULL) name = curbuf->b_fname; else name = curbuf->b_ffname; - home_replace(shorthelp ? curbuf : NULL, name, (char_u *)p, - (int)(IOSIZE - (p - buffer)), TRUE); + home_replace(shorthelp ? curbuf : NULL, name, (char_u *)buffer + bufferlen, + IOSIZE - (int)bufferlen, TRUE); + bufferlen += STRLEN(buffer + bufferlen); } - vim_snprintf_add(buffer, IOSIZE, "\"%s%s%s%s%s%s", - curbufIsChanged() ? (shortmess(SHM_MOD) - ? " [+]" : _(" [Modified]")) : " ", - (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf) - ? _("[Not edited]") : "", - (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf) - ? new_file_message() : "", - (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "", - curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]") - : _("[readonly]")) : "", - (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK) - || curbuf->b_p_ro) ? - " " : ""); - // With 32 bit longs and more than 21,474,836 lines multiplying by 100 - // causes an overflow, thus for large numbers divide instead. - if (curwin->w_cursor.lnum > 1000000L) - n = (int)(((long)curwin->w_cursor.lnum) / - ((long)curbuf->b_ml.ml_line_count / 100L)); - else - n = (int)(((long)curwin->w_cursor.lnum * 100L) / - (long)curbuf->b_ml.ml_line_count); + bufferlen += vim_snprintf_safelen( + buffer + bufferlen, + IOSIZE - bufferlen, + "\"%s%s%s%s%s%s", + curbufIsChanged() ? (shortmess(SHM_MOD) + ? " [+]" : _(" [Modified]")) : " ", + (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf) + ? _("[Not edited]") : "", + (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf) + ? new_file_message() : "", + (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "", curbuf->b_p_ro + ? (shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")) : "", + (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK) || curbuf->b_p_ro) + ? " " : ""); + if (curbuf->b_ml.ml_flags & ML_EMPTY) - vim_snprintf_add(buffer, IOSIZE, "%s", _(no_lines_msg)); + bufferlen += vim_snprintf_safelen(buffer + bufferlen, + IOSIZE - bufferlen, "%s", _(no_lines_msg)); else if (p_ru) // Current line and column are already on the screen -- webb - vim_snprintf_add(buffer, IOSIZE, - NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--", - curbuf->b_ml.ml_line_count), - (long)curbuf->b_ml.ml_line_count, n); + bufferlen += vim_snprintf_safelen( + buffer + bufferlen, + IOSIZE - bufferlen, + NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--", curbuf->b_ml.ml_line_count), + (long)curbuf->b_ml.ml_line_count, + calc_percentage(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count)); else { - vim_snprintf_add(buffer, IOSIZE, - _("line %ld of %ld --%d%%-- col "), - (long)curwin->w_cursor.lnum, - (long)curbuf->b_ml.ml_line_count, - n); + bufferlen += vim_snprintf_safelen( + buffer + bufferlen, + IOSIZE - bufferlen, + _("line %ld of %ld --%d%%-- col "), + (long)curwin->w_cursor.lnum, + (long)curbuf->b_ml.ml_line_count, + calc_percentage(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count)); + validate_virtcol(); - len = STRLEN(buffer); - (void)col_print((char_u *)buffer + len, IOSIZE - len, + bufferlen += col_print((char_u *)buffer + bufferlen, IOSIZE - bufferlen, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); } - (void)append_arg_number(curwin, (char_u *)buffer, IOSIZE, - !shortmess(SHM_FILE)); + (void)append_arg_number(curwin, (char_u *)buffer + bufferlen, + IOSIZE - bufferlen, !shortmess(SHM_FILE)); if (dont_truncate) { + int n; + // Temporarily set msg_scroll to avoid the message being truncated. // First call msg_start() to get the message in the right place. msg_start(); @@ -3937,7 +3949,7 @@ fileinfo( } else { - p = msg_trunc_attr(buffer, FALSE, 0); + char *p = msg_trunc_attr(buffer, FALSE, 0); if (restart_edit != 0 || (msg_scrolled && !need_wait_return)) // Need to repeat the message after redrawing when: // - When restart_edit is set (otherwise there will be a delay @@ -3958,9 +3970,9 @@ col_print( int vcol) { if (col == vcol) - return vim_snprintf((char *)buf, buflen, "%d", col); + return (int)vim_snprintf_safelen((char *)buf, buflen, "%d", col); - return vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol); + return (int)vim_snprintf_safelen((char *)buf, buflen, "%d-%d", col, vcol); } static char_u *lasttitle = NULL; @@ -3972,14 +3984,11 @@ static char_u *lasticon = NULL; void maketitle(void) { - char_u *p; char_u *title_str = NULL; char_u *icon_str = NULL; - int maxlen = 0; - int len; int mustset; char_u buf[IOSIZE]; - int off; + size_t buflen = 0; if (!redrawing()) { @@ -3994,6 +4003,8 @@ maketitle(void) if (p_title) { + int maxlen = 0; + if (p_titlelen > 0) { maxlen = p_titlelen * Columns / 100; @@ -4012,51 +4023,90 @@ maketitle(void) else #endif title_str = p_titlestring; + buflen = STRLEN(title_str); } else { - // format: "fname + (path) (1 of 2) - VIM" + char_u *p; + + // format: "<filename> [flags] <(path)> [argument info] <- servername>" + // example: + // buffer.c + (/home/vim/src) (1 of 2) - VIM + + // reserve some space for different parts of the title. + // use sizeof() to introduce 'size_t' so we don't have to + // cast sizes to it. +#define SPACE_FOR_FNAME (sizeof(buf) - 100) +#define SPACE_FOR_DIR (sizeof(buf) - 20) +#define SPACE_FOR_ARGNR (sizeof(buf) - 10) // at least room for " - VIM" -#define SPACE_FOR_FNAME (IOSIZE - 100) -#define SPACE_FOR_DIR (IOSIZE - 20) -#define SPACE_FOR_ARGNR (IOSIZE - 10) // at least room for " - VIM" + // file name if (curbuf->b_fname == NULL) - vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME); + buflen = vim_snprintf_safelen((char *)buf, + SPACE_FOR_FNAME, "%s", _("[No Name]")); #ifdef FEAT_TERMINAL else if (curbuf->b_term != NULL) - { - vim_strncpy(buf, term_get_status_text(curbuf->b_term), - SPACE_FOR_FNAME); - } + buflen = vim_snprintf_safelen((char *)buf, + SPACE_FOR_FNAME, "%s", + term_get_status_text(curbuf->b_term)); #endif else { - p = transstr(gettail(curbuf->b_fname)); - if (p != NULL) - { - vim_strncpy(buf, p, SPACE_FOR_FNAME); - vim_free(p); - } - else - STRCPY(buf, ""); + buflen = vim_snprintf_safelen((char *)buf, + SPACE_FOR_FNAME, "%s", + ((p = transstr(gettail(curbuf->b_fname))) != NULL) + ? p + : (char_u *)""); + vim_free(p); } + // flags #ifdef FEAT_TERMINAL if (curbuf->b_term == NULL) #endif + { switch (bufIsChanged(curbuf) + (curbuf->b_p_ro * 2) + (!curbuf->b_p_ma * 4)) { - case 1: STRCAT(buf, " +"); break; - case 2: STRCAT(buf, " ="); break; - case 3: STRCAT(buf, " =+"); break; + case 1: + // file was modified + buflen += vim_snprintf_safelen( + (char *)buf + buflen, + sizeof(buf) - buflen, " +"); + break; + case 2: + // file is readonly + buflen += vim_snprintf_safelen( + (char *)buf + buflen, + sizeof(buf) - buflen, " ="); + break; + case 3: + // file was modified and is readonly + buflen += vim_snprintf_safelen( + (char *)buf + buflen, + sizeof(buf) - buflen, " =+"); + break; case 4: - case 6: STRCAT(buf, " -"); break; + case 6: + // file cannot be modified + buflen += vim_snprintf_safelen( + (char *)buf + buflen, + sizeof(buf) - buflen, " -"); + break; case 5: - case 7: STRCAT(buf, " -+"); break; + case 7: + // file cannot be modified but was modified + buflen += vim_snprintf_safelen( + (char *)buf + buflen, + sizeof(buf) - buflen, " -+"); + break; + default: + break; } + } + // path (surrounded by '()') if (curbuf->b_fname != NULL #ifdef FEAT_TERMINAL && curbuf->b_term == NULL @@ -4064,64 +4114,69 @@ maketitle(void) ) { // Get path of file, replace home dir with ~ - off = (int)STRLEN(buf); - buf[off++] = ' '; - buf[off++] = '('; + buflen += vim_snprintf_safelen((char *)buf + buflen, + sizeof(buf) - buflen, " ("); + home_replace(curbuf, curbuf->b_ffname, - buf + off, SPACE_FOR_DIR - off, TRUE); + buf + buflen, (int)(SPACE_FOR_DIR - buflen), TRUE); + #ifdef BACKSLASH_IN_FILENAME // avoid "c:/name" to be reduced to "c" - if (SAFE_isalpha(buf[off]) && buf[off + 1] == ':') - off += 2; + if (SAFE_isalpha(buf[buflen]) && buf[buflen + 1] == ':') + buflen += 2; // step over "c:" #endif - // remove the file name - p = gettail_sep(buf + off); - if (p == buf + off) + + // determine if we have a help or normal buffer + p = gettail_sep(buf + buflen); + if (p == buf + buflen) { - // must be a help buffer - vim_strncpy(buf + off, (char_u *)_("help"), - (size_t)(SPACE_FOR_DIR - off - 1)); + // help buffer + buflen += vim_snprintf_safelen((char *)buf + buflen, + SPACE_FOR_DIR - buflen, "%s)", _("help")); } else - *p = NUL; - - // Translate unprintable chars and concatenate. Keep some - // room for the server name. When there is no room (very long - // file name) use (...). - if (off < SPACE_FOR_DIR) { - p = transstr(buf + off); - if (p != NULL) + // normal buffer + + // Translate unprintable chars and concatenate. Keep some + // room for the server name. When there is no room (very long + // file name) use (...). + if (buflen < SPACE_FOR_DIR) { - vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off)); + // remove the file name + *p = NUL; + + buflen += vim_snprintf_safelen((char *)buf + buflen, + SPACE_FOR_DIR - buflen, "%s)", + ((p = transstr(buf + buflen)) != NULL) + ? p + : (char_u *)""); vim_free(p); } + else + buflen += vim_snprintf_safelen((char *)buf + buflen, + SPACE_FOR_ARGNR - buflen, "...)"); } - else - { - vim_strncpy(buf + off, (char_u *)"...", - (size_t)(SPACE_FOR_ARGNR - off)); - } - STRCAT(buf, ")"); } - append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE); + // argument info + buflen += append_arg_number(curwin, buf + buflen, + SPACE_FOR_ARGNR - buflen, FALSE); + // servername + buflen += vim_snprintf_safelen((char *)buf + buflen, + sizeof(buf) - buflen, " - %s", #if defined(FEAT_CLIENTSERVER) - if (serverName != NULL) - { - STRCAT(buf, " - "); - vim_strcat(buf, serverName, IOSIZE); - } - else + (serverName != NULL) + ? serverName : #endif - STRCAT(buf, " - VIM"); + (char_u *)"VIM"); if (maxlen > 0) { // make it shorter by removing a bit in the middle if (vim_strsize(buf) > maxlen) - trunc_string(buf, buf, maxlen, IOSIZE); + trunc_string(buf, buf, maxlen, sizeof(buf)); } } } @@ -4142,22 +4197,23 @@ maketitle(void) } else { - if (buf_spname(curbuf) != NULL) - p = buf_spname(curbuf); - else // use file name only in icon - p = gettail(curbuf->b_ffname); - *icon_str = NUL; + char_u *name; + int namelen; + + name = buf_spname(curbuf); + if (name == NULL) + name = gettail(curbuf->b_ffname); // Truncate name at 100 bytes. - len = (int)STRLEN(p); - if (len > 100) + namelen = (int)STRLEN(name); + if (namelen > 100) { - len -= 100; + namelen -= 100; if (has_mbyte) - len += (*mb_tail_off)(p, p + len) + 1; - p += len; + namelen += (*mb_tail_off)(name, name + namelen) + 1; + name += namelen; } - STRCPY(icon_str, p); - trans_characters(icon_str, IOSIZE); + STRCPY(buf, name); + trans_characters(buf, sizeof(buf)); } } @@ -4270,18 +4326,15 @@ build_stl_str_hl( { linenr_T lnum; colnr_T len; + size_t outputlen; // length of out[] used (excluding the NUL) char_u *p; char_u *s; - char_u *t; int byteval; #ifdef FEAT_EVAL int use_sandbox; - win_T *save_curwin; - buf_T *save_curbuf; int save_VIsual_active; #endif int empty_line; - colnr_T virtcol; long l; long n; int prevchar_isflag; @@ -4293,8 +4346,6 @@ build_stl_str_hl( int width; int itemcnt; int curitem; - int group_end_userhl; - int group_start_userhl; int groupdepth; #ifdef FEAT_EVAL int evaldepth; @@ -4306,7 +4357,6 @@ build_stl_str_hl( char_u opt; #define TMPLEN 70 char_u buf_tmp[TMPLEN]; - char_u win_tmp[TMPLEN]; char_u *usefmt = fmt; stl_hlrec_T *sp; int save_redraw_not_allowed = redraw_not_allowed; @@ -4429,7 +4479,7 @@ build_stl_str_hl( sizeof(int) * new_len); if (new_separator_locs == NULL) break; - stl_separator_locations = new_separator_locs;; + stl_separator_locations = new_separator_locs; stl_items_len = new_len; } @@ -4478,6 +4528,8 @@ build_stl_str_hl( } if (*s == ')') { + char_u *t; + s++; if (groupdepth < 1) continue; @@ -4489,9 +4541,11 @@ build_stl_str_hl( if (curitem > stl_groupitem[groupdepth] + 1 && stl_items[stl_groupitem[groupdepth]].stl_minwid == 0) { + int group_start_userhl = 0; + int group_end_userhl = 0; + // remove group if all items are empty and highlight group // doesn't change - group_start_userhl = group_end_userhl = 0; for (n = stl_groupitem[groupdepth] - 1; n >= 0; n--) { if (stl_items[n].stl_type == Highlight) @@ -4693,12 +4747,16 @@ build_stl_str_hl( case STL_FILEPATH: case STL_FULLPATH: case STL_FILENAME: + { + char_u *name; + fillable = FALSE; // don't change ' ' to fillchar - if (buf_spname(wp->w_buffer) != NULL) - vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1); + name = buf_spname(wp->w_buffer); + if (name != NULL) + vim_strncpy(NameBuff, name, MAXPATHL - 1); else { - t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname + char_u *t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname : wp->w_buffer->b_fname; home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE); } @@ -4708,13 +4766,17 @@ build_stl_str_hl( else str = gettail(NameBuff); break; + } case STL_VIM_EXPR: // '{' { #ifdef FEAT_EVAL - char_u *block_start = s - 1; + char_u *block_start = s - 1; #endif - int reevaluate = (*s == '%'); + int reevaluate = (*s == '%'); + char_u *t; + buf_T *save_curbuf; + win_T *save_curwin; if (reevaluate) s++; @@ -4727,16 +4789,16 @@ build_stl_str_hl( break; s++; if (reevaluate) - p[-1] = 0; // remove the % at the end of %{% expr %} + p[-1] = NUL; // remove the % at the end of %{% expr %} else - *p = 0; + *p = NUL; p = t; #ifdef FEAT_EVAL vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "%d", curbuf->b_fnum); set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp); - vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->w_id); - set_internal_string_var((char_u *)"g:actual_curwin", win_tmp); + vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "%d", curwin->w_id); + set_internal_string_var((char_u *)"g:actual_curwin", buf_tmp); save_curbuf = curbuf; save_curwin = curwin; @@ -4755,7 +4817,7 @@ build_stl_str_hl( do_unlet((char_u *)"g:actual_curbuf", TRUE); do_unlet((char_u *)"g:actual_curwin", TRUE); - if (str != NULL && *str != 0) + if (str != NULL && *str != NUL) { if (*skipdigits(str) == NUL) { @@ -4767,30 +4829,19 @@ build_stl_str_hl( // If the output of the expression needs to be evaluated // replace the %{} block with the result of evaluation - if (reevaluate && str != NULL && *str != 0 + if (reevaluate && str != NULL && *str != NUL && strchr((const char *)str, '%') != NULL && evaldepth < MAX_STL_EVAL_DEPTH) { size_t parsed_usefmt = (size_t)(block_start - usefmt); - size_t str_length = strlen((const char *)str); - size_t fmt_length = strlen((const char *)s); - size_t new_fmt_len = parsed_usefmt - + str_length + fmt_length + 3; - char_u *new_fmt = (char_u *)alloc(new_fmt_len * sizeof(char_u)); + size_t new_fmt_len = (parsed_usefmt + + STRLEN(str) + STRLEN(s) + 3) * sizeof(char_u); + char_u *new_fmt = (char_u *)alloc(new_fmt_len); if (new_fmt != NULL) { - char_u *new_fmt_p = new_fmt; - - new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, parsed_usefmt) - + parsed_usefmt; - new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length) - + str_length; - new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2; - new_fmt_p = (char_u *)memcpy(new_fmt_p , s, fmt_length) - + fmt_length; - *new_fmt_p = 0; - new_fmt_p = NULL; + vim_snprintf((char *)new_fmt, new_fmt_len, "%.*s%s%s%s", + (int)parsed_usefmt, usefmt, str, "%}", s); if (usefmt != fmt) vim_free(usefmt); @@ -4820,7 +4871,9 @@ build_stl_str_hl( case STL_VIRTCOL: case STL_VIRTCOL_ALT: - virtcol = wp->w_virtcol + 1; + { + colnr_T virtcol = wp->w_virtcol + 1; + // Don't display %V if it's the same as %c. if (opt == STL_VIRTCOL_ALT && (virtcol == (colnr_T)((State & MODE_INSERT) == 0 @@ -4828,10 +4881,10 @@ build_stl_str_hl( break; num = (long)virtcol; break; + } case STL_PERCENTAGE: - num = (int)(((long)wp->w_cursor.lnum * 100L) / - (long)wp->w_buffer->b_ml.ml_line_count); + num = calc_percentage((long)wp->w_cursor.lnum, (long)wp->w_buffer->b_ml.ml_line_count); break; case STL_ALTPERCENT: @@ -4846,8 +4899,8 @@ build_stl_str_hl( case STL_ARGLISTSTAT: fillable = FALSE; - buf_tmp[0] = 0; - if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), FALSE)) + buf_tmp[0] = NUL; + if (append_arg_number(wp, buf_tmp, sizeof(buf_tmp), FALSE) > 0) str = buf_tmp; break; @@ -4921,6 +4974,8 @@ build_stl_str_hl( if (*wp->w_buffer->b_p_ft != NUL && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) { + char_u *t; + vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s", wp->w_buffer->b_p_ft); for (t = buf_tmp; *t != 0; t++) @@ -4963,26 +5018,30 @@ build_stl_str_hl( break; case STL_HIGHLIGHT: - t = s; - while (*s != '#' && *s != NUL) - ++s; - if (*s == '#') { - stl_items[curitem].stl_type = Highlight; - stl_items[curitem].stl_start = p; - stl_items[curitem].stl_minwid = -syn_namen2id(t, (int)(s - t)); - curitem++; + char_u *t = s; + + while (*s != '#' && *s != NUL) + ++s; + if (*s == '#') + { + stl_items[curitem].stl_type = Highlight; + stl_items[curitem].stl_start = p; + stl_items[curitem].stl_minwid = -syn_namen2id(t, (int)(s - t)); + curitem++; + } + if (*s != NUL) + ++s; + continue; } - if (*s != NUL) - ++s; - continue; } stl_items[curitem].stl_start = p; stl_items[curitem].stl_type = Normal; if (str != NULL && *str) { - t = str; + char_u *t = str; + if (itemisflag) { if ((t[0] && t[1]) @@ -5037,13 +5096,13 @@ build_stl_str_hl( } else if (num >= 0) { - int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); - char_u nstr[20]; + int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); + char_u nstr[20]; + char_u *t = nstr; if (p + 20 >= out + outlen) break; // not sufficient space prevchar_isitem = TRUE; - t = nstr; if (opt == STL_VIRTCOL_ALT) { *t++ = '-'; @@ -5054,12 +5113,13 @@ build_stl_str_hl( *t++ = '0'; *t++ = '*'; *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd'); - *t = 0; + *t = NUL; for (n = num, l = 1; n >= nbase; n /= nbase) l++; if (opt == STL_VIRTCOL_ALT) l++; + if (l > maxwid) { l += 2; @@ -5069,14 +5129,13 @@ build_stl_str_hl( *t++ = '>'; *t++ = '%'; *t = t[-3]; - *++t = 0; - vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, - 0, num, n); + *++t = NUL; + p += vim_snprintf_safelen((char *)p, outlen - (p - out), + (char *)nstr, 0, num, n); } else - vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, - minwid, num); - p += STRLEN(p); + p += vim_snprintf_safelen((char *)p, outlen - (p - out), + (char *)nstr, minwid, num); } else stl_items[curitem].stl_type = Empty; @@ -5089,6 +5148,7 @@ build_stl_str_hl( curitem++; } *p = NUL; + outputlen = (size_t)(p - out); itemcnt = curitem; #ifdef FEAT_EVAL @@ -5145,10 +5205,12 @@ build_stl_str_hl( break; itemcnt = l; *s++ = '>'; - *s = 0; + *s = NUL; } else { + char_u *end = out + outputlen; + if (has_mbyte) { n = 0; @@ -5161,7 +5223,8 @@ build_stl_str_hl( else n = width - maxwidth + 1; p = s + n; - STRMOVE(s + 1, p); + mch_memmove(s + 1, p, (size_t)(end - p) + 1); // +1 for NUL + end -= (size_t)(p - (s + 1)); *s = '<'; --n; // count the '<' @@ -5176,14 +5239,15 @@ build_stl_str_hl( // Fill up for half a double-wide character. while (++width < maxwidth) { - s = s + STRLEN(s); + s = end; MB_CHAR2BYTES(fillchar, s); *s = NUL; + end = s; } } width = maxwidth; } - else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen) + else if (width < maxwidth && outputlen + maxwidth - width + 1 < outlen) { // Find how many separators there are, which we will use when // figuring out how many groups there are. @@ -5284,7 +5348,7 @@ build_stl_str_hl( #endif // FEAT_STL_OPT /* - * Get relative cursor position in window into "buf[buflen]", in the localized + * Get relative cursor position in window into "buf[]", in the localized * percentage form like %99, 99%; using "Top", "Bot" or "All" when appropriate. */ int @@ -5295,7 +5359,6 @@ get_rel_pos( { long above; // number of lines above window long below; // number of lines below window - int len; if (buflen < 3) // need at least 3 chars for writing return 0; @@ -5309,42 +5372,31 @@ get_rel_pos( #endif below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; if (below <= 0) - len = vim_snprintf((char *)buf, buflen, "%s", (above == 0) ? _("All") : _("Bot")); - else if (above <= 0) - len = vim_snprintf((char *)buf, buflen, "%s", _("Top")); - else - { - int perc = (above > 1000000L) - ? (int)(above / ((above + below) / 100L)) - : (int)(above * 100L / (above + below)); + return (int)vim_snprintf_safelen((char *)buf, buflen, + "%s", (above == 0) ? _("All") : _("Bot")); - // localized percentage value - len = vim_snprintf((char *)buf, buflen, _("%s%d%%"), (perc < 10) ? " " : "", perc); - } - if (len < 0) - { - buf[0] = NUL; - len = 0; - } - else if (len > buflen - 1) - len = buflen - 1; + if (above <= 0) + return (int)vim_snprintf_safelen((char *)buf, buflen, + "%s", _("Top")); - return len; + // localized percentage value + return (int)vim_snprintf_safelen((char *)buf, buflen, + _("%2d%%"), calc_percentage(above, above + below)); } /* - * Append (file 2 of 8) to "buf[buflen]", if editing more than one file. - * Return TRUE if it was appended. + * Append (file 2 of 8) to "buf[]", if editing more than one file. + * Return the number of characters appended. */ static int append_arg_number( win_T *wp, char_u *buf, - int buflen, + size_t buflen, int add_file) // Add "file" before the arg number { if (ARGCOUNT <= 1) // nothing to do - return FALSE; + return 0; char *msg; switch ((wp->w_arg_idx_invalid ? 1 : 0) + (add_file ? 2 : 0)) @@ -5355,10 +5407,8 @@ append_arg_number( case 3: msg = _(" (file (%d) of %d)"); break; } - char_u *p = buf + STRLEN(buf); // go to the end of the buffer - vim_snprintf((char *)p, (size_t)(buflen - (p - buf)), msg, + return (int)vim_snprintf_safelen((char *)buf, buflen, msg, wp->w_arg_idx + 1, ARGCOUNT); - return TRUE; } /* @@ -5698,17 +5748,16 @@ chk_modeline( int flags) // Same as for do_modelines(). { char_u *s; + char_u *line_end; // point to the end of the line char_u *e; - char_u *linecopy; // local copy of any modeline found int prev; - int vers; - int end; int retval = OK; - sctx_T save_current_sctx; ESTACK_CHECK_DECLARATION; prev = -1; - for (s = ml_get(lnum); *s != NUL; ++s) + s = ml_get(lnum); + line_end = s + ml_get_len(lnum); + for (; *s != NUL; ++s) { if (prev == -1 || vim_isspace(prev)) { @@ -5718,6 +5767,8 @@ chk_modeline( // Accept both "vim" and "Vim". if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm') { + int vers; + if (s[3] == '<' || s[3] == '=' || s[3] == '>') e = s + 4; else @@ -5739,14 +5790,23 @@ chk_modeline( if (*s) { + size_t len; + char_u *linecopy; // local copy of any modeline found + int end; + do // skip over "ex:", "vi:" or "vim:" ++s; while (s[-1] != ':'); - s = linecopy = vim_strsave(s); // copy the line, it will change + len = (size_t)(line_end - s); // remember the line length + // so we can restore 'line_end' + // after the copy + s = linecopy = vim_strnsave(s, len); // copy the line, it will change if (linecopy == NULL) return FAIL; + line_end = s + len; // restore 'line_end' + // prepare for emsg() estack_push(ETYPE_MODELINE, (char_u *)"modelines", lnum); ESTACK_CHECK_SETUP; @@ -5764,7 +5824,10 @@ chk_modeline( */ for (e = s; *e != ':' && *e != NUL; ++e) if (e[0] == '\' && e[1] == ':') - STRMOVE(e, e + 1); + { + mch_memmove(e, e + 1, (size_t)(line_end - (e + 1)) + 1); // +1 for NUL + --line_end; + } if (*e == NUL) end = TRUE; @@ -5781,15 +5844,15 @@ chk_modeline( if (*e != ':') // no terminating ':'? break; end = TRUE; - s = vim_strchr(s, ' ') + 1; + s += (*(s + 2) == ' ') ? 3 : 4; } *e = NUL; // truncate the set command if (*s != NUL) // skip over an empty "::" { int secure_save = secure; + sctx_T save_current_sctx = current_sctx; - save_current_sctx = current_sctx; current_sctx.sc_version = 1; #ifdef FEAT_EVAL current_sctx.sc_sid = SID_MODELINE; @@ -5807,7 +5870,8 @@ chk_modeline( if (retval == FAIL) // stop if error found break; } - s = e + 1; // advance to next part + s = (e == line_end) ? e : e + 1; // advance to next part + // careful not to go off the end } ESTACK_CHECK_NOW; diff --git a/src/proto.h b/src/proto.h index f04ba0525..a5ca9e4e2 100644 --- a/src/proto.h +++ b/src/proto.h @@ -140,6 +140,7 @@ void siemsg(const char *, ...) ATTRIBUTE_COLD ATTRIBUTE_FORMAT_PRINTF(1, 2); int vim_snprintf_add(char *, size_t, const char *, ...) ATTRIBUTE_FORMAT_PRINTF(3, 4); int vim_snprintf(char *, size_t, const char *, ...) ATTRIBUTE_FORMAT_PRINTF(3, 4); +size_t vim_snprintf_safelen(char *, size_t, const char *, ...) ATTRIBUTE_FORMAT_PRINTF(3, 4); int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) ATTRIBUTE_FORMAT_PRINTF(3, 0); diff --git a/src/strings.c b/src/strings.c index d6f1b3823..e1d23e387 100644 --- a/src/strings.c +++ b/src/strings.c @@ -2487,6 +2487,33 @@ vim_snprintf(char *str, size_t str_m, const char *fmt, ...) return str_l; } +/* + * Like vim_snprintf() except the return value can be safely used to increment a + * buffer length. + * Normal `snprintf()` (and `vim_snprintf()`) returns the number of bytes that + * would have been copied if the destination buffer was large enough. + * This means that you cannot rely on it's return value for the destination + * length because the destination may be shorter than the source. This function + * guarantees the returned length will never be greater than the destination length. + */ + size_t +vim_snprintf_safelen(char *str, size_t str_m, const char *fmt, ...) +{ + va_list ap; + int str_l; + + va_start(ap, fmt); + str_l = vim_vsnprintf(str, str_m, fmt, ap); + va_end(ap); + + if (str_l < 0) + { + *str = NUL; + return 0; + } + return ((size_t)str_l >= str_m) ? str_m - 1 : (size_t)str_l; +} + int vim_vsnprintf( char *str, diff --git a/src/version.c b/src/version.c index 4609244f5..e500aa19e 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 */ +/**/ + 1291, /**/ 1290, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1u2xpf-00CgLA-Ku%40256bit.org.