Skip to content

fix(parsers/js): union local var-types across rebinds so a reassigned receiver keeps every constructed-class dispatch edge - #144

Merged
gadievron merged 1 commit into
masterfrom
fix/js-alias-per-function-scope
Jul 14, 2026
Merged

fix(parsers/js): union local var-types across rebinds so a reassigned receiver keeps every constructed-class dispatch edge#144
gadievron merged 1 commit into
masterfrom
fix/js-alias-per-function-scope

Conversation

@gadievron

@gadievron gadievron commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What: In the JS/TS call graph, when a local variable is reassigned to a
different class, _extractLocalTypes now keeps EVERY constructed class for that
variable (an array, not last-write-wins), and _resolveMethodCall returns the
UNION of dispatch edges across the local-var and DI resolution paths instead of
early-returning a single one.

Why: a reassigned receiver (let s = new A(); …; s = new B(); s.run()) or a
DI-provided receiver was otherwise resolved to a single class, dropping the
dispatch edge to the other class's method — a call-graph FALSE NEGATIVE that can
make a real sink unreachable. Over-approximating the receiver type is the
reachability-safe direction for a security scan.

Trade-off (accurate semantics): this ADDS candidate edges (an
over-approximation). It can introduce false-positive edges (a precision cost); it
does NOT drop or invalidate a binding, and there is no recall loss. Exact-class
match (step 1) still short-circuits; DI-internal precedence is preserved.

How: localTypes[varName] becomes an array (push(className));
_resolveMethodCall returns matches (the union of candidate edges).

Tests: 3 new tests under tests/parsers/javascript/ (rebind, DI-collision,
exact-match short-circuit); full file green.

@gadievron
gadievron force-pushed the fix/js-alias-per-function-scope branch from 195405d to 1903d5e Compare July 10, 2026 16:12
…y hold

_extractLocalTypes recorded only the FIRST `const x = new C()` binding and
ignored bare reassignments, so `let y = new Foo(); y = new Bar(); y.doIt()`
resolved to Foo.doIt and the real last-assigned target Bar.doIt was unreachable
— a call-graph false negative.

Track every constructor type a local takes (declarations and bare
reassignments) and emit a dispatch edge to EACH candidate class. Over-
approximating a local's type is reachability-safe: a false-unreachable hides
exploitable code (the dangerous direction for a security scan), whereas an extra
edge does not. This keeps every genuinely reachable method reachable — both the
last-assigned type and a type live at an earlier call (`y.doIt(); y = new Bar()`).

_resolveMethodCall now returns the list of resolved ids (exact-name and DI paths
still resolve to a single id).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gadievron
gadievron force-pushed the fix/js-alias-per-function-scope branch from 1903d5e to f2d0e97 Compare July 10, 2026 18:08
@gadievron
gadievron marked this pull request as ready for review July 10, 2026 18:17
@gadievron gadievron changed the title fix(parsers/js): invalidate a local var-type on rebind to a different class fix(parsers/js): union local var-types across rebinds so a reassigned receiver keeps every constructed-class dispatch edge Jul 14, 2026
@gadievron
gadievron merged commit 8f51fc3 into master Jul 14, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant