diff options
| author | zeertzjq <zeertzjq@outlook.com> | 2026-04-23 13:41:43 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-23 05:41:43 +0000 |
| commit | a4ad469fb1f935aed6f84cfa9e663ab4f7ca1e02 (patch) | |
| tree | 28311a01f3d5759667f4879d5cf3bb60f8c6d95c | |
| parent | db2f6a8a918f33abf10959949fb9e2a2f82dae4f (diff) | |
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
https://github.com/vim/vim/commit/8d23fcb603d8f8938ce0023086326a5db6780ea2
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
| -rw-r--r-- | src/nvim/insexpand.c | 3 | ||||
| -rw-r--r-- | src/nvim/regexp.c | 2 | ||||
| -rw-r--r-- | src/nvim/spell.c | 4 | ||||
| -rw-r--r-- | src/nvim/spellfile.c | 2 |
4 files changed, 7 insertions, 4 deletions
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 964c2517d6..97b84a0e8b 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -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++) { diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 142777b94a..247fc9e5d9 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -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; } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index a5ac2d46dd..91727c8c5c 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -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); diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index ab4f16eb3e..021a891eee 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -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; } |
