refactor(memory): add safe_free, safe_str_free, safe_buf_free, safe_grow to platform.h; cleanup#210
refactor(memory): add safe_free, safe_str_free, safe_buf_free, safe_grow to platform.h; cleanup#210map588 wants to merge 37 commits intoDeusData:mainfrom
Conversation
…crashes Three locations in store.c called sqlite3_prepare_v2 without checking the return code. If the statement fails to prepare (DB corruption, malformed SQL), subsequent bind_text and sqlite3_step calls dereference NULL, crashing the server. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t access The watcher's projects hash table was written by the main thread (watch/unwatch) and iterated by the watcher thread (poll_once) with no synchronization. Added cbm_mutex_t to the watcher struct and wrapped all hash table operations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Decorators previously only created DECORATES edges. A @login_required decorator was invisible to "find all references" queries because those look for CALLS and USAGE edges. Now resolve_decorator emits both DECORATES and CALLS edges. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Decorators previously only created DECORATES edges. References like
@login_required were invisible to "find all references" queries which
look for CALLS and USAGE edges. Now both sequential (resolve_decorator)
and parallel (resolve_def_decorators) paths emit a CALLS edge alongside
DECORATES.
Uses "{}" properties to avoid clobbering richer metadata from pass_calls
when a function both has @decorator and calls decorator() directly.
…L stmts - cypher: Add bounds check in lex_string_literal to prevent stack buffer overflow on string literals >4096 bytes. Escape sequences are always parsed correctly even past the truncation boundary. - cypher: Add malloc/calloc NULL checks in parse_props, parse_rel_types, parse_in_condition, and parse_case_expr. Growth paths use non-destructive realloc (temp pointer) so accumulated elements can be freed on OOM instead of leaking through safe_realloc's free-on-failure semantics. - store: Add sqlite3_prepare_v2 return code checks at 3 sites in cbm_store_schema_info and collect_pkg_names. Partially prepared statements are finalized before returning. Schema function cleans up partially populated output on failure. collect_pkg_names returns CBM_NOT_FOUND (not 0) to distinguish errors from empty results.
…threads - http_server: Replace lazy log mutex init with 3-state init (UNINIT → INITING → INITED) using atomic CAS. Concurrent callers spin until init completes, preventing use of uninitialized mutex. cbm_ui_log_append calls cbm_ui_log_init on first use so early startup logs are not dropped. - watcher: Add cbm_mutex_t to protect projects hash table. All accessors (watch, unwatch, touch, watch_count, poll_once) are guarded. poll_once snapshots project pointers under lock then polls without holding it, keeping the critical section small during git I/O and indexing. state_new OOM is handled with early return. - compat_thread: Add cbm_thread_detach() for POSIX and Windows. Both join() and detach() clear the handle on success across both platforms for consistent lifecycle tracking. - http_server: Detach index job threads to prevent handle leaks.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…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.
There was a problem hiding this comment.
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, andsafe_growhelpers alongsidesafe_reallocinsrc/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.
| /* 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)) | ||
|
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| /* 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) |
There was a problem hiding this comment.
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).
fix(cypher,store): prevent crashes from buffer overflow, OOM, and NULL stmts
fix(thread-safety): eliminate races in log mutex, watcher, and index threads
feat(pipeline): emit CALLS edges for decorator applications
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 8.0.1. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](actions/download-artifact@d3f86a1...3e5f45b) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.30.0 to 2.31.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](msys2/setup-msys2@4f806de...cafece8) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.31.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/attest-sbom](https://github.com/actions/attest-sbom) from 10926c72720ffc3f7b666661c8e55b1344e2a365 to bd218ad0dbcb3e146bd073d1d9c6d78e08aa8a0b. - [Release notes](https://github.com/actions/attest-sbom/releases) - [Changelog](https://github.com/actions/attest-sbom/blob/main/RELEASE.md) - [Commits](actions/attest-sbom@10926c7...bd218ad) --- updated-dependencies: - dependency-name: actions/attest-sbom dependency-version: bd218ad0dbcb3e146bd073d1d9c6d78e08aa8a0b dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.9.1 to 4.1.1. - [Release notes](https://github.com/sigstore/cosign-installer/releases) - [Commits](sigstore/cosign-installer@398d4b0...cad07c2) --- updated-dependencies: - dependency-name: sigstore/cosign-installer dependency-version: 4.1.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
…ownload-artifact-8.0.1 Bump actions/download-artifact from 4.3.0 to 8.0.1
…up-msys2-2.31.0 Bump msys2/setup-msys2 from 2.30.0 to 2.31.0
…ttest-sbom-bd218ad0dbcb3e146bd073d1d9c6d78e08aa8a0b Bump actions/attest-sbom from 10926c72720ffc3f7b666661c8e55b1344e2a365 to bd218ad0dbcb3e146bd073d1d9c6d78e08aa8a0b
…cosign-installer-4.1.1 Bump sigstore/cosign-installer from 3.9.1 to 4.1.1
|
Hey, thanks for publishing this PR. I will tackle this immediately after the 15th of April :) |
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.1 to 3.0.0. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](softprops/action-gh-release@153bb8e...b430933) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 3.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/attest-sbom](https://github.com/actions/attest-sbom) from 2.4.0 to 4.1.0. - [Release notes](https://github.com/actions/attest-sbom/releases) - [Changelog](https://github.com/actions/attest-sbom/blob/main/RELEASE.md) - [Commits](actions/attest-sbom@bd218ad...c604332) --- updated-dependencies: - dependency-name: actions/attest-sbom dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@bbbca2d...043fb46) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…attest-sbom-4.1.0 Bump actions/attest-sbom from 2.4.0 to 4.1.0
…s/action-gh-release-3.0.0 Bump softprops/action-gh-release from 2.6.1 to 3.0.0
…upload-artifact-7.0.1 Bump actions/upload-artifact from 7.0.0 to 7.0.1
…ts keeping safe_grow wrappers Co-authored-by: map588 <122550757+map588@users.noreply.github.com>
Centralize heap memory management into four safe wrappers alongside existing safe_realloc:
Applied across cypher.c, store.c, mcp.c, and pass_githistory.c, eliminating ~60 lines of repetitive free/grow boilerplate.