Skip to content

fix: unwatch deleted projects to prevent zombie reindex#537

Open
Golevka2001 wants to merge 3 commits into
DeusData:mainfrom
Golevka2001:main
Open

fix: unwatch deleted projects to prevent zombie reindex#537
Golevka2001 wants to merge 3 commits into
DeusData:mainfrom
Golevka2001:main

Conversation

@Golevka2001

@Golevka2001 Golevka2001 commented Jun 20, 2026

Copy link
Copy Markdown

Problem

When auto_index is enabled, opening a project directory triggers auto-indexing and registers the project with the file-change watcher. If the user later deletes that project via the delete_project MCP tool, the .db file is removed but the watcher entry persists.

The watcher continues polling the deleted project's git repository every 5–60 seconds. On each poll, it detects HEAD movement or a dirty working tree and invokes the full reindex pipeline — which operates on a database that no longer exists.

Reproduction scenario:

  1. Enable auto-index: codebase-memory-mcp config set auto_index true
  2. Start the MCP server from inside a git project directory
  3. The server auto-indexes and the watcher begins polling
  4. Delete the project: delete_project(project="<name>")
  5. Continue working in the same directory (git commit, pull, etc.)
  6. The watcher detects changes and attempts to reindex → error logs, wasted CPU, and unnecessary I/O on every poll cycle

cbm_watcher_unwatch() is fully implemented (watcher.c:316–332) but is never called from any production code path — only from tests.

Copilot AI review requested due to automatic review settings June 20, 2026 14:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes a “zombie reindex” scenario where deleting a project removes its .db but leaves the project registered with the file-change watcher, causing repeated failed reindex attempts and wasted CPU/I/O.

Changes:

  • Add a cbm_watcher_unwatch() call to the MCP delete_project handler after deleting the project DB.
  • Guard the unwatch call with if (srv->watcher).

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

Comment thread src/mcp/mcp.c
Comment on lines +1815 to +1817
if (srv->watcher) {
cbm_watcher_unwatch(srv->watcher, name);
}
Signed-off-by: Gol3vka <gol3vka@163.com>
@Golevka2001

Copy link
Copy Markdown
Author

Mind if I add a pending-free list? Unwatch defers the free there, poll_once drains it under lock before snapshotting—avoids the UAF without refcounting.

Signed-off-by: Gol3vka <gol3vka@163.com>
Signed-off-by: Gol3vka <gol3vka@163.com>
@Golevka2001

Copy link
Copy Markdown
Author

I have formatted the file with clang-format, please re-trigger the CI check.

@DeusData

Copy link
Copy Markdown
Owner

Thanks @Golevka2001 — unwatching deleted projects is the right fix and the deferred-free design is sound. One concern before merge: cbm_watcher_free also drains/frees pending_free, so if it can run while cbm_watcher_poll_once is mid-cycle there's a use-after-free / double-free window on the pending_free array. Please confirm the watcher thread is stopped/joined before cbm_watcher_free frees it (or guard the free with projects_lock). A small test exercising the delete→unwatch path would also help. 🙏

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.

3 participants