Skip to content

SEGV in c_resolve_pending_template_calls: OOB read on NULL-terminated param_types array #215

@JasonDictos

Description

@JasonDictos

Bug

Indexing any repository containing nlohmann/json.hpp (or other heavily-templated C++ headers) crashes with a segfault in c_resolve_pending_template_calls.

Version

0.5.7 (also reproduced on current main)

Reproduction

# Minimal repo setup
mkdir -p /tmp/cbm-crash-repro && cd /tmp/cbm-crash-repro
git init
curl -sL https://github.com/nlohmann/json/releases/download/v3.12.0/json.hpp -o json.hpp
git add json.hpp && git commit -m "add nlohmann json"

# Crash
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-crash-repro"}'
# => Segmentation fault (core dumped)

Root Cause

param_types in CBMType.data.func is a NULL-terminated array (see type_rep.h:48), but two loops iterate using call_arg_count / arg_count as the bound instead of stopping at the NULL sentinel. When a template function is called with more arguments than formal parameters (common in heavily-templated C++ like nlohmann/json), this reads past the end of the array.

internal/cbm/lsp/c_lsp.c:304c_resolve_pending_template_calls:

for (int i = 0; i < call_arg_count; i++) {
    const CBMType* formal = callee->signature->data.func.param_types[i];
    if (!formal || !call_arg_types[i]) continue;  // BUG: should break on !formal, not continue

internal/cbm/lsp/type_registry.c:215score_overload_match:

for (int i = 0; i < arg_count; i++) {
    const CBMType* expected = f->signature->data.func.param_types[i];
    // ... same bug

Backtrace

#0  c_resolve_pending_template_calls () at internal/cbm/lsp/c_lsp.c:305
#1  c_resolve_calls_in_node () at internal/cbm/lsp/c_lsp.c:3200
#2  c_resolve_calls_in_node () [recursive]
#3  c_resolve_calls_in_node ()
#4  c_process_body_child ()
#5  c_lsp_process_file ()
#6  cbm_run_c_lsp ()
#7  cbm_extract_file () — source=nlohmann/json.hpp (967KB)
#8  extract_worker () at src/pipeline/pass_parallel.c:481

Fix

Change continue to break when hitting the NULL sentinel in both locations:

--- a/internal/cbm/lsp/c_lsp.c
+++ b/internal/cbm/lsp/c_lsp.c
@@ -303,7 +303,8 @@
         callee->signature->data.func.param_types) {
         for (int i = 0; i < call_arg_count; i++) {
             const CBMType* formal = callee->signature->data.func.param_types[i];
-            if (!formal || !call_arg_types[i]) continue;
+            if (!formal) break;  /* NULL-terminated array — stop, not skip */
+            if (!call_arg_types[i]) continue;

--- a/internal/cbm/lsp/type_registry.c
+++ b/internal/cbm/lsp/type_registry.c
@@ -214,8 +214,9 @@
     int score = 50;
     for (int i = 0; i < arg_count; i++) {
         const CBMType* expected = f->signature->data.func.param_types[i];
+        if (!expected) break;  /* NULL-terminated array — stop, not skip */
         const CBMType* actual = arg_types[i];
-        if (!expected || !actual || cbm_type_is_unknown(actual)) continue;
+        if (!actual || cbm_type_is_unknown(actual)) continue;

Tested: after the fix, the repo indexes successfully (4,178 nodes, 4,845 edges).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions