Skip to content

PHP: trait whose name collides with an aliased use … as import it composes → unbounded recursion in definitions pass, OOM (SIGKILL) #765

Open

Description

@KasaharaDefries

Version

codebase-memory-mcp 0.8.1

Platform

macOS (Apple Silicon)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

ui

What happened, and what did you expect?

A single ~6-line PHP trait drives the indexer into unbounded memory growth during the definitions pass: RSS climbs to ~50% of machine RAM (~18–20 GB on a 36 GB Mac) and the process is OOM-killed (SIGKILL, exit 137).

The trigger is a name collision between a trait and an aliased use … as … import that the trait composes:

  • trait Auditable …
  • … that does use \Vendor\Pkg\Auditable as AuditableBase; (imported short name Auditable == trait name)
  • … and composes it with use AuditableBase;
  • … and has at least one method with a non-empty body.

The extractor appears to ignore the as alias and resolve the composed trait back to the same-short-name local trait — i.e. it sees trait Auditable composing Auditable (itself), a self-referential trait — then recurses without bound while expanding it to process a method body.

This reproduces with mode: fast, and with CBM_LSP_DISABLED=1 and CBM_DISABLE_LSP_CROSS=1 — so it is not in the LSP resolvers that received depth guards in #720. It is in the definitions pass and needs its own recursion/expansion guard.

