Skip to content

Indexer livelocks in the definitions pass on a real-world binary .res file (Godot 4 resource), while synthetic blobs of equal size index fine #2176

Description

@shIxx01

Version

codebase-memory-mcp 0.10.8

Platform

Windows (x64)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard

What happened, and what did you expect?

Environment

  • codebase-memory-mcp 0.10.8, build b4b403b1d7c4def3785f148b93f345ce8427858f4f5489ce28580c4387a336a6
  • Windows 11 x64, native install via install.ps1 (default path %LOCALAPPDATA%\Programs\codebase-memory-mcp)
  • 32 GB RAM, fresh install, no other CBM activity while testing
  • Triggered with codebase-memory-mcp cli --progress index_repository --repo-path <path>; the hang is in the spawned index worker

Summary

A binary file with the .res extension drives the definitions pass into an unbounded loop.

.res does not appear in the documented supported-language table, yet it is clearly parsed: adding a 4-line text file named tiny.res to an indexed project created 2 extra graph nodes. On a real-world Godot 4 binary resource (RSRC / ArrayMesh, 4,736,139 bytes) the pass then never terminates.

The surrounding project is 5 GDScript files totalling 5,107 bytes. GDScript itself is fine (see matrix).

Symptoms

  • Worker log ~/.cache/codebase-memory-mcp/logs/.worker-log-* ends at
    level=info msg=pass.start pass=definitions files=7 and never emits pass.done
  • CPU climbs monotonically: 138 → 162 → 194 CPU-seconds within ~3 minutes (~1.2 cores pinned), while RSS stays flat at 208 MB — so this is a livelock, not a memory blow-up
  • The output file <project>.db.stage.<id> stays at 0 bytes
  • The CLI prints nothing further after hint: this command started a temporary CBM daemon... — no error, no timeout, it never returns
  • Only killing the process ends it; each attempt leaves a new 0-byte .db.stage.<id> file behind

Reproduction

Reproduction

Every row is a fresh directory containing only the 5 project .gd files plus the one file listed below, indexed with cli index_repository. "Hang" = no completion after 30 s, process killed. Reproducible 2/2 for the full file, 10/10 clean for every other combination.

Added file Result
.gitignore indexed, 3,140 ms
.gitattributes indexed, 2,766 ms
.editorconfig indexed, 2,773 ms
project.godot indexed, 2,747 ms
scenes/*.tscn (3 scenes) indexed, 2,765 ms
piko_walk_mesh.res — 4,736,139 B Godot 4 ArrayMesh livelock, >30 s, killed
first 102,400 B of that same file, named .res indexed, 2,905 ms
the full 4.7 MB file renamed to .bin indexed, 2,759 ms
1,000,000 NUL bytes as .res indexed, 2,825 ms
2,000,000 NUL bytes as .res indexed, 2,886 ms
4-line text file as .res indexed, 2,744 ms (+2 nodes → .res is parsed)
4-line text file as .tres indexed, 2,757 ms

Baseline for comparison: the whole 5-file project without any extra file indexes in 1,236 ms (29 nodes, 34 edges), and a one-file test.gd project in 1,166 ms.

What this rules out

  • Not plain size — 2,000,000 NUL bytes with the same extension index fine
  • Not a long NUL run — the longest run of NUL bytes in the offending file is 44 bytes
  • Not content sniffing of unknown binaries — the identical 4.7 MB bytes are ignored when named .bin
  • Not GDScript, .gitignore, .gitattributes, .editorconfig, project.godot or .tscn — all index fine, alone and in combination
  • It needs the .res mapping and the structure of this specific real binary resource

Structural profile of the offending file

  • Magic RSRC, then ArrayMesh with long property-name strings (resource_local_to_scene, disable_specular_...)
  • 4,736,139 bytes total; 256 distinct byte values in every 256 KB block (fully binary throughout)
  • ~50 % NUL bytes in the data region, no degenerate block, longest NUL run 44 bytes
  • There are almost no newlines — the parser sees one very long "line"

Impact

Any repository containing a large binary .res asset (i.e. most 3D Godot projects) cannot be indexed at all — the indexer never returns and no partial result is written. Retrying does not help.

Workaround (verified)

Add *.res to .cbmignore in the indexed root:

.fennara/
addons/
.godot/
*.res

With that file present the same project indexes in 1,267 ms, status: indexed, 31 nodes / 36 edges.

Suggested direction

  1. Please confirm the intended mapping for .res — it is not in the supported-language table, so the mapping may be accidental
  2. Consider skipping binary content (or enforcing a hard input-size cap) before the definitions pass
  3. Consider a watchdog/timeout for the definitions pass so a single file cannot livelock the entire index — this would also help the other open unbounded-loop reports

Notes

  • A byte-identical copy of this asset exists in a second project on the same machine (identical MD5 14e044095a7499db94cae1b41ad4e339) and reproduces the same behaviour
  • The offending file can be provided on request, or it can be regenerated with Godot 4 by importing a large mesh and saving it as a binary .res

Logs


Diagnostics trajectory (memory / performance / leak issues)


Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstability/performanceServer crashes, OOM, hangs, high CPU/memorywindowsWindows-specific issues

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions