fix(coverity): false positives in kvec usages #41341

Coverity can't follow kv_ensure_space()'s `kv_roundup32()` bit math, so
every kv_concat_len() looks like an overrun; and it doesn't know
`kv_push()` allocates when `size == capacity`.

    _____________________________________________________________________________________________
    CID 653191:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 3536             in paste_store()
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    >>>     CID 653191:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "recordbuff.items" at offset corresponding to index variable "recordbuff.size" through dereference in call to "memcpy".
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }
    3539
    3540         if (s < str_end) {
    3541           int c = (uint8_t)(*s++);

    _____________________________________________________________________________________________
    CID 653190:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 730             in redo_append_spec()
    724         return;
    725       }
    726
    727       while (*s != NUL) {
    728         if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
    729           // Insert special key literally.
    >>>     CID 653190:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    730           kv_concat_len(redobuff.cur.keys, s, 3);
    731           s += 3;
    732         } else {
    733           sb_add_char(&redobuff.cur.keys, mb_cptr2char_adv(&s));
    734         }
    735       }

    CID 653189:         (OVERRUN)
    /src/nvim/input.c: 3533           in paste_store()
    /src/nvim/input.c: 3536           in paste_store()

    _____________________________________________________________________________________________
    CID 653189:           (OVERRUN)
    /src/nvim/input.c: 3533             in paste_store()
    3527                && *s != NL && !(crlf && *s == CAR)) {
    3528           s++;
    3529         }
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    >>>     CID 653189:           (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }
    /src/nvim/input.c: 3536             in paste_store()
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    >>>     CID 653189:           (OVERRUN)
    >>>     Overrunning dynamic array "recordbuff.items" at offset corresponding to index variable "recordbuff.size" through dereference in call to "memcpy".
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }
    3539
    3540         if (s < str_end) {
    3541           int c = (uint8_t)(*s++);

    _____________________________________________________________________________________________
    CID 653188:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input_cmdatom.c: 216             in atoms_concat_keys()
    210
    211     /// Concatenates the keys of multiple atoms into one (allocated) string.
    212     static String atoms_concat_keys(CmdAtomVec atoms)
    213     {
    214       StringBuilder keys = KV_INITIAL_VALUE;
    215       for (size_t i = 0; i < kv_size(atoms); i++) {
    >>>     CID 653188:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "keys.items" at offset corresponding to index variable "keys.size" through dereference in call to "memcpy".
    216         kv_concat(keys, kv_A(atoms, i).keys);
    217       }
    218       size_t len = kv_size(keys);
    219       kv_push(keys, NUL);
    220       return (String){ .data = keys.items, .size = len };
    221     }

    CID 653187:       Null pointer dereferences  (FORWARD_NULL)

    _____________________________________________________________________________________________
    CID 653186:         Null pointer dereferences  (FORWARD_NULL)
    /src/nvim/input_cmdatom.c: 173             in atom_compose_keys()
    167       StringBuilder sb = KV_INITIAL_VALUE;
    168       redo_prefix(&spec, &sb, false);
    169       redo_chars(&spec, &sb, false);
    170       if (sb.size == 0) {
    171         return NULL;
    172       }
    >>>     CID 653186:         Null pointer dereferences  (FORWARD_NULL)
    >>>     Dereferencing null pointer "((sb.size == sb.capacity) ? (sb.capacity = (sb.capacity ? sb.capacity << 1 : 8UL)) , (sb.items = xrealloc(sb.items, 1UL * sb.capacity)) , 0 : 0) , (sb.items + sb.size++)".
    173       kv_push(sb, NUL);
    174       return sb.items;
    175     }
    176
    177     /// The pending change as a CmdAtom: the composed keysequence plus the structured fields.
    178     /// Caller owns `keys`.

    _____________________________________________________________________________________________
    CID 653185:         Null pointer dereferences  (FORWARD_NULL)
    /src/nvim/input.c: 296             in redo_compose()
    290       StringBuilder buf = KV_INITIAL_VALUE;
    291       redo_prefix(&r->spec, &buf, false);
    292       kv_splice(buf, r->keys);
    293       if (buf.size == 0) {
    294         return (String)STRING_INIT;
    295       }
    >>>     CID 653185:         Null pointer dereferences  (FORWARD_NULL)
    >>>     Dereferencing null pointer "((buf.size == buf.capacity) ? (buf.capacity = (buf.capacity ? buf.capacity << 1 : 8UL)) , (buf.items = xrealloc(buf.items, 1UL * buf.capacity)) , 0 : 0) , (buf.items + buf.size++)".
    296       kv_push(buf, NUL);
    297       return cbuf_as_string(buf.items, buf.size - 1);
    298     }
    299
    301     String redo_keys(void)

    _____________________________________________________________________________________________
    CID 653184:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 3533             in paste_store()
    3527                && *s != NL && !(crlf && *s == CAR)) {
    3528           s++;
    3529         }
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    >>>     CID 653184:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }

    _____________________________________________________________________________________________
    CID 653183:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 730             in redo_append_spec()
    724         return;
    725       }
    726
    727       while (*s != NUL) {
    728         if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
    729           // Insert special key literally.
    >>>     CID 653183:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    730           kv_concat_len(redobuff.cur.keys, s, 3);
    731           s += 3;
    732         } else {
    733           sb_add_char(&redobuff.cur.keys, mb_cptr2char_adv(&s));
    734         }
This commit is contained in:
Justin M. Keyes
2026-08-16 11:37:51 -04:00
committed by GitHub
parent 7b6f344627
commit aaf57a053d
3 changed files with 5 additions and 0 deletions

View File

@@ -108,6 +108,8 @@
if (len > 0) { \
kv_ensure_space(v, len); \
assert((v).items); \
/* kv_roundup32() only ORs bits in, so kv_ensure_space() leaves capacity >= size+len. */ \
/* coverity[overrun-buffer-arg] */ \
memcpy((v).items + (v).size, data, sizeof((v).items[0]) * len); \
(v).size = (v).size + len; \
}

View File

@@ -293,6 +293,7 @@ static String redo_compose(RedoBuf *r)
if (buf.size == 0) {
return (String)STRING_INIT;
}
assert(buf.items != NULL); // Coverity false-positive (already checked `size` above).
kv_push(buf, NUL);
return cbuf_as_string(buf.items, buf.size - 1);
}
@@ -865,6 +866,7 @@ int start_redo(int count, bool old_redo)
}
StringBuilder prefix = KV_INITIAL_VALUE;
redo_prefix(&spec, &prefix, true);
// coverity[var_deref_model] `items` is NULL only when size=0, which add_buff() ignores.
add_buff(&readbuf2, prefix.items, (ptrdiff_t)prefix.size);
kv_destroy(prefix);
if (spec.regname == '=') {

View File

@@ -170,6 +170,7 @@ static char *atom_compose_keys(CmdSpec spec)
if (sb.size == 0) {
return NULL;
}
assert(sb.items != NULL); // Coverity false-positive (already checked `size` above).
kv_push(sb, NUL);
return sb.items;
}