aboutsummaryrefslogtreecommitdiff
path: root/src/klib/kvec.h
Commit message (Collapse)AuthorAge
* fix(coverity): kv_ensure_space overflow #42091Justin M. Keyes2026-09-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: gcc and Coverity report potential `size + len `overflow kv_concat_len(). CID 656305: Null pointer dereferences (FORWARD_NULL) /src/nvim/input_cmdatom.c: 474 in atom_push_raw() 468 atom_captures++; 469 } 470 if (collect) { 471 composite.queued = true; 472 } 473 kv_push(vatom.atoms, *atom); >>> CID 656305: Null pointer dereferences (FORWARD_NULL) >>> Dereferencing null pointer "cur_frame". 474 vatom.frame = cur_frame->id; 475 return; 476 } 477 atom_captures++; 478 if (atom->type == kAVisual && kv_size(atom->atoms) > 0) { 479 // The completing operator is the only subatom that could have edited. CID 656304: Memory - illegal accesses (OVERRUN) /src/nvim/input.c: 718 in sb_add_spec() 712 /// bytes. Unlike sb_add_lit(), no CTRL-V: for text read raw (<Cmd>), not typed into a cmdline. 713 void sb_add_spec(StringBuilder *buf, const char *s) 714 { 715 while (*s != NUL) { 716 if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) { 717 // Insert special key literally. >>> CID 656304: Memory - illegal accesses (OVERRUN) >>> Overrunning dynamic array "buf->items" at offset corresponding to index variable "buf->size" through dereference in call to "memcpy". 718 kv_concat_len(*buf, s, 3); 719 s += 3; 720 } else { 721 sb_add_char(buf, mb_cptr2char_adv(&s)); 722 } 723 } Solution: Both are false positives; assert or check to avoid the warnings.
* fix(klib): parenthesize kvec macro argumentsVolodymyr Chernetskyi2026-09-10
| | | | | | | | | | | | | | | Problem: The kvec append and reserve macros do not parenthesize length arguments. Compound expressions can change the allocation and copy sizes, causing buffer overflows for elements larger than one byte. The append macros also expand to bare if statements, making them unsafe to use in unbraced if/else statements. Solution: Parenthesize length and data arguments and wrap both append macros in do/while statements. AI-assisted
* refactor(cmdatom): atom_redo_keys #41345Justin M. Keyes2026-08-16
| | | | Some names/comments are misleading. Also add some asserts.
* fix(coverity): false positives in kvec usages #41341Justin M. Keyes2026-08-16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 }
* refactor: move StringBuilder to types_defs.h (#33745)Gregory Anders2025-05-01
|
* refactor(wininfo): change wininfo from a linked list to an arraybfredl2024-12-16
| | | | | | | | | | "wininfo" is going to be my next victim. The main problem with wininfo is that it is "all or nothing", i e either all state about a buffer in a window is considered valid or none of it is. This needs to be fixed to address some long running grievances. For now this is just a warmup: refactor it from a linked list to a vector.
* feat(lua): pass keys before mapping to vim.on_key() callback (#28098)zeertzjq2024-03-31
| | | Keys before mapping (i.e. typed keys) are passed as the second argument.
* fix(coverity/477623,477624): guard null pointer dereference in kv_concat_len ↵Gregory Anders2024-01-15
| | | | | | | | | | | | (#27022) Coverity warns about a possible null pointer dereference in the `memcpy` call in `kv_concat_len`. The `memcpy` follows `kv_ensure_space` which (re)allocates the `items` pointer if the vector's capacity is not large enough to contain all of the items being appended. The only way `items` would be NULL at this point is if `capacity` were mistakenly set to some large number without `items` ever having being set in the first place. This should not happen when using the kvec API so if this condition is ever false it is a bug, which the `assert` will catch.
* build: don't define FUNC_ATTR_* as empty in headers (#26317)zeertzjq2023-11-30
| | | | | | FUNC_ATTR_* should only be used in .c files with generated headers. Defining FUNC_ATTR_* as empty in headers causes misuses of them to be silently ignored. Instead don't define them by default, and only define them as empty after a .c file has included its generated header.
* build: remove PVSdundargoc2023-11-12
| | | | | | | We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable.
* feat(extmark): support proper multiline rangesbfredl2023-09-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The removes the previous restriction that nvim_buf_set_extmark() could not be used to highlight arbitrary multi-line regions The problem can be summarized as follows: let's assume an extmark with a hl_group is placed covering the region (5,0) to (50,0) Now, consider what happens if nvim needs to redraw a window covering the lines 20-30. It needs to be able to ask the marktree what extmarks cover this region, even if they don't begin or end here. Therefore the marktree needs to be augmented with the information covers a point, not just what marks begin or end there. To do this, we augment each node with a field "intersect" which is a set the ids of the marks which overlap this node, but only if it is not part of the set of any parent. This ensures the number of nodes that need to be explicitly marked grows only logarithmically with the total number of explicitly nodes (and thus the number of of overlapping marks). Thus we can quickly iterate all marks which overlaps any query position by looking up what leaf node contains that position. Then we only need to consider all "start" marks within that leaf node, and the "intersect" set of that node and all its parents. Now, and the major source of complexity is that the tree restructuring operations (to ensure that each node has T-1 <= size <= 2*T-1) also need to update these sets. If a full inner node is split in two, one of the new parents might start to completely overlap some ranges and its ids will need to be moved from its children's sets to its own set. Similarly, if two undersized nodes gets joined into one, it might no longer completely overlap some ranges, and now the children which do needs to have the have the ids in its set instead. And then there are the pivots! Yes the pivot operations when a child gets moved from one parent to another.
* refactor: replace char_u with charDundar Göc2022-11-26
| | | | Work on https://github.com/neovim/neovim/issues/459
* refactor: move klib out of src/nvim/ #20341dundargoc2022-09-25
It's confusing to mix vendored dependencies with neovim source code. A clean separation is simpler to keep track of and simpler to document.