libvec bug tracker
Verified char.c @ 2026-09-28 12:48:04, 3 independent passes.
char.h 108 lines, utils.h 31, utils.c 12, CMakeLists.txt 32, main.c 55.
Line numbers are the only field that drifts. Re-verify before trusting them.
Pass 4 @ 2026-09-28, push_back / pop_back (char.c:67-157), ASan.
Pass 5 @ 2026-09-28, whole file re-read plus 10 harness runs, ASan.
Line count moved 804 to 800 with the create rewrite; re-measured per pass.
Open 79 — 11 S1, 27 S2, 11 S3, 29 C
1 DECIDE · Fixed 12 (listed at the bottom, no rows) · 79 rows
Severity S1 memory safety · S2 wrong result / broken contract ·
S3 edge case · C cleanup · DECIDE open design question
How to read this
Each function is a ### with one table. Rows are sorted by severity (S1 first),
so the worst thing in each function is on top. Fixed findings are not rows —
they are a flat ID list at the bottom of the file.
Tracking state is a column, not a checkbox: a State cell carries more than
"done or not done" — DECIDE has no checkbox equivalent, and it is load-bearing
here. And task-list syntax inside a table cell is renderer-dependent, so a
State column is the form that survives any markdown preview. If your preview
does render checkboxes in tables and you want click-to-toggle, a leading Done
column can be added without disturbing anything else.
Rules
- IDs are permanent. Never reused, never renumbered. An ID leaves the file
only when its row is deleted outright, and only under rule 3.
- Locations drift freely. The only field updated in place.
- False findings are deleted, not archived. If a row turns out to be my own
error, the row is removed. A new ID carries the accurate finding if there is
one. No
DISPUTED state, no corrections log — a tracker is not a diary.
- State is
OPEN / DECIDE. FIXED means the row is gone and its ID is
in the bottom list.
- Fixed findings live in the ID list at the bottom, nothing else.
Triage — the 11 open S1s, in suggested order
| # |
ID |
Location |
Summary |
| 1 |
RS-7 |
char.c:175, 200 |
reserve on a blank vector allocates 1024 but claims 5000. Ordinary size, live overflow |
| 3 |
PB-8 |
char.c:89, 131 |
live heap overflow, 2-line repro |
| 4 |
PB-14 |
char.c:131, 154 |
write through the freed buffer after delete, 2-line repro |
| 5 |
RS-1 |
char.c:180-195 |
use-after-free in reserve's truncation loop, ASan confirmed |
| 6 |
IN-1 |
char.c:783 |
inverted iter_end > iter_start |
| 7 |
IN-2 |
char.c:783 |
dead bounds check sitting behind IN-1 |
| 8 |
DL-1 |
char.c:293, 297 |
const delete, double free on second call |
| 9 |
DL-2 |
char.h:11-17 |
no ownership marker, struct copy double-frees |
| 8 |
UT-2 |
utils.c:3-12 |
error_messages[0] / [1] are NULL |
| 9 |
PB-3 |
char.c:106, 116 |
capacity committed before the realloc check |
| 10 |
PB-15 |
char.c:87, 128-131 |
null-buffer path has no else, so arr == NULL && size > 0 writes to NULL. Defensive |
Two of the eleven are the same class. RS-7 and PB-8 both end in a
write past a small block, and both come from a struct field claiming more
bytes than were allocated: capacity set from the request rather than the
block (RS-7, char.c:200), calloc(1) with capacity untouched (PB-8,
char.c:89). One rule kills both: never write _internal_capacity without
writing the allocation it describes. Verify with a single postcondition —
after any function that touches capacity, the block size and the field must
agree. CR-8 was a third member of this class; it is fixed as of Pass 5, and
create now carries the same postcondition in one place (CR-9, char.c:44).
Fix IN-1 and IN-2 in the same commit. The raw read in the 3-arg overload
is unreachable only because IN-1's inversion empties the loop. Fixing IN-1
alone converts a clean rejection into a live out-of-bounds read, because IN-2's
bound check stays dead behind the short-circuit.
PB-8 and PB-14 are the only two rows in this file with a sanitizer trace
attached. Both reproduce in three lines from main. delete should null
the struct's fields (DL-1) and push should size the materialization from
_internal_capacity (PB-8); those two fixes close the whole S1 set for this
function pair.
Reproducer harness: clang -std=c2x -g -fsanitize=address -Isrc/lib -Isrc/lib/char t.c src/lib/char/char.c src/lib/utils/utils.c. -std=c2x is
required — char.c uses nullptr, so the project does not compile as C17.
Reproducers that ask for a multi-exabyte calloc additionally need
ASAN_OPTIONS=allocator_may_return_null=1, or ASan aborts on the 2^61-byte
calloc before the interesting line runs.
Defensive-only rows. RZ-2, RS-2, PB-15 and PB-18 are not reachable
without an allocation of ~2^61 bytes, or a hand-built struct. Kept as
hardening because the guards are cheap and the invariant is worth stating.
Bugs
_vec_char_push_back / _vec_char_pop_back — char.c:71, 136
| ID |
Sev |
Location |
Finding |
State |
PB-8 |
S1 |
char.c:89, 131 |
calloc(1) on the null-buffer path leaves _internal_capacity at 1024, so the 2nd push_back writes arr[1] one byte past a 1-byte block. ASan: heap-buffer-overflow WRITE of size 1 at char.c:131, block allocated at char.c:89 |
OPEN |
PB-14 |
S1 |
char.c:75, 131, 154 |
neither function checks liveness. _vec_char_delete frees without clearing the struct (DL-1), so delete(&v); push_back(&v,'z') writes through the freed pointer. ASan: heap-use-after-free WRITE of size 1 at char.c:131, freed at char.c:297. Same for pop_back, which writes '\0' at char.c:154 |
OPEN |
PB-15 |
S1 |
char.c:87, 128-131 |
the materialize branch is guarded by status == ERR_BUF_NULL && _internal_size == 0 and has no else. Any state with arr == NULL && _internal_size > 0 falls through to char.c:126, takes res = ptr->_internal_arr (NULL) and writes arr[size]. No in-file producer, but nothing checks the invariant either |
OPEN |
PB-3 |
S1 |
char.c:106, 116 |
_internal_capacity assigned before the !res check; on OOM the struct overstates its capacity and the next call writes past the real block. Both branches |
OPEN |
PB-9 |
S2 |
char.c:85-99 |
push_back materializes a null vector, making it a second path alongside reserve; the two disagree on allocation size (1 byte vs 1024) |
OPEN |
PB-16 |
S2 |
char.c:116, 131 vs 154 |
the growth realloc leaves the new tail uninitialized and push_back never writes a terminator at _internal_size, so _vec_char_data hands back a non-NUL-terminated buffer — strlen(data(&v)) runs off the end. ASan: heap-buffer-overflow READ of 2049 bytes past a 2048-byte region grown at char.c:116. The lone '\0' write in either function is pop_back's vacated slot, so termination is accidental |
OPEN |
PB-21 |
S2 |
char.c:81, 104 |
after any reserve the vector is permanently full: reserve sets max_size = capacity, so char.c:81 fails for good and push_back can only return ERR_MAX_PASSED. Duplicate view of AS-4, kept so this table stands alone |
OPEN |
PB-17 |
S3 |
char.c:144-147 vs 87 |
pop_back refuses to materialize while push_back does. A blank vector reports ERR_BUF_NULL (21) and logs a spurious "Buffer :- NULL" instead of ERR_SIZE_ZERO (22), so a while (pop_back(&v) == SUCCESS) drain reports the wrong reason |
OPEN |
PB-18 |
S3 |
char.c:103, 116, 120-124 |
_internal_capacity == 0 makes dst_cap 0, and realloc(arr, 0) frees the block. The !res check then returns ERR_ALLOC_FAIL with _internal_arr dangling and capacity already committed as 0; the next push writes to freed memory. Capacity 0 is unreachable from this file today, so defensive |
OPEN |
PB-20 |
S3 |
char.c:154 |
only the vacated slot is zeroed, so bytes past _internal_size keep their values and are readable out of band through data(). clear zeroes the whole range and erase zeroes the tail; pop_back is the inconsistent one |
OPEN |
PB-1 and PB-2 were originally described as firing "on the very next call" and
as "the clamp silently does nothing". Both claims were wrong in detail: PB-1
needed capacity < size+1 <= max_size < 2*capacity, a band today's VEC_MAX
never reaches, and PB-2's cause was cap being recomputed from the
already-clobbered capacity, not the branch being skipped.
Pass-4 note. Four pre-existing rows here were my own errors and were
deleted: a "dead else" that is the common path, two is_valid double-call
claims in a function that hoists, and an overflow that VEC_MAX makes
impossible. Found by diffing the wording against the source, not by testing.
The three new S1/S2 rows were tested; the reproducer command is above.
_vec_char_create — char.c:23
Pass-5 note. create's growth block was rewritten this pass and the
rewrite is correct. The invariant it now enforces in one place is
size <= _internal_capacity <= _internal_max_size on return, held by the
commit-back at char.c:44. Verified under ASan at size 0, 1, 1023, 1024,
1025, 2047, 2048, 2049, 2999, 5000 and VEC_MAX - 1: capacity >= size on
every call, the calloc block matches the reported capacity, no overflow.
One case to know about: create(NULL, VEC_MAX - 1) still returns
capacity=4611686018427387902 over arr == NULL, because growth is correct
and the calloc then fails. That is CR-3 below, and it is unchanged.
dst_cap * 2 at char.c:42 cannot wrap, because the loop only doubles while
the product stays under _internal_max_size. An intermediate revision of
this fix omitted the commit-back and overflowed every size > CAPACITY; it
never reached a build, so no ID was spent on it. Two create findings left
the table this pass and their IDs are in the bottom list: CR-7, the
second growth branch, which tested the ceiling (capacity*2 > max_size)
instead of the loop's own postcondition — a superset that also fired after a
successful grow, overwriting capacity with size and forcing the next
push_back to reallocate for one byte; its > test also disagreed with the
loop's >= exit on exactly one value, reachable only because VEC_MAX is
odd. CR-8, the >= guard at char.c:32, which left size == VEC_MAX
allocating 1024 bytes and copying VEC_MAX bytes into it. Both are gone
because the branch they described no longer exists, not because either was
re-filed under a new ID.
| ID |
Sev |
Location |
Finding |
State |
CR-6 |
S2 |
char.c:29, 39-45 |
null vector's _internal_capacity is set to CAPACITY (1024) while nothing is allocated. Currently masked by AC-1: capacity() returns ERR_BUF_NULL first, so the lie is not observable through the public API. The observable form of this same lie is PB-8, after push_back materializes the buffer |
OPEN |
CR-3 |
S3 |
char.c:48-53 |
on calloc failure returns a struct with an already-grown capacity and arr == NULL. Defensive. Now reachable with an ordinary size, not just a huge one: create(NULL, 5000) grows capacity to 8192 at char.c:44, then the 8192-byte calloc fails and the struct survives claiming 8192 over a null buffer |
OPEN |
CR-4 |
DECIDE |
char.c:58-65 |
no NUL terminator; is a const char* src, size_t size pair a byte range or a C string? Affects whether a from_cstr helper is needed |
DECIDE |
_vec_char_is_valid — char.c:6
| ID |
Sev |
Location |
Finding |
State |
IV-1 |
S2 |
char.c:6 |
always returns non-zero, so if (_vec_char_is_valid(&v)) is true for every input including NULL. Every call site compares codes by luck |
OPEN |
IV-3 |
S2 |
char.c:6-17 |
is_valid is the only validation primitive in the file and it requires a non-null buffer, not just a non-null vector. Every accessor that only needs to validate the vector pointer therefore inherits ERR_BUF_NULL. This is the root cause of AC-1, AC-2, SW-1 and ST-2 |
OPEN |
_vec_char_reserve — char.c:156
| ID |
Sev |
Location |
Finding |
State |
RS-7 |
S1 |
char.c:175, 200 |
the ERR_BUF_NULL path allocates ptr->_internal_capacity bytes, not the requested capacity, then line 200 sets _internal_capacity = capacity regardless. So reserve(&v, 5000) on a blank vector callocs 1024 bytes and the struct claims 5000. ASan: heap-buffer-overflow WRITE at char.c:131, 0 bytes after a 1024-byte region allocated at char.c:175, reached by 1026 push_backs. The SUCCESS path at char.c:184 sizes the realloc correctly; only the null-buffer path is wrong. Second producer of PB-8, and unlike CR-7 this one needs no huge size — 5000 is ordinary |
OPEN |
RS-1 |
S1 |
char.c:180, 186-193, 195 |
realloc result held in res, but the truncation loop writes ptr->_internal_arr, which is still the pre-realloc pointer. Use-after-free when a shrinking reserve moves the block. Introduced by the FX-3 fix. ASan confirmed: create("abcdefgh",8) then reserve(3) gives heap-use-after-free WRITE at char.c:194 into a block freed at char.c:184 |
OPEN |
RS-2 |
S3 |
char.c:160-164 |
capacity == 0 checked before the NULL-vector check, so a NULL vector with capacity == 0 reports ERR_SIZE_ZERO instead of ERR_VECTOR_NULL. Defensive |
OPEN |
RS-6 |
C |
char.c:158, 178, 195 |
clang -Wsometimes-uninitialized: res used uninitialized at 195 if the if/else if chain falls through. Not reachable today since is_valid returns exactly 3 values, but real fragility |
OPEN |
RS-3 |
C |
char.c:197 |
max_size = capacity is correct under the hard-cap semantics but is documented nowhere. This is also the cause of ST-1 and AS-4 |
OPEN |
RS-4 |
C |
char.c:188-191 |
element-at-a-time loop, should be memset |
OPEN |
_vec_char_shrink_to_fit — char.c:202
| ID |
Sev |
Location |
Finding |
State |
ST-1 |
S2 |
char.c:202, 217 -> 197 |
calls reserve(ptr, _internal_size), and reserve sets max_size = capacity. So max_size is permanently capped to the current size and the vector can never grow again — every later push_back trips size+1 > max_size and returns ERR_MAX_PASSED. Silent brick. No save/restore, unlike resize (RZ-3) |
OPEN |
ST-2 |
S3 |
char.c:204-211 |
returns ERR_SIZE_ZERO on an empty vector; shrinking an empty vector should be a successful no-op. Two unhoisted is_valid calls at 204 and 208 |
OPEN |
_vec_char_swap — char.c:221
| ID |
Sev |
Location |
Finding |
State |
SW-1 |
S2 |
char.c:229-233 |
refuses NULL-buffer operands, so a blank vector can never be swapped against a populated one. Blocks the create(nullptr, 0) workflow outright |
OPEN |
SW-2 |
C |
char.c:223 |
temp built via _vec_char_create(nullptr, 0); a plain initializer states the intent |
OPEN |
_vec_char_delete — char.c:289
| ID |
Sev |
Location |
Finding |
State |
DL-1 |
S1 |
char.c:289, 293 |
takes const * so it cannot reset the vector; a second call is a double free. Only function still taking const in a mutable API |
OPEN |
DL-2 |
S1 |
char.h:11-17 |
no ownership marker on the struct, so a by-value copy yields two owners of one buffer and delete cannot detect it |
OPEN |
DL-3 |
C |
char.c:293 |
unnecessary (void*) cast; const on the struct does not propagate to the pointee |
OPEN |
_vec_char_capacity / _vec_char_max_size / _vec_char_data — char.c:261, 275, 252
| ID |
Sev |
Location |
Finding |
State |
AC-1 |
S2 |
char.c:254, 267, 281 |
all three return ERR_BUF_NULL for a null vector, though none of them needs a buffer. capacity() should report capacity, not an error |
OPEN |
DA-1 |
S2 |
char.c:251, 257 |
char* returned from a const _VecCharInternal*, laundering the const-correctness the mutable refactor was meant to establish |
OPEN |
_vec_char_clear / _vec_char_print_vec — char.c:298, 341
| ID |
Sev |
Location |
Finding |
State |
CL-1 |
C |
char.c:310-313 |
element-at-a-time zeroing loop, should be memset |
OPEN |
_vec_char_at — char.c:320
| ID |
Sev |
Location |
Finding |
State |
AT-1 |
S2 |
char.c:323, 328, 335 |
returns error codes (23/25, and 21) as a char; assign at char.c:642 pushes such a value into the vector as data |
OPEN |
AT-2 |
C |
char.c:332 |
raw fprintf bypasses LOGERROR |
OPEN |
_vec_char_begin / _vec_char_end — char.c:352, 359
| ID |
Sev |
Location |
Finding |
State |
BE-1 |
S2 |
char.c:355, 365, 367, 630, 668 |
FAILURE (== 1) returned as an index, indistinguishable from index 1. Single root cause of the + 1 at char.c:630 and char.c:668, of the assign-on-empty failures AS-1, and of the erase-on-empty failure ER-1 |
OPEN |
BE-2 |
C |
char.c:364 |
(int) cast on a size_t return |
OPEN |
_vec_char_front / _vec_char_back / _vec_char_empty — char.c:371, 379, 387
| ID |
Sev |
Location |
Finding |
State |
AC-2 |
S2 |
char.c:392, 393 |
inverted: SUCCESS (0) when empty, FAILURE (1) when not, so if (empty(v)) is false for an empty vector |
OPEN |
FB-1 |
S2 |
char.c:373, 374, 381, 382 |
returns FAILURE (1) as a char; 1 is valid data |
OPEN |
FB-2 |
C |
char.c:373, 381 |
validates only ERR_VECTOR_NULL, unlike every other accessor |
OPEN |
_vec_char_erase (both overloads) — char.c:398, 412
| ID |
Sev |
Location |
Finding |
State |
ER-1 |
S2 |
char.c:417, 418 |
iter_start >= iter_end returns ERR_OUT_OF_BOUNDS, so erase(begin(), end()) on an empty vector always errors. This is what breaks both assign overloads. On an empty vector the actual trip is char.c:417 (iter_end > size) because end() returned 1 and the caller added 1 — see BE-1 |
OPEN |
ER-2 |
C |
char.c:396, 410, 422-426 |
zeroing loop should be memset; two stale // TODO: Fix return value comments |
OPEN |
_vec_char_resize (both overloads) — char.c:432, 518
| ID |
Sev |
Location |
Finding |
State |
RZ-8 |
S2 |
char.c:434-444, 520-530 |
both overloads reject a null-buffer vector with ERR_BUF_NULL before the _internal_size == 0 branch that would have materialized one, so resize cannot be the first call on a blank vector. push_back can. ASan: create(NULL,0) then resize(0,4) returns 21 and the vector is still empty, where push_back four times would have worked. Same shape as PB-17, opposite direction |
OPEN |
RZ-3 |
S2 |
char.c:456, 471, 478, 497, 540, 557, 569, 579 |
the max_size save/restore is load-bearing (it undoes reserve's cap) but looks removable. Nothing documents that |
OPEN |
RZ-1 |
S2 |
char.c:442-446, 528-532 |
size == _internal_size returns ERR_OUT_OF_BOUNDS for a legitimate no-op; the code is also semantically wrong |
OPEN |
RZ-4 |
S3 |
char.c:501-504 vs 583-586 |
3-arg fills the discarded tail with val, 2-arg with '\0'. data() exposes the difference |
OPEN |
RZ-2 |
S3 |
char.c:481, 567 |
unguarded tmpcp *= 2 wraps on overflow. Defensive |
OPEN |
RZ-5 |
C |
char.c:462, 492, 548 |
dead post-reserve capacity checks; reserve always assigns capacity to its argument exactly |
OPEN |
RZ-6 |
C |
char.c:432-515 vs 518-597 |
two ~84-line near-identical bodies, with the growth blocks copy-pasted between them |
OPEN |
RZ-7 |
C |
char.c:444, 467, 501, 508, 530, 553, 583, 590 |
fill loops should be memset; misleading LOG("ERR :- ...") on what is now a no-op |
OPEN |
_vec_char_assign (both overloads) — char.c:600, 652
| ID |
Sev |
Location |
Finding |
State |
AS-1 |
S2 |
char.c:630, 668 |
fails on an empty destination, via ER-1. Fatal now because status is propagated; the immutable version discarded it and continued |
OPEN |
AS-2 |
S2 |
char.c:624-647, 661-687 |
not atomic: erase → reserve → push_back loop. Reserve failure leaves the destination wiped; a push_back failure mid-loop leaves it partially filled |
OPEN |
AS-3 |
S2 |
char.c:624, 662, 679 |
no > _internal_max_size guard on the assign count |
OPEN |
AS-4 |
S2 |
char.c:635, 673 |
the internal reserve caps max_size at the assign count with no save/restore, which resize does have |
OPEN |
AS-6 |
C |
char.c:600-649 vs 652-688 |
near-duplicate overloads differing only in the value source |
OPEN |
AS-7 |
S3 |
char.c:642 |
no check that at() succeeded before pushing its result. Currently correct only because the guards at char.c:611-618 and char.c:624 happen to make every index in range and the buffer non-null. Removing or loosening either guard turns this into AT-1's data-corruption case |
OPEN |
_vec_char_insert (all three overloads) — char.c:691, 726, 759
| ID |
Sev |
Location |
Finding |
State |
IN-1 |
S1 |
char.c:779 |
inverted check: iter_end > iter_start should be iter_end <= iter_start, so every valid non-empty range is rejected and only an empty range is accepted |
OPEN |
IN-2 |
S1 |
char.c:779 |
that clause short-circuits first, so the iter_end > iterator->_internal_size bound never fires |
OPEN |
IN-4 |
S2 |
char.c:742, 747-754 |
no max_size pre-check, so an oversized amount partially inserts and then fails, leaving the vector half-modified |
OPEN |
IN-6 |
S3 |
char.c:747 |
iter + amount can overflow size_t |
OPEN |
IN-5 |
S3 |
char.c:742 |
amount <= 0 on a size_t is always just == 0 |
OPEN |
IN-8 |
S2 |
char.c:747-754, 793 |
the loop copies via the raw iterator->_internal_arr[i] rather than a bounds-checked accessor. It is unreachable today only because IN-1's inversion makes iter_end <= iter_start always true, so the loop never runs. It becomes a live out-of-bounds read the moment IN-1 is fixed, unless IN-2 is fixed in the same change |
OPEN |
IN-9 |
C |
char.c:747-754 |
O(amount²) loop of single inserts where one grow + memmove would do |
OPEN |
utils.h / utils.c
| ID |
Sev |
Location |
Finding |
State |
UT-2 |
S1 |
utils.c:3-12 |
indices 0 and 1 are never assigned, so error_messages[0] and [1] are NULL. LOGERROR(SUCCESS) prints %s of NULL, and both are values functions return. Latent only because no caller exists yet |
OPEN |
UT-1 |
S2 |
utils.h:29 |
SIZE_MAX / sizeof(int) is what the char vector uses, capping it at 1/4 of the usable address space |
OPEN |
UT-3 |
S2 |
utils.c:3 |
SUCCESS/FAILURE overlap the error-index namespace, so 0 is both "success" and a table slot |
OPEN |
UT-5 |
C |
utils.h:23 |
DEBUG prints the literal DEBUB: , so char.c:109 — the only DEBUG call in the tree, on the clamp path in push_back — emits a misspelled prefix |
OPEN |
UT-4 |
C |
utils.h:7, 17, 20, 22-25, 27, 29 · utils.c:6, 10 |
static const in a header gives every TU its own copy; ERR_NULL is now dead (defined and given a message, never referenced from char.c); ERR_SIZE_ZERO message mentions < 0 on a size_t; extern const char* should be const char* const[]; LOG/LOGERROR are hardwired to stdout and single-arg; find_len is UB for pointers; CAPACITY is a magic number in a shared header |
OPEN |
char.h
| ID |
Sev |
Location |
Finding |
State |
CH-9 |
S2 |
char.h:11-106 (29 identifiers) |
every public identifier is reserved by the C standard: _VecCharInternal and all 28 _vec_char_* functions begin with _ at file scope, which C11 7.1.3 reserves for the implementation. Undefined behaviour on collision with any libc or third-party name. clang -Weverything reports all 28 |
OPEN |
CH-4 |
C |
char.h:6-8 |
<stdio.h>/<stdlib.h>/<string.h> in the header, only needed by the .c |
OPEN |
CH-5 |
C |
char.h |
no doc comments on any function, despite the /**< */ style in utils.h |
OPEN |
CH-7 |
C |
char.h:22-23 |
no from_cstr / NUL-termination path for the char specialization. See CR-4 |
OPEN |
CH-8 |
C |
char.h:11-17 |
the public struct is named with a _ prefix and its four fields are named _internal_* instead of being PRIVATE, so the "internal" contract is expressed only by spelling. Combined with CH-9 this is the whole naming problem |
OPEN |
CH-1 |
C |
char.h:32 vs char.c:156 |
param named max_size in the header, capacity in the definition |
OPEN |
CH-2 |
C |
char.h:23-106 |
const on by-value params throughout (const size_t size, const char val, const size_t idx, …) |
OPEN |
CH-3 |
C |
char.h |
no size() accessor, so callers reach into _internal_size directly |
OPEN |
Project
| ID |
Sev |
Location |
Finding |
State |
PR-2 |
C |
char.c:1-3 |
mixed brace style (single-line if in erase/front/back/begin/empty vs expanded blocks); .clang-format exists and is not run |
OPEN |
PR-3 |
C |
char.c:204, 208, 224, 225, 229, 230, 254, 255, 263, 267, 277, 281, 291, 300, 304, 322, 326, 343, 344, 354, 361, 373, 381, 389, 390, 400, 401, 415, 416, 434, 438, 520, 524, 603, 607, 611, 615, 654, 658, 693, 697, 763, 767, 771, 775 |
is_valid called 2-3× per function and logging each time, in every function except push_back, pop_back and reserve — those three hoist |
OPEN |
PR-7 |
C |
CMakeLists.txt:28, main.c:20-54 |
the test_runner target exists but main() is entirely commented out, so nothing in the tree calls a single function in this tracker. This is the only place a regression in the 10 open S1s could be caught, and it is dead |
OPEN |
PR-4 |
C |
main.c:23-53 |
100% commented out, references removed API Vec8_t and v1.size |
OPEN |
PR-5 |
C |
include/libvec.h:4, CMakeLists.txt:12-14 |
empty placeholder; int/float/string are empty dirs already listed as comments in CMakeLists.txt |
OPEN |
ID map
FX-1 … FX-5 are first-pass IDs. FX-1 was a duplicate of PB-6 and was never
given a row.
| Prefix |
Scope |
|
Prefix |
Scope |
PB- |
push_back, pop_back |
|
AT- |
at |
RS- |
reserve |
|
FB- |
front, back |
ST- |
shrink_to_fit |
|
BE- |
begin, end |
CR- |
create |
|
SW- |
swap |
AC- |
accessors |
|
CL- |
clear, print_vec |
DA- |
data |
|
IV- |
is_valid |
DL- |
delete |
|
UT- |
utils.h, utils.c |
ER- |
erase |
|
CH- |
char.h |
RZ- |
resize |
|
PR- |
project |
AS- |
assign |
|
FX- |
retired first-pass IDs |
IN- |
insert |
|
|
|
PB-1 PB-2 PB-4 PB-6 PB-7 FX-2 FX-3 FX-4 FX-5 PR-1 CR-7 CR-8