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 37 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 37 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.

map588 and others added 10 commits April 4, 2026 19:08
…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.
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 thread src/foundation/platform.h
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 thread src/foundation/platform.h
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.
map588 and others added 16 commits April 6, 2026 10:23
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
@DeusData DeusData added the enhancement New feature or request label Apr 6, 2026
@DeusData
Copy link
Copy Markdown
Owner

DeusData commented Apr 7, 2026

Hey, thanks for publishing this PR. I will tackle this immediately after the 15th of April :)

map588 and others added 10 commits April 12, 2026 00:47
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants