vim-patch:partial:9.2.0315: missing bound-checks (#39334)

Problem:  missing bound-checks
Solution: Add defensive guards against potential buffer overflow
          (Yasuhiro Matsumoto)

Add bounds checking and integer overflow guards across multiple files
as a defensive measure. While these code paths are unlikely to be
exploitable in practice, the guards prevent undefined behavior in
edge cases.

- libvterm/vterm.c: use heap tmpbuffer instead of stack buffer in
  vsprintf() fallback path
- channel.c: validate len in channel_consume() before mch_memmove()
- spell.c: use long instead of int for addlen to avoid signed overflow
  in size_t subtraction
- alloc.c: add SIZE_MAX overflow check in ga_grow_inner() before
  itemsize multiplication
- list.c: add overflow check before count * sizeof(listitem_T)
- popupwin.c: add overflow check before width * height allocation
- insexpand.c: add overflow check before compl_num_bests multiplication
- regexp_bt.c: replace sprintf() with vim_snprintf() in regprop()
- spellfile.c: use SIZE_MAX instead of LONG_MAX for allocation overflow
  check

closes: vim/vim#19904

8d23fcb603

Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
This commit is contained in:
zeertzjq
2026-04-23 13:41:43 +08:00
committed by GitHub
parent db2f6a8a91
commit a4ad469fb1
4 changed files with 7 additions and 4 deletions

View File

@@ -3974,6 +3974,9 @@ static void fuzzy_longest_match(void)
return;
}
if ((size_t)compl_num_bests > SIZE_MAX / sizeof(compl_T *)) {
return;
}
compl_best_matches = (compl_T **)xmalloc((size_t)compl_num_bests * sizeof(compl_T *));
for (int i = 0; compl != NULL && i < compl_num_bests; i++) {

View File

@@ -8287,7 +8287,7 @@ static uint8_t *regprop(uint8_t *op)
break;
}
if (p != NULL) {
STRCPY(buf + buflen, p);
xstrlcpy(buf + buflen, p, sizeof(buf) - buflen);
}
return (uint8_t *)buf;
}

View File

@@ -2650,7 +2650,7 @@ void ex_spellrepall(exarg_T *eap)
}
const size_t repl_from_len = strlen(repl_from);
const size_t repl_to_len = strlen(repl_to);
const int addlen = (int)(repl_to_len - repl_from_len);
const int64_t addlen = (int64_t)repl_to_len - (int64_t)repl_from_len;
const size_t frompatsize = repl_from_len + 7;
char *frompat = xmalloc(frompatsize);
@@ -2671,7 +2671,7 @@ void ex_spellrepall(exarg_T *eap)
char *line = get_cursor_line_ptr();
if (addlen <= 0
|| strncmp(line + curwin->w_cursor.col, repl_to, repl_to_len) != 0) {
char *p = xmalloc((size_t)get_cursor_line_len() + (size_t)addlen + 1);
char *p = xmalloc((size_t)(get_cursor_line_len() + addlen) + 1);
memmove(p, line, (size_t)curwin->w_cursor.col);
STRCPY(p + curwin->w_cursor.col, repl_to);
strcat(p, line + curwin->w_cursor.col + repl_from_len);

View File

@@ -1670,7 +1670,7 @@ static int spell_read_tree(FILE *fd, uint8_t **bytsp, int *bytsp_len, idx_T **id
if (len < 0) {
return SP_TRUNCERROR;
}
if ((size_t)len >= SIZE_MAX / sizeof(int)) {
if ((size_t)len > SIZE_MAX / sizeof(int)) {
// Invalid length, multiply with sizeof(int) would overflow.
return SP_FORMERROR;
}