Skip to content

refactor(memory): add safe_free, safe_str_free, safe_buf_free, safe_grow to platform.h; cleanup#210

Open
map588 wants to merge 3 commits intoDeusData:mainfrom
map588:refactor/safe-memory-wrappers
Open

refactor(memory): add safe_free, safe_str_free, safe_buf_free, safe_grow to platform.h; cleanup#210
map588 wants to merge 3 commits intoDeusData:mainfrom
map588:refactor/safe-memory-wrappers

Conversation

@map588
Copy link
Copy Markdown
Contributor

@map588 map588 commented Apr 5, 2026

Centralize heap memory management into four safe wrappers alongside existing safe_realloc:

  • safe_free(ptr): frees and NULLs any pointer to prevent double-free
  • safe_str_free(&str): frees const char* with NULL-out (replaces free((void*)str))
  • safe_buf_free(buf, &count): frees array and zeros its count
  • safe_grow(arr, n, cap, factor): one-line capacity-doubling realloc

Applied across cypher.c, store.c, mcp.c, and pass_githistory.c, eliminating ~60 lines of repetitive free/grow boilerplate.

…row to platform.h

Centralize heap memory management into four safe wrappers alongside
existing safe_realloc:

- safe_free(ptr): frees and NULLs any pointer to prevent double-free
- safe_str_free(&str): frees const char* with NULL-out (replaces free((void*)str))
- safe_buf_free(buf, &count): frees array and zeros its count
- safe_grow(arr, n, cap, factor): one-line capacity-doubling realloc

Applied across cypher.c, store.c, mcp.c, and pass_githistory.c,
eliminating ~60 lines of repetitive free/grow boilerplate.
Copilot AI review requested due to automatic review settings April 5, 2026 20:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes heap memory management into platform.h helpers and applies them across the store, cypher parser, MCP grep collection, and git-history parsing to reduce repetitive free/grow boilerplate and improve consistency.

Changes:

  • Add safe_free, safe_str_free, safe_buf_free, and safe_grow helpers alongside safe_realloc in src/foundation/platform.h.
  • Replace many direct free(...) and manual capacity-growth blocks with the new wrappers across multiple modules.
  • Standardize “free + NULL-out” behavior for heap-owned strings and arrays in several cleanup paths.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/foundation/platform.h Introduces new “safe” memory-management wrappers/macros used across the codebase.
src/store/store.c Replaces many manual free/realloc growth patterns with safe_* helpers across store queries and free functions.
src/cypher/cypher.c Updates parser/lexer/result cleanup and dynamic array growth to use the new wrappers.
src/mcp/mcp.c Simplifies grep-match dynamic array growth with safe_grow.
src/pipeline/pass_githistory.c Simplifies commit-list growth with safe_grow in both libgit2 and popen implementations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +34 to +65
/* 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))

Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

safe_free/safe_buf_free implement pointer-nullification by casting &(ptr) to void **. In standard C this is not type-safe: writing through a void ** that actually points to (e.g.) a char * object can violate strict-aliasing rules and is undefined behavior under optimization. Suggest implementing safe_free/safe_buf_free as statement macros that operate directly on the original lvalue (free then assign NULL), or using a C11 _Generic wrapper to preserve the correct pointer-to-pointer type without void ** casting.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Comment on lines +66 to +74
/* 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)
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The safe_grow comment says it "doubles capacity" and "evaluates to the new arr", but the macro is a do { ... } while (0) statement and grows by multiplying cap by the caller-provided factor. Please update the comment to match the actual semantics to avoid misuse/confusion (especially since callers might pass factors other than 2).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants