diff --git a/src/cypher/cypher.c b/src/cypher/cypher.c index 6aedeb9..a0d652a 100644 --- a/src/cypher/cypher.c +++ b/src/cypher/cypher.c @@ -405,10 +405,10 @@ void cbm_lex_free(cbm_lex_result_t *r) { return; } for (int i = 0; i < r->count; i++) { - free((void *)r->tokens[i].text); + safe_str_free(&r->tokens[i].text); } - free(r->tokens); - free(r->error); + safe_free(r->tokens); + safe_free(r->error); memset(r, 0, sizeof(*r)); } @@ -473,23 +473,20 @@ static int parse_props(parser_t *p, cbm_prop_filter_t **out, int *count) { while (!check(p, TOK_RBRACE) && !check(p, TOK_EOF)) { const cbm_token_t *key = expect(p, TOK_IDENT); if (!key) { - free(arr); + safe_free(arr); return CBM_NOT_FOUND; } if (!expect(p, TOK_COLON)) { - free(arr); + safe_free(arr); return CBM_NOT_FOUND; } const cbm_token_t *val = expect(p, TOK_STRING); if (!val) { - free(arr); + safe_free(arr); return CBM_NOT_FOUND; } - if (n >= cap) { - cap *= PAIR_LEN; - arr = safe_realloc(arr, cap * sizeof(cbm_prop_filter_t)); - } + safe_grow(arr, n, cap, PAIR_LEN); arr[n].key = heap_strdup(key->text); arr[n].value = heap_strdup(val->text); n++; @@ -572,7 +569,7 @@ static int parse_rel_types(parser_t *p, cbm_rel_pattern_t *out) { const cbm_token_t *t = expect(p, TOK_IDENT); if (!t) { - free(types); + safe_free(types); return CBM_NOT_FOUND; } types[n++] = heap_strdup(t->text); @@ -581,15 +578,12 @@ static int parse_rel_types(parser_t *p, cbm_rel_pattern_t *out) { t = expect(p, TOK_IDENT); if (!t) { for (int i = 0; i < n; i++) { - free((void *)types[i]); + safe_str_free(&types[i]); } - free(types); + safe_free(types); return CBM_NOT_FOUND; } - if (n >= cap) { - cap *= PAIR_LEN; - types = safe_realloc(types, cap * sizeof(const char *)); - } + safe_grow(types, n, cap, PAIR_LEN); types[n++] = heap_strdup(t->text); } @@ -670,14 +664,14 @@ static void expr_free(cbm_expr_t *e) { while (top > 0) { cbm_expr_t *cur = stack[--top]; if (cur->type == EXPR_CONDITION) { - free((void *)cur->cond.variable); - free((void *)cur->cond.property); - free((void *)cur->cond.op); - free((void *)cur->cond.value); + safe_str_free(&cur->cond.variable); + safe_str_free(&cur->cond.property); + safe_str_free(&cur->cond.op); + safe_str_free(&cur->cond.value); for (int i = 0; i < cur->cond.in_value_count; i++) { - free((void *)cur->cond.in_values[i]); + safe_str_free(&cur->cond.in_values[i]); } - free(cur->cond.in_values); + safe_free(cur->cond.in_values); } if (cur->right && top < EXPR_FREE_STACK) { stack[top++] = cur->right; @@ -685,7 +679,7 @@ static void expr_free(cbm_expr_t *e) { if (cur->left && top < EXPR_FREE_STACK) { stack[top++] = cur->left; } - free(cur); + safe_free(cur); } } @@ -754,9 +748,9 @@ static cbm_expr_t *parse_in_list(parser_t *p, cbm_condition_t *c) { advance(p); c->op = heap_strdup("IN"); if (!expect(p, TOK_LBRACKET)) { - free((void *)c->variable); - free((void *)c->property); - free((void *)c->op); + safe_str_free(&c->variable); + safe_str_free(&c->property); + safe_str_free(&c->op); return NULL; } int vcap = CYP_INIT_CAP8; @@ -767,10 +761,7 @@ static cbm_expr_t *parse_in_list(parser_t *p, cbm_condition_t *c) { match(p, TOK_COMMA); } if (check(p, TOK_STRING) || check(p, TOK_NUMBER)) { - if (vn >= vcap) { - vcap *= PAIR_LEN; - vals = safe_realloc(vals, vcap * sizeof(const char *)); - } + safe_grow(vals, vn, vcap, PAIR_LEN); vals[vn++] = heap_strdup(advance(p)->text); } else { break; @@ -870,8 +861,8 @@ static cbm_expr_t *parse_condition_expr(parser_t *p) { c.op = parse_comparison_op(p); if (!c.op) { snprintf(p->error, sizeof(p->error), "unexpected operator at pos %d", peek(p)->pos); - free((void *)c.variable); - free((void *)c.property); + safe_str_free(&c.variable); + safe_str_free(&c.property); return NULL; } @@ -886,9 +877,9 @@ static cbm_expr_t *parse_condition_expr(parser_t *p) { c.value = heap_strdup("false"); } else { snprintf(p->error, sizeof(p->error), "expected value at pos %d", peek(p)->pos); - free((void *)c.variable); - free((void *)c.property); - free((void *)c.op); + safe_str_free(&c.variable); + safe_str_free(&c.property); + safe_str_free(&c.op); return NULL; } @@ -978,7 +969,7 @@ static int parse_where(parser_t *p, cbm_where_clause_t **out) { cbm_where_clause_t *w = calloc(CBM_ALLOC_ONE, sizeof(cbm_where_clause_t)); w->root = parse_or_expr(p); if (!w->root && p->error[0]) { - free(w); + safe_free(w); return CBM_NOT_FOUND; } @@ -1072,10 +1063,7 @@ static cbm_case_expr_t *parse_case_expr(parser_t *p) { break; } const char *then_val = parse_value_literal(p); - if (kase->branch_count >= bcap) { - bcap *= PAIR_LEN; - kase->branches = safe_realloc(kase->branches, bcap * sizeof(cbm_case_branch_t)); - } + safe_grow(kase->branches, kase->branch_count, bcap, PAIR_LEN); kase->branches[kase->branch_count++] = (cbm_case_branch_t){.when_expr = when, .then_val = then_val}; } @@ -1244,15 +1232,12 @@ static int parse_return_or_with(parser_t *p, cbm_return_clause_t **out, bool is_ cbm_return_item_t item = {0}; if (parse_return_item(p, &item) < 0) { - free(r->items); - free(r); + safe_free(r->items); + safe_free(r); return CBM_NOT_FOUND; } - if (r->count >= cap) { - cap *= PAIR_LEN; - r->items = safe_realloc(r->items, cap * sizeof(cbm_return_item_t)); - } + safe_grow(r->items, r->count, cap, PAIR_LEN); r->items[r->count++] = item; } while (check(p, TOK_COMMA)); @@ -1302,19 +1287,13 @@ static int parse_match_pattern(parser_t *p, cbm_pattern_t *pat) { pat->node_count = SKIP_ONE; while (check(p, TOK_DASH) || check(p, TOK_LT)) { - if (pat->rel_count >= rel_cap) { - rel_cap *= PAIR_LEN; - pat->rels = safe_realloc(pat->rels, rel_cap * sizeof(cbm_rel_pattern_t)); - } + safe_grow(pat->rels, pat->rel_count, rel_cap, PAIR_LEN); if (parse_rel(p, &pat->rels[pat->rel_count]) < 0) { return CBM_NOT_FOUND; } pat->rel_count++; - if (pat->node_count >= node_cap) { - node_cap *= PAIR_LEN; - pat->nodes = safe_realloc(pat->nodes, node_cap * sizeof(cbm_node_pattern_t)); - } + safe_grow(pat->nodes, pat->node_count, node_cap, PAIR_LEN); if (parse_node(p, &pat->nodes[pat->node_count]) < 0) { return CBM_NOT_FOUND; } @@ -1500,7 +1479,7 @@ void cbm_parse_free(cbm_parse_result_t *r) { return; } cbm_query_free(r->query); - free(r->error); + safe_free(r->error); memset(r, 0, sizeof(*r)); } @@ -1509,25 +1488,25 @@ void cbm_parse_free(cbm_parse_result_t *r) { static void free_pattern(cbm_pattern_t *pat) { for (int i = 0; i < pat->node_count; i++) { cbm_node_pattern_t *n = &pat->nodes[i]; - free((void *)n->variable); - free((void *)n->label); + safe_str_free(&n->variable); + safe_str_free(&n->label); for (int j = 0; j < n->prop_count; j++) { - free((void *)n->props[j].key); - free((void *)n->props[j].value); + safe_str_free(&n->props[j].key); + safe_str_free(&n->props[j].value); } - free(n->props); + safe_free(n->props); } - free(pat->nodes); + safe_free(pat->nodes); for (int i = 0; i < pat->rel_count; i++) { cbm_rel_pattern_t *r = &pat->rels[i]; - free((void *)r->variable); + safe_str_free(&r->variable); for (int j = 0; j < r->type_count; j++) { - free((void *)r->types[j]); + safe_str_free(&r->types[j]); } - free(r->types); - free((void *)r->direction); + safe_free(r->types); + safe_str_free(&r->direction); } - free(pat->rels); + safe_free(pat->rels); } static void free_where(cbm_where_clause_t *w) { @@ -1536,18 +1515,18 @@ static void free_where(cbm_where_clause_t *w) { } expr_free(w->root); for (int i = 0; i < w->count; i++) { - free((void *)w->conditions[i].variable); - free((void *)w->conditions[i].property); - free((void *)w->conditions[i].op); - free((void *)w->conditions[i].value); + safe_str_free(&w->conditions[i].variable); + safe_str_free(&w->conditions[i].property); + safe_str_free(&w->conditions[i].op); + safe_str_free(&w->conditions[i].value); for (int j = 0; j < w->conditions[i].in_value_count; j++) { - free((void *)w->conditions[i].in_values[j]); + safe_str_free(&w->conditions[i].in_values[j]); } - free(w->conditions[i].in_values); + safe_free(w->conditions[i].in_values); } - free(w->conditions); - free((void *)w->op); - free(w); + safe_free(w->conditions); + safe_str_free(&w->op); + safe_free(w); } static void free_case_expr(cbm_case_expr_t *k) { @@ -1556,11 +1535,11 @@ static void free_case_expr(cbm_case_expr_t *k) { } for (int i = 0; i < k->branch_count; i++) { expr_free(k->branches[i].when_expr); - free((void *)k->branches[i].then_val); + safe_str_free(&k->branches[i].then_val); } - free(k->branches); - free((void *)k->else_val); - free(k); + safe_free(k->branches); + safe_str_free(&k->else_val); + safe_free(k); } static void free_return_clause(cbm_return_clause_t *r) { @@ -1568,16 +1547,16 @@ static void free_return_clause(cbm_return_clause_t *r) { return; } for (int i = 0; i < r->count; i++) { - free((void *)r->items[i].variable); - free((void *)r->items[i].property); - free((void *)r->items[i].alias); - free((void *)r->items[i].func); + safe_str_free(&r->items[i].variable); + safe_str_free(&r->items[i].property); + safe_str_free(&r->items[i].alias); + safe_str_free(&r->items[i].func); free_case_expr(r->items[i].kase); } - free(r->items); - free((void *)r->order_by); - free((void *)r->order_dir); - free(r); + safe_free(r->items); + safe_str_free(&r->order_by); + safe_str_free(&r->order_dir); + safe_free(r); } void cbm_query_free(cbm_query_t *q) { @@ -1586,15 +1565,15 @@ void cbm_query_free(cbm_query_t *q) { for (int i = 0; i < q->pattern_count; i++) { free_pattern(&q->patterns[i]); } - free(q->patterns); - free(q->pattern_optional); + safe_free(q->patterns); + safe_free(q->pattern_optional); free_where(q->where); free_where(q->post_with_where); free_return_clause(q->with_clause); free_return_clause(q->ret); - free((void *)q->unwind_expr); - free((void *)q->unwind_alias); - free(q); + safe_str_free(&q->unwind_expr); + safe_str_free(&q->unwind_alias); + safe_free(q); q = next; } } @@ -1765,12 +1744,12 @@ static void node_fields_free(cbm_node_t *n) { if (!n) { return; } - free((void *)n->project); - free((void *)n->label); - free((void *)n->name); - free((void *)n->qualified_name); - free((void *)n->file_path); - free((void *)n->properties_json); + safe_str_free(&n->project); + safe_str_free(&n->label); + safe_str_free(&n->name); + safe_str_free(&n->qualified_name); + safe_str_free(&n->file_path); + safe_str_free(&n->properties_json); } /* Deep copy an edge (binding owns the strings) */ @@ -1782,9 +1761,9 @@ static void edge_deep_copy(cbm_edge_t *dst, const cbm_edge_t *src) { } static void edge_fields_free(cbm_edge_t *e) { - free((void *)e->project); - free((void *)e->type); - free((void *)e->properties_json); + safe_str_free(&e->project); + safe_str_free(&e->type); + safe_str_free(&e->properties_json); } /* Set an edge variable in a binding */ @@ -2027,10 +2006,7 @@ static void rb_set_columns(result_builder_t *rb, const char **cols, int count) { } static void rb_add_row(result_builder_t *rb, const char **values) { - if (rb->row_count >= rb->row_cap) { - rb->row_cap *= PAIR_LEN; - rb->rows = safe_realloc(rb->rows, rb->row_cap * sizeof(const char **)); - } + safe_grow(rb->rows, rb->row_count, rb->row_cap, PAIR_LEN); const char **row = malloc((rb->col_count > 0 ? (size_t)rb->col_count : SKIP_ONE) * sizeof(const char *)); for (int i = 0; i < rb->col_count; i++) { @@ -2324,7 +2300,7 @@ static void expand_pattern_rels(cbm_store_t *store, cbm_pattern_t *pat, binding_ for (int bi = 0; bi < *bind_count; bi++) { binding_free(&(*bindings)[bi]); } - free(*bindings); + safe_free(*bindings); *bindings = new_bindings; *bind_count = new_count; *var_name = to_var; @@ -2403,18 +2379,18 @@ static void rb_apply_skip_limit(result_builder_t *rb, int skip_n, int limit) { if (skip_n > 0 && skip_n < rb->row_count) { for (int i = 0; i < skip_n; i++) { for (int c = 0; c < rb->col_count; c++) { - free((void *)rb->rows[i][c]); + safe_str_free(&rb->rows[i][c]); } - free(rb->rows[i]); + safe_free(rb->rows[i]); } memmove(rb->rows, rb->rows + skip_n, (rb->row_count - skip_n) * sizeof(const char **)); rb->row_count -= skip_n; } else if (skip_n >= rb->row_count) { for (int i = 0; i < rb->row_count; i++) { for (int c = 0; c < rb->col_count; c++) { - free((void *)rb->rows[i][c]); + safe_str_free(&rb->rows[i][c]); } - free(rb->rows[i]); + safe_free(rb->rows[i]); } rb->row_count = 0; } @@ -2422,9 +2398,9 @@ static void rb_apply_skip_limit(result_builder_t *rb, int skip_n, int limit) { if (limit > 0 && rb->row_count > limit) { for (int i = limit; i < rb->row_count; i++) { for (int c = 0; c < rb->col_count; c++) { - free((void *)rb->rows[i][c]); + safe_str_free(&rb->rows[i][c]); } - free(rb->rows[i]); + safe_free(rb->rows[i]); } rb->row_count = limit; } @@ -2455,9 +2431,9 @@ static void rb_apply_distinct(result_builder_t *rb) { kept++; } else { for (int c = 0; c < rb->col_count; c++) { - free((void *)rb->rows[i][c]); + safe_str_free(&rb->rows[i][c]); } - free(rb->rows[i]); + safe_free(rb->rows[i]); } } rb->row_count = kept; @@ -2466,15 +2442,15 @@ static void rb_apply_distinct(result_builder_t *rb) { static void rb_free(result_builder_t *rb) { for (int i = 0; i < rb->row_count; i++) { for (int c = 0; c < rb->col_count; c++) { - free((void *)rb->rows[i][c]); + safe_str_free(&rb->rows[i][c]); } - free(rb->rows[i]); + safe_free(rb->rows[i]); } - free(rb->rows); + safe_free(rb->rows); for (int i = 0; i < rb->col_count; i++) { - free((void *)rb->columns[i]); + safe_str_free(&rb->columns[i]); } - free(rb->columns); + safe_free(rb->columns); } /* ── Get projection value for a binding + return item ─────────── */ @@ -2673,15 +2649,15 @@ static void with_add_vbinding_var(binding_t *vb, const char *alias, const char * static void with_agg_free(with_agg_t *aggs, int agg_cnt, int item_count) { for (int a = 0; a < agg_cnt; a++) { for (int ci = 0; ci < item_count; ci++) { - free((void *)aggs[a].group_vals[ci]); + safe_str_free(&aggs[a].group_vals[ci]); } - free(aggs[a].group_vals); - free(aggs[a].sums); - free(aggs[a].counts); - free(aggs[a].mins); - free(aggs[a].maxs); + safe_free(aggs[a].group_vals); + safe_free(aggs[a].sums); + safe_free(aggs[a].counts); + safe_free(aggs[a].mins); + safe_free(aggs[a].maxs); } - free(aggs); + safe_free(aggs); } /* Execute WITH aggregation path */ @@ -2785,7 +2761,7 @@ static void execute_with_clause(cbm_query_t *q, binding_t **bindings_ptr, int *b for (int bi = 0; bi < bind_count; bi++) { binding_free(&bindings[bi]); } - free(bindings); + safe_free(bindings); if (q->post_with_where) { filter_bindings_where(q->post_with_where, vbindings, &vcount); @@ -2833,7 +2809,7 @@ static void build_star_columns(result_builder_t *rb, const char **vars, int vc) } rb_set_columns(rb, col_names, col_n); for (int i = 0; i < col_n; i++) { - free((void *)col_names[i]); + safe_str_free(&col_names[i]); } } @@ -2970,21 +2946,21 @@ static void ret_agg_accumulate(ret_agg_entry_t *entry, cbm_return_clause_t *ret, static void ret_agg_free(ret_agg_entry_t *aggs, int agg_count, int item_count) { for (int a = 0; a < agg_count; a++) { for (int ci = 0; ci < item_count; ci++) { - free((void *)aggs[a].group_vals[ci]); + safe_str_free(&aggs[a].group_vals[ci]); for (int j = 0; j < aggs[a].collect_counts[ci]; j++) { - free(aggs[a].collect_lists[ci][j]); + safe_free(aggs[a].collect_lists[ci][j]); } - free(aggs[a].collect_lists[ci]); + safe_free(aggs[a].collect_lists[ci]); } - free(aggs[a].group_vals); - free(aggs[a].sums); - free(aggs[a].counts); - free(aggs[a].mins); - free(aggs[a].maxs); - free(aggs[a].collect_lists); - free(aggs[a].collect_counts); + safe_free(aggs[a].group_vals); + safe_free(aggs[a].sums); + safe_free(aggs[a].counts); + safe_free(aggs[a].mins); + safe_free(aggs[a].maxs); + safe_free(aggs[a].collect_lists); + safe_free(aggs[a].collect_counts); } - free(aggs); + safe_free(aggs); } /* Execute RETURN with aggregation */ @@ -3042,10 +3018,7 @@ static void execute_return_agg(cbm_return_clause_t *ret, binding_t *bindings, in } } if (found < 0) { - if (agg_count >= agg_cap) { - agg_cap *= PAIR_LEN; - aggs = safe_realloc(aggs, agg_cap * sizeof(ret_agg_entry_t)); - } + safe_grow(aggs, agg_count, agg_cap, PAIR_LEN); found = agg_count++; ret_agg_init_group(&aggs[found], key, ret->count, vals); } @@ -3083,7 +3056,7 @@ static void build_return_columns(result_builder_t *rb, cbm_return_clause_t *ret) for (int i = 0; i < ret->count && i < CBM_SZ_32; i++) { cbm_return_item_t *item = &ret->items[i]; if (!item->alias && (item->func || (!item->kase && item->property))) { - free((void *)col_names[i]); + safe_str_free(&col_names[i]); } } } @@ -3121,7 +3094,7 @@ static void build_default_columns(result_builder_t *rb, const char **vars, int v } rb_set_columns(rb, col_names, col_n); for (int i = 0; i < col_n; i++) { - free((void *)col_names[i]); + safe_str_free(&col_names[i]); } } @@ -3170,7 +3143,7 @@ static void cross_join_nodes(binding_t **bindings, int *bind_count, cbm_node_t * for (int bi = 0; bi < *bind_count; bi++) { binding_free(&(*bindings)[bi]); } - free(*bindings); + safe_free(*bindings); *bindings = new_bindings; *bind_count = new_count; } @@ -3196,7 +3169,7 @@ static void cross_join_with_rels(cbm_store_t *store, cbm_pattern_t *patn, bindin for (int ti = 0; ti < tc; ti++) { new_bindings[new_count++] = tmp[ti]; } - free(tmp); + safe_free(tmp); } if (opt && extra_count == 0) { binding_t nb = {0}; @@ -3207,7 +3180,7 @@ static void cross_join_with_rels(cbm_store_t *store, cbm_pattern_t *patn, bindin for (int bi = 0; bi < *bind_count; bi++) { binding_free(&(*bindings)[bi]); } - free(*bindings); + safe_free(*bindings); *bindings = new_bindings; *bind_count = new_count; } @@ -3322,7 +3295,7 @@ static int execute_single(cbm_store_t *store, cbm_query_t *q, const char *projec for (int bi = 0; bi < bind_count; bi++) { binding_free(&bindings[bi]); } - free(bindings); + safe_free(bindings); cbm_store_free_nodes(scanned, scan_count); return 0; } @@ -3397,16 +3370,16 @@ void cbm_cypher_result_free(cbm_cypher_result_t *r) { return; } for (int i = 0; i < r->col_count; i++) { - free((void *)r->columns[i]); + safe_str_free(&r->columns[i]); } - free(r->columns); + safe_free(r->columns); for (int i = 0; i < r->row_count; i++) { for (int j = 0; j < r->col_count; j++) { - free((void *)r->rows[i][j]); + safe_str_free(&r->rows[i][j]); } - free(r->rows[i]); + safe_free(r->rows[i]); } - free(r->rows); - free(r->error); + safe_free(r->rows); + safe_free(r->error); memset(r, 0, sizeof(*r)); } diff --git a/src/foundation/platform.h b/src/foundation/platform.h index 5624810..f0665d5 100644 --- a/src/foundation/platform.h +++ b/src/foundation/platform.h @@ -31,6 +31,48 @@ static inline void *safe_realloc(void *ptr, size_t size) { return tmp; } +/* Safe free: frees and NULLs a pointer to prevent double-free / use-after-free. + * Accepts void** so it works with any pointer type via the macro. */ +static inline void safe_free_impl(void **pp) { + if (pp && *pp) { + free(*pp); + *pp = NULL; + } +} +#define safe_free(ptr) safe_free_impl((void **)(void *)&(ptr)) + +/* Safe string free: frees a const char* and NULLs it. + * Casts away const so callers don't need the (void*) dance. */ +static inline void safe_str_free(const char **sp) { + if (sp && *sp) { + free((void *)*sp); + *sp = NULL; + } +} + +/* Safe buffer free: frees a heap array and zeros its element count. + * Use for dynamic arrays paired with a size_t count. */ +static inline void safe_buf_free_impl(void **buf, size_t *count) { + if (buf && *buf) { + free(*buf); + *buf = NULL; + } + if (count) { + *count = 0; + } +} +#define safe_buf_free(buf, countp) safe_buf_free_impl((void **)(void *)&(buf), (countp)) + +/* Safe grow: doubles capacity and reallocs when count reaches cap. + * Usage: safe_grow(arr, count, cap, growth_factor) + * Evaluates to the new arr (NULL on OOM — old memory freed by safe_realloc). */ +#define safe_grow(arr, n, cap, factor) do { \ + if ((size_t)(n) >= (size_t)(cap)) { \ + (cap) *= (factor); \ + (arr) = safe_realloc((arr), (size_t)(cap) * sizeof(*(arr))); \ + } \ +} while (0) + /* ── Memory mapping ────────────────────────────────────────────── */ /* Map a file read-only into memory. Returns NULL on error. diff --git a/src/mcp/mcp.c b/src/mcp/mcp.c index 6b5cec5..52a7337 100644 --- a/src/mcp/mcp.c +++ b/src/mcp/mcp.c @@ -2688,10 +2688,7 @@ static grep_match_t *collect_grep_matches(FILE *fp, const char *root_path, size_ continue; } - if (gm_count >= gm_cap) { - gm_cap *= PAIR_LEN; - gm = safe_realloc(gm, gm_cap * sizeof(grep_match_t)); - } + safe_grow(gm, gm_count, gm_cap, PAIR_LEN); snprintf(gm[gm_count].file, sizeof(gm[0].file), "%s", file); gm[gm_count].line = (int)strtol(colon1 + SKIP_ONE, NULL, CBM_DECIMAL_BASE); snprintf(gm[gm_count].content, sizeof(gm[0].content), "%s", colon2 + SKIP_ONE); diff --git a/src/pipeline/pass_githistory.c b/src/pipeline/pass_githistory.c index 36b491f..6be5138 100644 --- a/src/pipeline/pass_githistory.c +++ b/src/pipeline/pass_githistory.c @@ -185,10 +185,7 @@ static int parse_git_log(const char *repo_path, commit_t **out, int *out_count) } if (current.count > 0) { - if (count >= cap) { - cap *= PAIR_LEN; - commits = safe_realloc(commits, cap * sizeof(commit_t)); - } + safe_grow(commits, count, cap, PAIR_LEN); commits[count++] = current; } else { commit_free(¤t); @@ -250,10 +247,7 @@ static int parse_git_log(const char *repo_path, commit_t **out, int *out_count) if (strncmp(line, "COMMIT:", SLEN("COMMIT:")) == 0) { if (current.count > 0) { - if (count >= cap) { - cap *= PAIR_LEN; - commits = safe_realloc(commits, cap * sizeof(commit_t)); - } + safe_grow(commits, count, cap, PAIR_LEN); commits[count++] = current; memset(¤t, 0, sizeof(current)); } @@ -265,10 +259,7 @@ static int parse_git_log(const char *repo_path, commit_t **out, int *out_count) } } if (current.count > 0) { - if (count >= cap) { - cap *= PAIR_LEN; - commits = safe_realloc(commits, cap * sizeof(commit_t)); - } + safe_grow(commits, count, cap, PAIR_LEN); commits[count++] = current; } else { commit_free(¤t); diff --git a/src/store/store.c b/src/store/store.c index cacf97f..494c2bb 100644 --- a/src/store/store.c +++ b/src/store/store.c @@ -511,7 +511,7 @@ static cbm_store_t *store_open_internal(const char *path, bool in_memory) { int rc = sqlite3_open_v2(path, &s->db, flags, NULL); if (rc != SQLITE_OK) { - free(s); + safe_free(s); return NULL; } @@ -539,8 +539,8 @@ static cbm_store_t *store_open_internal(const char *path, bool in_memory) { if (configure_pragmas(s, in_memory) != CBM_STORE_OK || init_schema(s) != CBM_STORE_OK || create_user_indexes(s) != CBM_STORE_OK) { sqlite3_close(s->db); - free((void *)s->db_path); - free(s); + safe_str_free(&s->db_path); + safe_free(s); return NULL; } @@ -573,7 +573,7 @@ cbm_store_t *cbm_store_open_path_query(const char *db_path) { if (rc != SQLITE_OK) { /* sqlite3_open_v2 allocates a handle even on failure — must close it. */ sqlite3_close(s->db); - free(s); + safe_free(s); return NULL; } @@ -594,8 +594,8 @@ cbm_store_t *cbm_store_open_path_query(const char *db_path) { if (configure_pragmas(s, false) != CBM_STORE_OK) { sqlite3_close(s->db); - free((void *)s->db_path); - free(s); + safe_str_free(&s->db_path); + safe_free(s); return NULL; } @@ -919,10 +919,7 @@ int cbm_store_list_projects(cbm_store_t *s, cbm_project_t **out, int *count) { cbm_project_t *arr = malloc(cap * sizeof(cbm_project_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_project_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].name = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].indexed_at = heap_strdup((const char *)sqlite3_column_text(stmt, SKIP_ONE)); arr[n].root_path = heap_strdup((const char *)sqlite3_column_text(stmt, CBM_SZ_2)); @@ -1086,10 +1083,7 @@ int cbm_store_find_nodes_by_name_any(cbm_store_t *s, const char *name, cbm_node_ int n = 0; cbm_node_t *arr = malloc(cap * sizeof(cbm_node_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_node_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); scan_node(stmt, &arr[n]); n++; } @@ -1145,10 +1139,7 @@ static int find_nodes_generic(cbm_store_t *s, sqlite3_stmt **slot, const char *s cbm_node_t *arr = malloc(cap * sizeof(cbm_node_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_node_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); scan_node(stmt, &arr[n]); n++; } @@ -1334,10 +1325,7 @@ static int find_edges_generic(cbm_store_t *s, sqlite3_stmt **slot, const char *s cbm_edge_t *arr = malloc(cap * sizeof(cbm_edge_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_edge_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); scan_edge(stmt, &arr[n]); n++; } @@ -1548,10 +1536,7 @@ int cbm_store_get_file_hashes(cbm_store_t *s, const char *project, cbm_file_hash cbm_file_hash_t *arr = malloc(cap * sizeof(cbm_file_hash_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_file_hash_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].project = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].rel_path = heap_strdup((const char *)sqlite3_column_text(stmt, SKIP_ONE)); arr[n].sha256 = heap_strdup((const char *)sqlite3_column_text(stmt, CBM_SZ_2)); @@ -1627,10 +1612,7 @@ int cbm_store_find_nodes_by_file_overlap(cbm_store_t *s, const char *project, co int n = 0; cbm_node_t *nodes = malloc(cap * sizeof(cbm_node_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - nodes = safe_realloc(nodes, cap * sizeof(cbm_node_t)); - } + safe_grow(nodes, n, cap, ST_GROWTH); memset(&nodes[n], 0, sizeof(cbm_node_t)); scan_node(stmt, &nodes[n]); n++; @@ -1683,10 +1665,7 @@ int cbm_store_find_nodes_by_qn_suffix(cbm_store_t *s, const char *project, const int n = 0; cbm_node_t *nodes = malloc(cap * sizeof(cbm_node_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - nodes = safe_realloc(nodes, cap * sizeof(cbm_node_t)); - } + safe_grow(nodes, n, cap, ST_GROWTH); memset(&nodes[n], 0, sizeof(cbm_node_t)); scan_node(stmt, &nodes[n]); n++; @@ -1748,10 +1727,7 @@ int cbm_store_list_files(cbm_store_t *s, const char *project, char ***out, int * if (!fp) { continue; } - if (n >= cap) { - cap *= ST_GROWTH; - files = safe_realloc(files, cap * sizeof(char *)); - } + safe_grow(files, n, cap, ST_GROWTH); files[n++] = heap_strdup(fp); } sqlite3_finalize(stmt); @@ -1781,10 +1757,7 @@ static int query_neighbor_names(sqlite3 *db, const char *sql, int64_t node_id, i if (!name) { continue; } - if (count >= cap) { - cap *= ST_GROWTH; - names = safe_realloc(names, (size_t)cap * sizeof(char *)); - } + safe_grow(names, count, cap, ST_GROWTH); names[count++] = strdup(name); } sqlite3_finalize(stmt); @@ -1947,10 +1920,7 @@ int cbm_store_find_edges_by_url_path(cbm_store_t *s, const char *project, const int n = 0; cbm_edge_t *edges = malloc(cap * sizeof(cbm_edge_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - edges = safe_realloc(edges, cap * sizeof(cbm_edge_t)); - } + safe_grow(edges, n, cap, ST_GROWTH); memset(&edges[n], 0, sizeof(cbm_edge_t)); scan_edge(stmt, &edges[n]); n++; @@ -2327,7 +2297,7 @@ int cbm_store_search(cbm_store_t *s, const cbm_search_params_t *params, cbm_sear rc = sqlite3_prepare_v2(s->db, sql, CBM_NOT_FOUND, &main_stmt, NULL); if (rc != SQLITE_OK) { store_set_error_sqlite(s, "search prepare"); - free(like_pattern); + safe_free(like_pattern); return CBM_STORE_ERR; } @@ -2340,10 +2310,7 @@ int cbm_store_search(cbm_store_t *s, const cbm_search_params_t *params, cbm_sear cbm_search_result_t *results = malloc(cap * sizeof(cbm_search_result_t)); while (sqlite3_step(main_stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - results = safe_realloc(results, cap * sizeof(cbm_search_result_t)); - } + safe_grow(results, n, cap, ST_GROWTH); memset(&results[n], 0, sizeof(cbm_search_result_t)); scan_node(main_stmt, &results[n].node); results[n].in_degree = sqlite3_column_int(main_stmt, ST_COL_9); @@ -2352,7 +2319,7 @@ int cbm_store_search(cbm_store_t *s, const cbm_search_params_t *params, cbm_sear } sqlite3_finalize(main_stmt); - free(like_pattern); + safe_free(like_pattern); out->results = results; out->count = n; @@ -2365,18 +2332,18 @@ void cbm_store_search_free(cbm_search_output_t *out) { } for (int i = 0; i < out->count; i++) { cbm_search_result_t *r = &out->results[i]; - free((void *)r->node.project); - free((void *)r->node.label); - free((void *)r->node.name); - free((void *)r->node.qualified_name); - free((void *)r->node.file_path); - free((void *)r->node.properties_json); + safe_str_free(&r->node.project); + safe_str_free(&r->node.label); + safe_str_free(&r->node.name); + safe_str_free(&r->node.qualified_name); + safe_str_free(&r->node.file_path); + safe_str_free(&r->node.properties_json); for (int j = 0; j < r->connected_count; j++) { - free((void *)r->connected_names[j]); + safe_str_free(&r->connected_names[j]); } - free(r->connected_names); + safe_free(r->connected_names); } - free(out->results); + safe_free(out->results); memset(out, 0, sizeof(*out)); } @@ -2431,10 +2398,7 @@ static int bfs_collect_edges(cbm_store_t *s, int64_t start_id, const cbm_node_ho cbm_edge_info_t *edges = malloc(ecap * sizeof(cbm_edge_info_t)); while (sqlite3_step(estmt) == SQLITE_ROW) { - if (en >= ecap) { - ecap *= ST_GROWTH; - edges = safe_realloc(edges, ecap * sizeof(cbm_edge_info_t)); - } + safe_grow(edges, en, ecap, ST_GROWTH); edges[en].from_name = heap_strdup((const char *)sqlite3_column_text(estmt, 0)); edges[en].to_name = heap_strdup((const char *)sqlite3_column_text(estmt, SKIP_ONE)); edges[en].type = heap_strdup((const char *)sqlite3_column_text(estmt, CBM_SZ_2)); @@ -2536,10 +2500,7 @@ int cbm_store_bfs(cbm_store_t *s, int64_t start_id, const char *direction, const cbm_node_hop_t *visited = malloc(cap * sizeof(cbm_node_hop_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - visited = safe_realloc(visited, cap * sizeof(cbm_node_hop_t)); - } + safe_grow(visited, n, cap, ST_GROWTH); scan_node(stmt, &visited[n].node); visited[n].hop = sqlite3_column_int(stmt, ST_COL_9); n++; @@ -2567,32 +2528,32 @@ void cbm_store_traverse_free(cbm_traverse_result_t *out) { return; } /* Free root */ - free((void *)out->root.project); - free((void *)out->root.label); - free((void *)out->root.name); - free((void *)out->root.qualified_name); - free((void *)out->root.file_path); - free((void *)out->root.properties_json); + safe_str_free(&out->root.project); + safe_str_free(&out->root.label); + safe_str_free(&out->root.name); + safe_str_free(&out->root.qualified_name); + safe_str_free(&out->root.file_path); + safe_str_free(&out->root.properties_json); /* Free visited */ for (int i = 0; i < out->visited_count; i++) { cbm_node_hop_t *h = &out->visited[i]; - free((void *)h->node.project); - free((void *)h->node.label); - free((void *)h->node.name); - free((void *)h->node.qualified_name); - free((void *)h->node.file_path); - free((void *)h->node.properties_json); + safe_str_free(&h->node.project); + safe_str_free(&h->node.label); + safe_str_free(&h->node.name); + safe_str_free(&h->node.qualified_name); + safe_str_free(&h->node.file_path); + safe_str_free(&h->node.properties_json); } - free(out->visited); + safe_free(out->visited); /* Free edges */ for (int i = 0; i < out->edge_count; i++) { - free((void *)out->edges[i].from_name); - free((void *)out->edges[i].to_name); - free((void *)out->edges[i].type); + safe_str_free(&out->edges[i].from_name); + safe_str_free(&out->edges[i].to_name); + safe_str_free(&out->edges[i].type); } - free(out->edges); + safe_free(out->edges); memset(out, 0, sizeof(*out)); } @@ -2711,10 +2672,7 @@ int cbm_store_get_schema(cbm_store_t *s, const char *project, cbm_schema_info_t int n = 0; cbm_label_count_t *arr = malloc(cap * sizeof(cbm_label_count_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_label_count_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].label = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].count = sqlite3_column_int(stmt, SKIP_ONE); n++; @@ -2736,10 +2694,7 @@ int cbm_store_get_schema(cbm_store_t *s, const char *project, cbm_schema_info_t int n = 0; cbm_type_count_t *arr = malloc(cap * sizeof(cbm_type_count_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_type_count_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].type = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].count = sqlite3_column_int(stmt, SKIP_ONE); n++; @@ -2757,34 +2712,34 @@ void cbm_store_schema_free(cbm_schema_info_t *out) { return; } for (int i = 0; i < out->node_label_count; i++) { - free((void *)out->node_labels[i].label); + safe_str_free(&out->node_labels[i].label); } - free(out->node_labels); + safe_free(out->node_labels); for (int i = 0; i < out->edge_type_count; i++) { - free((void *)out->edge_types[i].type); + safe_str_free(&out->edge_types[i].type); } - free(out->edge_types); + safe_free(out->edge_types); for (int i = 0; i < out->rel_pattern_count; i++) { - free((void *)out->rel_patterns[i]); + safe_str_free(&out->rel_patterns[i]); } - free(out->rel_patterns); + safe_free(out->rel_patterns); for (int i = 0; i < out->sample_func_count; i++) { - free((void *)out->sample_func_names[i]); + safe_str_free(&out->sample_func_names[i]); } - free(out->sample_func_names); + safe_free(out->sample_func_names); for (int i = 0; i < out->sample_class_count; i++) { - free((void *)out->sample_class_names[i]); + safe_str_free(&out->sample_class_names[i]); } - free(out->sample_class_names); + safe_free(out->sample_class_names); for (int i = 0; i < out->sample_qn_count; i++) { - free((void *)out->sample_qns[i]); + safe_str_free(&out->sample_qns[i]); } - free(out->sample_qns); + safe_free(out->sample_qns); memset(out, 0, sizeof(*out)); } @@ -2995,10 +2950,7 @@ static int arch_entry_points(cbm_store_t *s, const char *project, cbm_architectu int n = 0; cbm_entry_point_t *arr = calloc(cap, sizeof(cbm_entry_point_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_entry_point_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].name = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].qualified_name = heap_strdup((const char *)sqlite3_column_text(stmt, SKIP_ONE)); arr[n].file = heap_strdup((const char *)sqlite3_column_text(stmt, CBM_SZ_2)); @@ -3057,10 +3009,7 @@ static int arch_routes(cbm_store_t *s, const char *project, cbm_architecture_inf if (cbm_is_test_file_path(fp)) { continue; } - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_route_info_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].method = heap_strdup(""); arr[n].path = heap_strdup(name); @@ -3069,17 +3018,17 @@ static int arch_routes(cbm_store_t *s, const char *project, cbm_architecture_inf char *val; val = extract_json_string_prop(props, "\"method\"", ST_METHOD_PROP_LEN); if (val) { - free((void *)arr[n].method); + safe_str_free(&arr[n].method); arr[n].method = val; } val = extract_json_string_prop(props, "\"path\"", ST_PATH_PROP_LEN); if (val) { - free((void *)arr[n].path); + safe_str_free(&arr[n].path); arr[n].path = val; } val = extract_json_string_prop(props, "\"handler\"", ST_HANDLER_PROP_LEN); if (val) { - free((void *)arr[n].handler); + safe_str_free(&arr[n].handler); arr[n].handler = val; } n++; @@ -3109,10 +3058,7 @@ static int arch_hotspots(cbm_store_t *s, const char *project, cbm_architecture_i int n = 0; cbm_hotspot_t *arr = calloc(cap, sizeof(cbm_hotspot_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_hotspot_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].name = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].qualified_name = heap_strdup((const char *)sqlite3_column_text(stmt, SKIP_ONE)); arr[n].fan_in = sqlite3_column_int(stmt, CBM_SZ_2); @@ -3172,10 +3118,10 @@ static int arch_boundaries(cbm_store_t *s, const char *project, cbm_cross_pkg_bo char **npkgs = malloc(ncap * sizeof(char *)); while (sqlite3_step(nstmt) == SQLITE_ROW) { - if (nn >= ncap) { + if ((size_t)nn >= (size_t)ncap) { ncap *= ST_GROWTH; - nids = safe_realloc(nids, ncap * sizeof(int64_t)); - npkgs = safe_realloc(npkgs, ncap * sizeof(char *)); + nids = safe_realloc(nids, (size_t)ncap * sizeof(int64_t)); + npkgs = safe_realloc(npkgs, (size_t)ncap * sizeof(char *)); } nids[nn] = sqlite3_column_int64(nstmt, 0); const char *qn = (const char *)sqlite3_column_text(nstmt, SKIP_ONE); @@ -3189,10 +3135,10 @@ static int arch_boundaries(cbm_store_t *s, const char *project, cbm_cross_pkg_bo sqlite3_stmt *estmt = NULL; if (sqlite3_prepare_v2(s->db, esql, CBM_NOT_FOUND, &estmt, NULL) != SQLITE_OK) { for (int i = 0; i < nn; i++) { - free(npkgs[i]); + safe_free(npkgs[i]); } - free(nids); - free(npkgs); + safe_free(nids); + safe_free(npkgs); store_set_error_sqlite(s, "arch_boundaries_edges"); return CBM_STORE_ERR; } @@ -3216,10 +3162,10 @@ static int arch_boundaries(cbm_store_t *s, const char *project, cbm_cross_pkg_bo } sqlite3_finalize(estmt); for (int i = 0; i < nn; i++) { - free(npkgs[i]); + safe_free(npkgs[i]); } - free(nids); - free(npkgs); + safe_free(nids); + safe_free(npkgs); /* Sort by count descending */ for (int i = SKIP_ONE; i < bn; i++) { @@ -3239,8 +3185,8 @@ static int arch_boundaries(cbm_store_t *s, const char *project, cbm_cross_pkg_bo } if (bn > CBM_DECIMAL_BASE) { for (int i = ST_MAX_ITERATIONS; i < bn; i++) { - free(bfroms[i]); - free(btos[i]); + safe_free(bfroms[i]); + safe_free(btos[i]); } bn = ST_MAX_ITERATIONS; } @@ -3252,9 +3198,9 @@ static int arch_boundaries(cbm_store_t *s, const char *project, cbm_cross_pkg_bo result[i].to = btos[i]; result[i].call_count = bcounts[i]; } - free(bfroms); - free(btos); - free(bcounts); + safe_free(bfroms); + safe_free(btos); + safe_free(bcounts); *out_arr = result; *out_count = bn; return CBM_STORE_OK; @@ -3315,7 +3261,7 @@ static int arch_packages_from_qn(cbm_store_t *s, const char *project, } if (np > MAX_PREVIEW_NAMES) { for (int i = MAX_PREVIEW_NAMES; i < np; i++) { - free(pnames[i]); + safe_free(pnames[i]); } np = MAX_PREVIEW_NAMES; } @@ -3346,10 +3292,7 @@ static int arch_packages(cbm_store_t *s, const char *project, cbm_architecture_i int n = 0; cbm_package_summary_t *arr = calloc(cap, sizeof(cbm_package_summary_t)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(cbm_package_summary_t)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n].name = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); arr[n].node_count = sqlite3_column_int(stmt, SKIP_ONE); n++; @@ -3358,7 +3301,7 @@ static int arch_packages(cbm_store_t *s, const char *project, cbm_architecture_i /* Fallback: group by QN segment if no Package nodes */ if (n == 0) { - free(arr); + safe_free(arr); int rc = arch_packages_from_qn(s, project, &arr, &n); if (rc != CBM_STORE_OK) { return rc; @@ -3521,15 +3464,15 @@ static int arch_layers(cbm_store_t *s, const char *project, cbm_architecture_inf /* Cleanup */ for (int i = 0; i < bcount; i++) { - free((void *)boundaries[i].from); - free((void *)boundaries[i].to); + safe_str_free(&boundaries[i].from); + safe_str_free(&boundaries[i].to); } - free(boundaries); + safe_free(boundaries); for (int i = 0; i < nrpkgs; i++) { - free(route_pkgs[i]); + safe_free(route_pkgs[i]); } for (int i = 0; i < nepkgs; i++) { - free(entry_pkgs[i]); + safe_free(entry_pkgs[i]); } return CBM_STORE_OK; @@ -3716,20 +3659,20 @@ static void arch_collect_entries(char **dir_paths, int *dir_child_counts, char * static void arch_free_dirs(char **dir_paths, int *dir_child_counts, char ***dir_children, int *dir_children_caps, int dn, char **files, int fn) { for (int i = 0; i < dn; i++) { - free(dir_paths[i]); + safe_free(dir_paths[i]); for (int k = 0; k < dir_child_counts[i]; k++) { - free(dir_children[i][k]); + safe_free(dir_children[i][k]); } - free(dir_children[i]); + safe_free(dir_children[i]); } - free(dir_paths); - free(dir_child_counts); - free(dir_children); - free(dir_children_caps); + safe_free(dir_paths); + safe_free(dir_child_counts); + safe_free(dir_children); + safe_free(dir_children_caps); for (int i = 0; i < fn; i++) { - free(files[i]); + safe_free(files[i]); } - free(files); + safe_free(files); } static int arch_file_tree(cbm_store_t *s, const char *project, cbm_architecture_info_t *out) { @@ -3757,10 +3700,7 @@ static int arch_file_tree(cbm_store_t *s, const char *project, cbm_architecture_ if (!fp) { continue; } - if (fn >= fcap) { - fcap *= ST_GROWTH; - files = safe_realloc(files, fcap * sizeof(char *)); - } + safe_grow(files, fn, fcap, ST_GROWTH); files[fn++] = heap_strdup(fp); arch_register_file_dirs(fp, dir_paths, dir_child_counts, dir_children, dir_children_caps, &dn, dcap); @@ -3934,23 +3874,23 @@ static bool louvain_iteration(int n, int **adj, double **adj_w, const int *adj_n improved = true; } - free(nc_weight); - free(nc_seen); + safe_free(nc_weight); + safe_free(nc_seen); } - free(order); - free(comm_degree); + safe_free(order); + safe_free(comm_degree); return improved; } static void louvain_free_adj(int **adj, double **adj_w, int *adj_n, int *adj_cap, int n) { for (int i = 0; i < n; i++) { - free(adj[i]); - free(adj_w[i]); + safe_free(adj[i]); + safe_free(adj_w[i]); } - free(adj); - free(adj_w); - free(adj_n); - free(adj_cap); + safe_free(adj); + safe_free(adj_w); + safe_free(adj_n); + safe_free(adj_cap); } int cbm_louvain(const int64_t *nodes, int node_count, const cbm_louvain_edge_t *edges, @@ -3976,13 +3916,13 @@ int cbm_louvain(const int64_t *nodes, int node_count, const cbm_louvain_edge_t * int *adj_n = calloc(n, sizeof(int)); int *adj_cap = calloc(n, sizeof(int)); if (!adj || !adj_w || !adj_n || !adj_cap) { - free(adj); - free(adj_w); - free(adj_n); - free(adj_cap); - free(wsi); - free(wdi); - free(ww); + safe_free(adj); + safe_free(adj_w); + safe_free(adj_n); + safe_free(adj_cap); + safe_free(wsi); + safe_free(wdi); + safe_free(ww); return CBM_NOT_FOUND; } @@ -3991,9 +3931,9 @@ int cbm_louvain(const int64_t *nodes, int node_count, const cbm_louvain_edge_t * total_weight += ww[i]; adj_add_edge(adj, adj_w, adj_n, adj_cap, wsi[i], wdi[i], ww[i]); } - free(wsi); - free(wdi); - free(ww); + safe_free(wsi); + safe_free(wdi); + safe_free(ww); /* Initialize communities */ int *community = malloc(n * sizeof(int)); @@ -4009,7 +3949,7 @@ int cbm_louvain(const int64_t *nodes, int node_count, const cbm_louvain_edge_t * } *out = result; *out_count = n; - free(community); + safe_free(community); louvain_free_adj(adj, adj_w, adj_n, adj_cap, n); return CBM_STORE_OK; } @@ -4017,7 +3957,7 @@ int cbm_louvain(const int64_t *nodes, int node_count, const cbm_louvain_edge_t * /* Compute node degrees */ double *degree = calloc(n, sizeof(double)); if (!degree) { - free(community); + safe_free(community); louvain_free_adj(adj, adj_w, adj_n, adj_cap, n); return CBM_NOT_FOUND; } @@ -4045,8 +3985,8 @@ int cbm_louvain(const int64_t *nodes, int node_count, const cbm_louvain_edge_t * *out = result; *out_count = n; - free(community); - free(degree); + safe_free(community); + safe_free(degree); louvain_free_adj(adj, adj_w, adj_n, adj_cap, n); return CBM_STORE_OK; } @@ -4134,68 +4074,68 @@ void cbm_store_architecture_free(cbm_architecture_info_t *out) { return; } for (int i = 0; i < out->language_count; i++) { - free((void *)out->languages[i].language); + safe_str_free(&out->languages[i].language); } - free(out->languages); + safe_free(out->languages); for (int i = 0; i < out->package_count; i++) { - free((void *)out->packages[i].name); + safe_str_free(&out->packages[i].name); } - free(out->packages); + safe_free(out->packages); for (int i = 0; i < out->entry_point_count; i++) { - free((void *)out->entry_points[i].name); - free((void *)out->entry_points[i].qualified_name); - free((void *)out->entry_points[i].file); + safe_str_free(&out->entry_points[i].name); + safe_str_free(&out->entry_points[i].qualified_name); + safe_str_free(&out->entry_points[i].file); } - free(out->entry_points); + safe_free(out->entry_points); for (int i = 0; i < out->route_count; i++) { - free((void *)out->routes[i].method); - free((void *)out->routes[i].path); - free((void *)out->routes[i].handler); + safe_str_free(&out->routes[i].method); + safe_str_free(&out->routes[i].path); + safe_str_free(&out->routes[i].handler); } - free(out->routes); + safe_free(out->routes); for (int i = 0; i < out->hotspot_count; i++) { - free((void *)out->hotspots[i].name); - free((void *)out->hotspots[i].qualified_name); + safe_str_free(&out->hotspots[i].name); + safe_str_free(&out->hotspots[i].qualified_name); } - free(out->hotspots); + safe_free(out->hotspots); for (int i = 0; i < out->boundary_count; i++) { - free((void *)out->boundaries[i].from); - free((void *)out->boundaries[i].to); + safe_str_free(&out->boundaries[i].from); + safe_str_free(&out->boundaries[i].to); } - free(out->boundaries); + safe_free(out->boundaries); for (int i = 0; i < out->service_count; i++) { - free((void *)out->services[i].from); - free((void *)out->services[i].to); - free((void *)out->services[i].type); + safe_str_free(&out->services[i].from); + safe_str_free(&out->services[i].to); + safe_str_free(&out->services[i].type); } - free(out->services); + safe_free(out->services); for (int i = 0; i < out->layer_count; i++) { - free((void *)out->layers[i].name); - free((void *)out->layers[i].layer); - free((void *)out->layers[i].reason); + safe_str_free(&out->layers[i].name); + safe_str_free(&out->layers[i].layer); + safe_str_free(&out->layers[i].reason); } - free(out->layers); + safe_free(out->layers); for (int i = 0; i < out->cluster_count; i++) { - free((void *)out->clusters[i].label); + safe_str_free(&out->clusters[i].label); for (int j = 0; j < out->clusters[i].top_node_count; j++) { - free((void *)out->clusters[i].top_nodes[j]); + safe_str_free(&out->clusters[i].top_nodes[j]); } - free(out->clusters[i].top_nodes); + safe_free(out->clusters[i].top_nodes); for (int j = 0; j < out->clusters[i].package_count; j++) { - free((void *)out->clusters[i].packages[j]); + safe_str_free(&out->clusters[i].packages[j]); } - free(out->clusters[i].packages); + safe_free(out->clusters[i].packages); for (int j = 0; j < out->clusters[i].edge_type_count; j++) { - free((void *)out->clusters[i].edge_types[j]); + safe_str_free(&out->clusters[i].edge_types[j]); } - free(out->clusters[i].edge_types); + safe_free(out->clusters[i].edge_types); } - free(out->clusters); + safe_free(out->clusters); for (int i = 0; i < out->file_tree_count; i++) { - free((void *)out->file_tree[i].path); - free((void *)out->file_tree[i].type); + safe_str_free(&out->file_tree[i].path); + safe_str_free(&out->file_tree[i].type); } - free(out->file_tree); + safe_free(out->file_tree); memset(out, 0, sizeof(*out)); } @@ -4446,8 +4386,8 @@ void cbm_adr_sections_free(cbm_adr_sections_t *s) { return; } for (int i = 0; i < s->count; i++) { - free(s->keys[i]); - free(s->values[i]); + safe_free(s->keys[i]); + safe_free(s->values[i]); } memset(s, 0, sizeof(*s)); } @@ -4538,7 +4478,7 @@ int cbm_store_adr_update_sections(cbm_store_t *s, const char *project, const cha bool found = false; for (int j = 0; j < sections.count; j++) { if (strcmp(sections.keys[j], keys[i]) == 0) { - free(sections.values[j]); + safe_free(sections.values[j]); sections.values[j] = heap_strdup(values[i]); found = true; break; @@ -4561,13 +4501,13 @@ int cbm_store_adr_update_sections(cbm_store_t *s, const char *project, const cha snprintf(msg, sizeof(msg), "merged ADR exceeds %d chars (%d chars)", CBM_ADR_MAX_LENGTH, (int)strlen(merged)); store_set_error(s, msg); - free(merged); + safe_free(merged); return CBM_STORE_ERR; } /* Store merged */ rc = cbm_store_adr_store(s, project, merged); - free(merged); + safe_free(merged); if (rc != CBM_STORE_OK) { return rc; } @@ -4579,10 +4519,10 @@ void cbm_store_adr_free(cbm_adr_t *adr) { if (!adr) { return; } - free((void *)adr->project); - free((void *)adr->content); - free((void *)adr->created_at); - free((void *)adr->updated_at); + safe_str_free(&adr->project); + safe_str_free(&adr->content); + safe_str_free(&adr->created_at); + safe_str_free(&adr->updated_at); memset(adr, 0, sizeof(*adr)); } @@ -4605,10 +4545,7 @@ int cbm_store_find_architecture_docs(cbm_store_t *s, const char *project, char * int n = 0; char **arr = malloc(cap * sizeof(char *)); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (n >= cap) { - cap *= ST_GROWTH; - arr = safe_realloc(arr, cap * sizeof(char *)); - } + safe_grow(arr, n, cap, ST_GROWTH); arr[n++] = heap_strdup((const char *)sqlite3_column_text(stmt, 0)); } sqlite3_finalize(stmt); @@ -4620,12 +4557,12 @@ int cbm_store_find_architecture_docs(cbm_store_t *s, const char *project, char * /* ── Memory management ──────────────────────────────────────────── */ void cbm_node_free_fields(cbm_node_t *n) { - free((void *)n->project); - free((void *)n->label); - free((void *)n->name); - free((void *)n->qualified_name); - free((void *)n->file_path); - free((void *)n->properties_json); + safe_str_free(&n->project); + safe_str_free(&n->label); + safe_str_free(&n->name); + safe_str_free(&n->qualified_name); + safe_str_free(&n->file_path); + safe_str_free(&n->properties_json); } void cbm_store_free_nodes(cbm_node_t *nodes, int count) { @@ -4635,7 +4572,7 @@ void cbm_store_free_nodes(cbm_node_t *nodes, int count) { for (int i = 0; i < count; i++) { cbm_node_free_fields(&nodes[i]); } - free(nodes); + safe_free(nodes); } void cbm_store_free_edges(cbm_edge_t *edges, int count) { @@ -4643,17 +4580,17 @@ void cbm_store_free_edges(cbm_edge_t *edges, int count) { return; } for (int i = 0; i < count; i++) { - free((void *)edges[i].project); - free((void *)edges[i].type); - free((void *)edges[i].properties_json); + safe_str_free(&edges[i].project); + safe_str_free(&edges[i].type); + safe_str_free(&edges[i].properties_json); } - free(edges); + safe_free(edges); } void cbm_project_free_fields(cbm_project_t *p) { - free((void *)p->name); - free((void *)p->indexed_at); - free((void *)p->root_path); + safe_str_free(&p->name); + safe_str_free(&p->indexed_at); + safe_str_free(&p->root_path); } void cbm_store_free_projects(cbm_project_t *projects, int count) { @@ -4663,7 +4600,7 @@ void cbm_store_free_projects(cbm_project_t *projects, int count) { for (int i = 0; i < count; i++) { cbm_project_free_fields(&projects[i]); } - free(projects); + safe_free(projects); } void cbm_store_free_file_hashes(cbm_file_hash_t *hashes, int count) { @@ -4671,11 +4608,11 @@ void cbm_store_free_file_hashes(cbm_file_hash_t *hashes, int count) { return; } for (int i = 0; i < count; i++) { - free((void *)hashes[i].project); - free((void *)hashes[i].rel_path); - free((void *)hashes[i].sha256); + safe_str_free(&hashes[i].project); + safe_str_free(&hashes[i].rel_path); + safe_str_free(&hashes[i].sha256); } - free(hashes); + safe_free(hashes); } /* ── Vector search ────────────────────────��──────────────────────── */