Expected: the file indexes instantly (it's 6 lines), as it does the moment any one of the three ingredients is removed.

Reproduction

No proprietary code needed. Create a directory with one file Auditable.php:

<?php
namespace App\Demo;

use Vendor\Pkg\Auditable as AuditableBase;  // aliased import; short name "Auditable" == trait name below

trait Auditable {
    use AuditableBase;                       // composes the aliased trait

    function f() { $x = 1; return $x; }      // any method with a non-empty body
}

Run:

CBM_LSP_DISABLED=1 codebase-memory-mcp cli index_repository \
  '{"repo_path":"/path/to/that/dir","mode":"fast"}'

→ RSS climbs to ~18–20 GB and the process is killed (exit 137). Vendor\Pkg\Auditable does not need to exist — it is an unresolved, pure short-name collision.

All three ingredients are required. Removing any one makes it index instantly at ~0 GB (verified, each run monitored for peak RSS):

Change from the repro above Result
rename the trait so its name ≠ Auditable ✅ OK, ~0 GB
drop use AuditableBase; (import present but not composed) ✅ OK, ~0 GB
empty method body {} (or no method at all) ✅ OK, ~0 GB
all three present (as above) ❌ OOM, ~20 GB, exit 137

Note: $this is not required — a body of just $x = 1; is enough.

Real-world origin: this is the shape of a trait that wraps the popular owen-it/laravel-auditing package, e.g. use OwenIt\Auditing\Auditable as AuditableBase; inside a local trait Auditable. So it hits real Laravel apps, not just synthetic input.

Logs

From the minimal single-file repro above — it dies right at the start of the definitions pass:

level=info msg=mem.init budget_mb=18432 total_ram_mb=36864
level=info msg=pipeline.discover files=1 elapsed_ms=0
level=info msg=pipeline.route path=full
level=info msg=pass.start pass=structure files=1
level=info msg=pass.done pass=structure nodes=2 edges=1
level=info msg=pass.timing pass=structure elapsed_ms=0
level=info msg=pipeline.mode mode=sequential files=1
level=info msg=pkgmap.scan_repo manifests=0
level=info msg=pkgmap.scan manifests_from_files=0 manifests_from_walk=0 entries=0
level=info msg=pass.start pass=definitions files=1
<no further output — SIGKILL / OOM, exit 137>

Anything else?

Activity

  1. added
    bugSomething isn't working
    parsing/qualityGraph extraction bugs, false positives, missing edges
    stability/performanceServer crashes, OOM, hangs, high CPU/memory
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Jul 3, 2026
  2. DeusData commented on Jul 3, 2026

    @DeusData
    Owner

    Thanks for reducing this to the trait/import-alias collision. Triage: high-priority PHP parser stability and extraction correctness under #390/#592.

    The expected behavior is alias-aware trait composition, or at worst an unknown/skipped relation. It must not recurse without bound. The first guard should be a tiny PHP fixture matching this collision and a subprocess/OOM-safe regression so the test runner is not killed by the bug.

  3. added this to the 0.9.1-rc milestone on Jul 8, 2026
  4. added a commit that references this issue on Jul 9, 2026
  5. DeusData commented on Jul 9, 2026

    @DeusData
    Owner

    Regression guards for this landed on main in #986 (merge f7127ee). The underlying fix shipped with #920's trait-alias guards in v0.9.0; the new test reproduces the exact name-collision hang from this report (verified RED against the unguarded code) and now pins it green permanently.

  6. KasaharaDefries commented on Jul 16, 2026

    @KasaharaDefries
    Author

    The v0.9.0 release binary still reproduces this (macOS darwin-arm64, checksum-verified from the release page), so #920's guards don't seem to cover this variant — here the collision is with the alias target's short name, not the alias itself:

    namespace App\Models\Traits;
    
    use OwenIt\Auditing\Auditable as AuditableBase; // vendor trait (vendor/ not indexed)
    
    trait Auditable            // short name == short name of the alias *target*
    {
        use AuditableBase;     // resolved by short name back into this very trait
        // ...
    }

    Symptoms on 0.9.0:

    • parallel.extract.progress stalls at N-4 of N every run; worker RSS grows until the memory-budget kill (SIGKILL at ~16–18 GB with budget_mb=18432). Reproduced 3/3 runs; also reproduces with CBM_INDEX_WORKER_TIMEOUT_S=1800, so it's the budget kill, not the watchdog timeout.
    • sample of the spinning worker thread:
    cbm_extract_file
      cbm_run_php_lsp
        php_lsp_collect_class_fields
          process_class_for_fields
            flatten_trait_into_class   <- hot: cbm_arena_sprintf / cbm_arena_strdup + memmove
    
    • Excluding this single 53-line trait file via .cbmignore → the same repo (~1760 files) indexes in 1.7 s / 709 MB RSS.

    Found the culprit by diffing CBM_LSP_DEBUG=1 per-module output against the discovered file list. Happy to test a main build or provide more detail if useful.

  7. DeusData commented on Jul 18, 2026

    @DeusData
    Owner

    Reopening based on the detailed post-close v0.9.0 reproduction. The alias target’s short name colliding with the local trait name is a distinct unbounded-recursion variant that the earlier guard did not cover: the definitions pass stalls, memory grows to the worker budget, and excluding the single trait restores a bounded run. This is back in the 0.9.1-rc queue under #390. The RED guard should preserve the exact AuditableBase/Auditable binding shape and prove bounded completion without relying on the worker budget kill.

  8. DeusData commented on Sep 26, 2026

    @DeusData
    Owner

    Thank you, @KasaharaDefries, for bisecting a whole Laravel app down to one trait, and for the precise sample of flatten_trait_into_class!

    We rebuilt your v0.9.0 shape on current main:

    • use OwenIt\Auditing\Auditable as AuditableBase; inside trait Auditable { use AuditableBase; … };
    • a model using that trait;
    • 70 more classes using it, to force the parallel path.

    It now indexes in about 5 seconds under a 1 GB memory budget, with no runaway growth. Could you confirm on v0.11.0 with the real repo, without the .cbmignore exclusion? If extract progress still stalls at N-4, a fresh sample of the worker would tell us which path is still unbounded.

  9. added
    awaiting-reporterWaiting on the reporter for info/repro; stale bot will warn then close
    on Sep 26, 2026
  10. github-actions commented on Sep 26, 2026

    @github-actions

    Thanks for the report! To move this forward we need a bit more so we can reproduce it ourselves:

    • the codebase-memory-mcp --version you're on
    • the exact steps or command you ran
    • a public repo (or a small dummy snippet) that shows the problem — please don't paste proprietary code

    Once that's here we'll pick it straight back up. Heads-up: issues left awaiting-reporter are automatically closed after a few weeks of silence, but a comment reopens the door anytime.

  11. github-actions commented on Oct 18, 2026

    @github-actions

    This issue has been waiting on more information for 21 days (a version, exact steps, or a public repro), so it's now marked stale. It will not be closed automatically — a maintainer reviews stale issues by hand. Adding a comment with the details clears the label and puts it straight back in the queue. We're happy to pick it back up the moment we can reproduce it.

  12. added
    staleNo activity after an info request; will be closed soon
    on Oct 18, 2026
  13. DeusData commented on Oct 19, 2026

    @DeusData
    Owner

    Thank you again for isolating the alias-target collision. Checking back on the September retest request: if you have safely tried a newer build, did the exact trait shape still stall? Please do not repeat an unbounded run just to keep this report open; I have no fresh real-repository confirmation to add.

  14. removed
    staleNo activity after an info request; will be closed soon
    on Oct 20, 2026
  15. DeusData commented on Oct 25, 2026

    @DeusData
    Owner

    Thank you again for the report. Any existing safe retest result for the aliased-trait case is welcome; please do not repeat an unbounded OOM run just for this follow-up.

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

    awaiting-reporterWaiting on the reporter for info/repro; stale bot will warn then closebugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memory

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions