Skip to content

fix(analyzer, model): Fix a bunch of FN - #393

Draft
Saloed wants to merge 3 commits into
mainfrom
saloed/dataflowbench-boxing-and-prescan-pass-rules
Draft

fix(analyzer, model): Fix a bunch of FN#393
Saloed wants to merge 3 commits into
mainfrom
saloed/dataflowbench-boxing-and-prescan-pass-rules

Conversation

@Saloed

@Saloed Saloed commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

No description provided.

Saloed and others added 3 commits September 1, 2026 19:17
A callable stored in a collection and invoked after being read back was never
connected to its body, so taint flowing through it was lost. Two gates
collided.

Lambda callee resolution runs only in prescan: `tryExtractLambdaType` and
`TypeInfoSequentFlowFunction.handle` both return unless the phase is Prescan,
so the `TypeInfoAccessor` fact is produced at the allocation and consumed at
the callsite only in that phase. But `handlePhase` discarded every
config-derived rule during prescan, pass-through included -- and pass-through
is the only model for `Collection#add` and `Iterator#next`. The type-info fact
therefore could not cross the container, the receiver of the invocation carried
no type info, and the lambda body was analyzed in neither phase.

Pass-through rules describe how a value moves, not where taint starts or ends,
so prescan needs them for the very thing it exists to do: find the callsites
the full scan should look at. Sources, sinks and cleaners stay disabled, so
prescan still carries no taint of its own.

This also closes a second loss that only appears in the staged pipeline. With
the lambda body unreachable in prescan its sink was never discovered, so
`relevantRuleIds` carried no `TaintMethodSink` and `SemgrepRuleProvider`
dropped the whole rule before the full scan. The unit harness cannot show this
-- its rules have no serialized id -- so lifting the phase gates on type-info
instead would turn the tests green while leaving the miss in place.

Adds the DataFlowBench false-negative shapes as source/sink dataflow tests,
each paired with a control that isolates its cause. The misses that remain are
disabled with their measured cause recorded.

Verified: core JVM 313 tests / 0 failures, java-querylang 207 / 0 failures.
Not yet measured: prescan now does strictly more work and gets only 0.3x the
IFDS timeout, and a larger prescan also widens `relevantRuleIds` and so the
full scan. Needs an A/B on a real project before this is relied upon.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A tainted primitive stored into a collection and read back lost its taint,
because javac's implicit boxing had no model. `Integer.valueOf(int)` is an
unresolved JDK callee with no pass-through rule, so the fact was dropped at the
boxing call and every later step already saw a clean value -- the taint died
before the collection was even reached.

Boxing and unboxing are independent barriers: a value that is boxed and later
read back crosses both, so modelling only `valueOf` still loses the taint at
`intValue()`. Adds both directions for the eight wrapper types.
`Character#charValue` already existed and is left alone.

`overrides: false` keeps each rule on the wrapper that declares it. A receiver
typed as `java.lang.Number` resolves its accessor to `Number#intValue` and is
therefore not covered; that is deliberate, since an overriding rule there would
also claim `BigDecimal`, `AtomicInteger` and every other `Number`.

These are config rules, so they are only applied once prescan stops discarding
pass-through -- see the preceding commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The boxing pass-through rules this test needs live in `model/`, which the
scope-path check keeps in a separate pull request, so the test is enabled here
rather than alongside them. It fails until those rules land.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Saloed

Saloed commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@Saloed Saloed changed the title fix(core): Fix a bunch of FN fix(core, model): Fix a bunch of FN Sep 3, 2026
@misonijnik misonijnik changed the title fix(core, model): Fix a bunch of FN fix(core,model): Fix a bunch of FN Sep 3, 2026
@misonijnik misonijnik changed the title fix(core,model): Fix a bunch of FN fix(core, model): Fix a bunch of FN Sep 4, 2026
@misonijnik misonijnik changed the title fix(core, model): Fix a bunch of FN fix(analyzer, model): Fix a bunch of FN Sep 4, 2026
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