Skip to content

fix(summaries): keep nothing of the blocks constant propagation proves unreachable - #259

Merged
SizzleUnrlsd merged 3 commits into
mainfrom
fix/summary-reachability
Oct 15, 2026
Merged

SizzleUnrlsd merged 3 commits into
mainfrom
fix/summary-reachability

Conversation

@SizzleUnrlsd

Copy link
Copy Markdown
Contributor

Summary

A summary carried the effects of blocks constant propagation proves unreachable: a sink, a return, a value merged at a join, an argument mutation under if False: or while False: were reported at every caller, through any number of project functions.

Change:

  • A block proven unreachable has no outgoing state in the summary's dataflow (_DependenceProblem.flow) and is skipped by the final pass. Its stores, calls, returns and writes never happen, and the phis of its successors ignore it.
  • Blocks that may run are kept, whatever decides them at run time: a parameter, or a module-level name intraprocedural constant propagation does not resolve.
  • Reachability is judged per block. An infeasible edge between two reachable blocks is still followed, which keeps the summary conservative.
  • The selection check added in feat(code-injection): report attributes chosen by input and then called #257 is now implied; the invocation check stays.

Verification

  • tests/test_summary_reachability.py, new: 11 tests.

    • 6 reproductions fail on main: a sink under if False/while False, a return, a value merged at a join, a mutated argument, and two levels of functions.
    • 5 controls stay reported: a parameter flag, a module-level constant, and the same effects in reachable blocks.

    No existing test or snapshot changed.

  • Mutation check: removing either guard fails the new tests.

  • Full suite green, apart from the local test_packaging metadata issue. ruff check and mypy clean.

  • Corpus: no finding added or removed in any of the 19 regression repositories, nor on mitmproxy (73 findings).

Closes #258

@SizzleUnrlsd SizzleUnrlsd added the bug Something isn't working label Oct 15, 2026
@SizzleUnrlsd SizzleUnrlsd self-assigned this Oct 15, 2026
The fix of #258 keeps every cache key between commits of one version; the engine version, part of every key, is what delivers it to cached projects.
…eave it unwritten

NonlocalWrite.kept says the function may return without writing the name, and no record means it never does; NonlocalResult carries the variable's value before the call, which the caller keeps there, joined with what may be written. A write that cannot run, a write on some paths only, or none at all no longer erases the caller's taint. PyIR schema 2, cache format 16. Part of #258.
@SizzleUnrlsd
SizzleUnrlsd merged commit dbf88f8 into main Oct 15, 2026
10 checks passed
@SizzleUnrlsd
SizzleUnrlsd deleted the fix/summary-reachability branch October 15, 2026 23:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

summaries: a sink in unreachable code of a project function is reported at its callers

1 participant