fix(extract): descend into Go struct field_declaration_list - #1940
fix(extract): descend into Go struct field_declaration_list#1940ilyabrykau-orca wants to merge 4 commits into
Conversation
USAGE, WRITES and READS edges resolve through the same short-name registry as CALLS but never consulted the DeusData#725 cross-language guard. On a Go tree with eBPF C probes every Go identifier spelled like a C one produced a reference edge into the C file: 31.5% of all WRITES on the originally measured repo crossed the Go->C boundary, led by dozens of Go test locals named event writing a C probe's automatic variable. Add cbm_suppress_cross_language_ref() - the reference-edge analog of cbm_suppress_cross_language_suffix_match - and consult it on BOTH resolvers of each edge type: the sequential pass (pass_usages.c resolve_usage_edges registry-fallback branch, resolve_rw_edges) and their parallel twins (pass_parallel.c resolve_file_usages, resolve_file_rw). The sequential-only version of this change left 344 Go->C WRITES alive on a ~1150-file repo because large repos resolve through pass_parallel.c - the field census caught it, and the parallel-twin test now pins it. Unlike the CALLS guard the predicate takes no strategy parameter: a reference edge carries no import-closure evidence, so every registry strategy is a bare-name guess across a boundary. LSP-backed semantic references resolve before the fallback and are unaffected. JS/TS stay one family, and C/C++ count as one family too (.h maps to CBM_LANG_CPP, so a .c file referencing its own header is not a boundary). Field-validated on the ~1150-file Go+C repo: Go->C/C++ WRITES 835->0, USAGE 1545->0; C->Go 15/90->0; 6432 reference edges dropped in total, every one cross-language (Go->.json 3034, Go->.hpp/.h 1612, Go->.c 746, Go->.sh/.yaml/.yml 443, ...) and none same-language. CALLS and IMPORTS totals are byte-identical to main. Fixes DeusData#1928 Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
Reproduce-first probe for the two fixes on this branch: RED without the descend fix (count_defs_with_label(r, "Field") == 0, expected 3), GREEN with it. Asserts the three named fields with their declared types in return_type, the absence of the blank identifier, and that interface members keep extracting exactly as before. Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
|
Rebased onto the amended #1937 (its guard now covers the parallel resolvers). No semantic changes to this PR's commits; extraction+pipeline suites green, full venue leg green on the stack. Heads-up from field validation: with #1937 under it, this fix still surfaces ~26k same-language bare-name reference edges onto the new Field nodes (a local |
914aac0 to
e07a12b
Compare
The READS/WRITES resolvers and the USAGE registry fallback hand bare reference text to the short-name registry, which contains Field nodes - so once Go struct fields exist (DeusData#1935), every Go local err := ... binds whichever struct field is named err, project-wide: 21308 USAGE and 5191 WRITES onto Go fields on the measured repo, top target a test struct's field T collecting 3013 edges. In Go that binding is impossible by construction: a field is only reachable through a selector expression (x.f), and selector references resolve on the LSP path - every Field-targeted reference edge in the census carried dot-less text. Add cbm_go_suppress_bare_field_ref() next to the DeusData#1928 predicate and consult it at the same four sites (both READS/WRITES resolvers, both USAGE registry fallbacks): drop the bind when the file is Go, the target label is Field, and the reference text has no '.'. Go-gated because C#/Java/C++/Python method bodies legitimately reference their own members bare (cp_reads_writes_cs_static_field pins that shape). Field-validated on the DeusData#1940 stack: USAGE onto Go fields 21308 -> 0, WRITES 5191 -> 0; the only remaining field-targeted edges are 2466 CALLS, which are DeusData#1906/DeusData#1907's selector-guard territory. Reproduce- first pipeline probes (sequential + parallel twins) were RED on the stack without this commit. Fixes DeusData#1942 Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
The READS/WRITES resolvers and the USAGE registry fallback hand bare reference text to the short-name registry, which contains Field nodes - so once Go struct fields exist (DeusData#1935), every Go local err := ... binds whichever struct field is named err, project-wide: 21308 USAGE and 5191 WRITES onto Go fields on the measured repo, top target a test struct's field T collecting 3013 edges. In Go that binding is impossible by construction: a field is only reachable through a selector expression (x.f), and selector references resolve on the LSP path - every Field-targeted reference edge in the census carried dot-less text. Add cbm_go_suppress_bare_field_ref() next to the DeusData#1928 predicate and consult it at the same four sites (both READS/WRITES resolvers, both USAGE registry fallbacks): drop the bind when the file is Go, the target label is Field, and the reference text has no '.'. Go-gated because C#/Java/C++/Python method bodies legitimately reference their own members bare (cp_reads_writes_cs_static_field pins that shape). Field-validated on the DeusData#1940 stack: USAGE onto Go fields 21308 -> 0, WRITES 5191 -> 0; the only remaining field-targeted edges are 2466 CALLS, which are DeusData#1906/DeusData#1907's selector-guard territory. Reproduce- first pipeline probes (sequential + parallel twins) were RED on the stack without this commit. Fixes DeusData#1942 Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
Fixes #1935. Stacked on #1937 (the USAGE/WRITES cross-language guard) — the issue's own measurement shows why this must not land alone: ~4600 recovered
Fieldnodes namederr/ctx/path/_would otherwise mint ~5700WRITES/ ~22000USAGEname-collision edges through the unguarded reference resolver. The two tip commits + the test are this PR's own change; the base commit is #1937's.What
Go struct fields were never extracted — 0
Fieldnodes for ~5055 field declarations on the measured repo, while the 850Fieldnodes in the graph were all C/C++.find_class_body()returnstype_spec'stypechild:interface_typeholds its method specs directly → always worked;struct_type's only named child is afield_declaration_list, one level above thefield_declarationnodes the member loop looks for → every field silently skipped.go_field_types[] = {"field_declaration"}was already registered inlang_specs.c; the extractor just never reached them.How
go_normalize_struct_body()descendsstruct_type→field_declaration_listbeforeextract_class_fields()iterates, the same normalization step the Javaenum_body_declarationspath already does. A second commit skips the Go blank identifier_(struct padding in generated code — not a referenceable field; 55 nodes that collected 241 collision edges).Measured effect (from the issue)
0 → 4588 Go
Fieldnodes, each carrying its declared type inreturn_type. Embedded fields (~208) stay unrepresented by construction (nonamechild) — separate follow-up;lsp_embed_dispatchis unaffected. With #1937 under it,CALLSonto Go fields stay guarded (2466 → 417 by #1907's gate in the issue's stacked measurement) and theWRITES/USAGEcollision classes are dropped by the reference guard. Also unblocks func-typed-field call dispatch (r.fn(4)→Router.fn), which needs the field node to exist.Tests
extract_go_struct_fields_have_nodes: RED with the descend fix reverted —count_defs_with_label(r, "Field") == 0, expected 3— GREEN on the branch. Asserts the three named fields with declared types (string,int,*Config), the blank identifier's absence, and that interface members keep extracting exactly as before.scripts/test.shvenue leg (ASan+UBSan, all suites + contract steps): green on the stack.git clang-format --diff: clean.#1932 tracks the family; ordering constraint (#1928 first) is from the issue's own two-index measurement.