You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(pipeline): USAGE and WRITES edges have no cross-language guard — 31% of WRITES on a Go+C repo cross the Go/C boundary #1928
fix(pipeline): USAGE and WRITES edges have no cross-language guard
Status: fix open — PR #1937 (cbm_suppress_cross_language_ref() at all four resolver sites — sequential and parallel twins; the sequential-only first cut left 344 Go→C WRITES alive). Measured: Go→C/C++ WRITES 835 → 0, USAGE 1545 → 0, C→Go 15/90 → 0; 6432 reference edges dropped, all cross-language, none same-language; CALLS/IMPORTS byte-identical. Unblocks #1935 (with #1942 as the same-language other half).
What happens
#725 gave CALLS a cross-language guard (cbm_suppress_cross_language_suffix_match). USAGE, WRITES and READS resolve through the same short-name registry — pass_usages.c (resolve_usage_edges fallback, resolve_rw_edges) and their parallel twins in pass_parallel.c (resolve_file_usages, resolve_file_rw) — and never consult it. On a Go+C tree (any eBPF/kernel component), every identifier existing in both languages produces an edge across the boundary.
Representative: dozens of Go test functions each declaring a local event produced WRITES edges to a local variable inside an eBPF C probe. The full dropped-edge breakdown is wider than Go↔C: Go→.json 3034 (config keys), Go→.hpp/.h 1612, Go→.sh/.yaml 443.
Index both → a WRITES edge from the Go test into the C event. Expected: none — Go cannot touch a C translation unit's identifiers.
Detection recipe
SELECTe.type, count(*) FROM edges e
JOIN nodes s ONs.id=e.source_idJOIN nodes t ONt.id=e.target_idWHEREe.typeIN ('WRITES','USAGE','CALLS') ANDs.file_pathLIKE'%.go'AND (t.file_pathLIKE'%.c'ORt.file_pathLIKE'%.h'ORt.file_pathLIKE'%.cpp'ORt.file_pathLIKE'%.hpp')
GROUP BY1; -- repeat with source/target swapped
Fix shape (as landed)
One pure predicate next to the #725 guard. Two deliberate differences from CALLS: no strategy parameter (a reference edge carries no import-closure evidence, so every registry strategy is a bare-name guess across a boundary — the unpenalized-unique_name carve-out of #1572 does not apply), and C/C++ are one family (.h maps to CBM_LANG_CPP; a .c file referencing its own header is not a boundary). LSP-backed semantic references resolve before the fallback and never reach it — that path is where a genuine cgo binding (#1929) would live. JS/TS family exemption as in #725.
Fixed on main by d6417ada0ec5bb144c0694d076fc504b6fa14e06, merged as fcd8bfc1066db4f1649d3537579c355c4da34437 (#1937).
The guard is cbm_suppress_cross_language_ref(caller_lang, target_file_path) in registry.c, consulted on the registry-fallback branch of resolve_usage_edges and on resolve_rw_edges. Reviewed against the recall risk specifically: it fails open on every ambiguous input — unknown caller language, missing or empty target path, unknown target language, same language, the JS/TS family, and the C/C++ family all return "keep". It suppresses only when both languages are known and differ across families, which is where the bind is impossible by construction rather than merely unlikely.
Activity
fix(pipeline): guard USAGE/WRITES/READS against cross-language binds
fix(pipeline): a bare Go reference never binds a struct Field
fix(pipeline): a bare Go reference never binds a struct Field
fix(pipeline): a bare Go reference never binds a struct Field
fix(pipeline): a bare Go reference never binds a struct Field
DeusData commentedon Aug 31, 2026
Fixed on
mainbyd6417ada0ec5bb144c0694d076fc504b6fa14e06, merged asfcd8bfc1066db4f1649d3537579c355c4da34437(#1937).The guard is
cbm_suppress_cross_language_ref(caller_lang, target_file_path)inregistry.c, consulted on the registry-fallback branch ofresolve_usage_edgesand onresolve_rw_edges. Reviewed against the recall risk specifically: it fails open on every ambiguous input — unknown caller language, missing or empty target path, unknown target language, same language, the JS/TS family, and the C/C++ family all return "keep". It suppresses only when both languages are known and differ across families, which is where the bind is impossible by construction rather than merely unlikely.test(ci): make the Windows path guard fixture polyglot so CI indexes …
fix(graph): typedef'd C aggregates get nodes; member access binds by …