Skip to content

feat(dataflow): vendored typed_ast-free scalpel as the default L4 oracle#111

Open
rahlk wants to merge 6 commits into
mainfrom
feat/vendor-scalpel-default-oracle
Open

feat(dataflow): vendored typed_ast-free scalpel as the default L4 oracle#111
rahlk wants to merge 6 commits into
mainfrom
feat/vendor-scalpel-default-oracle

Conversation

@rahlk

@rahlk rahlk commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

Vendor a minimal, typed_ast-free slice of python-scalpel 1.0b0 into codeanalyzer/dataflow/scalpel/ and make ScalpelAliasOracle the shipping-default L4 may-alias oracle on every supported Python — with no external python-scalpel/typed_ast dependency. The type-based oracle demotes to a pure runtime safety net.

Why

python-scalpel hard-depends on typed_ast, an abandoned package whose last release (1.5.5) has no wheel for Python 3.12+ and fails to build from source there. So pip install python-scalpel fails on 3.12/3.13/3.14, and scalpel — the primary L4 points-to oracle — was an optional extra that silently degraded to the coarser type-based oracle on modern Python. typed_ast is imported by exactly one scalpel module (typeinfer), which this analyzer never uses. Vendoring the small slice the oracle actually needs removes the typed_ast wall entirely.

How

  • Vendored codeanalyzer/dataflow/scalpel/ — exactly the 9-module SSA/cfg/core closure the oracle loads (verified free of typeinfer/typed_ast), copied verbatim from 1.0b0 except one patch: cfg/model.py's module-load import graphviz as gv is guarded so the unused visualization code no longer forces a graphviz dependency.
  • Apache-2.0 attribution — upstream LICENSE + a provenance README.md in the vendored dir + a top-level NOTICE entry.
  • Oraclescalpel_oracle.py imports the vendored path; the dead "scalpel not installed" fallback branch is removed (scalpel can't be absent now); the per-callable build-failure and per-query unresolved-path fallbacks to TypeBasedAliasOracle remain, so the may_alias interface stays total and never raises.
  • Depsastor added to core (a genuine runtime dep of scalpel's SSA; pure-Python, universal); the [scalpel] extra removed; requires-python unchanged at >=3.9.

Behavior change

On Python 3.12+ — and for anyone who never installed the old [scalpel] extra — L4's prov:["points-to"] DDG edges were derived from the type-based over-approximation; they are now scalpel-precise (a tighter subset). The prov:["ssa"] edges are unchanged, so the monotonicity invariant L3 ⊆ L4 still holds. Users who already had the [scalpel] extra on ≤3.11 see no change (same code). Recorded in CHANGELOG.md.

Testing

  • Verified on Python 3.12 (where PyCG and the vendored scalpel both work): the L4 suites (test_v2_l4, test_v2_l4_summary, test_dataflow_sdg, test_dataflow_defuse) and the test_l3_subset_of_l4 monotonicity gate pass, now genuinely exercising scalpel-derived points-to. New test/test_vendored_scalpel.py gates the typed_ast-free property (imports + computes SSA with no typed_ast), asserts scalpel is the default oracle, checks determinism, and includes a vendored-vs-upstream SSA fidelity check (skips where upstream can't install).
  • The vendoring was verified verbatim against a fresh upstream re-fetch (only the graphviz line differs).
  • CI (release.yml) runs on Python 3.10, where both PyCG and the vendored scalpel work; the removed [scalpel] extra doesn't affect its .[neo4j] install.

Note on Python 3.14

The analyzer's own default dev interpreter here is 3.14, where PyCG is independently broken (ast.Num.n was removed in 3.14), so the CLI L4 pipeline can't run end-to-end on 3.14 until that unrelated PyCG issue is addressed. This PR's typed_ast-free property is proven on 3.14 in isolation; the full L4 verification runs on 3.12. The scalpel-vendoring change itself is Python-version-agnostic.

rahlk added 6 commits July 22, 2026 15:57
Vendor the 9-module SSA/cfg/core slice of python-scalpel 1.0b0 (Apache-2.0,
typed_ast-free) into codeanalyzer/dataflow/scalpel/, making ScalpelAliasOracle
the shipping-default L4 oracle on Python 3.9-3.14+ with no external
python-scalpel/typed_ast dependency. Type-based oracle demotes to the runtime
safety net. Includes feasibility evidence, oracle rewiring, the L4 precision
behavior change, and the testing plan.
Repoint ScalpelAliasOracle.from_function at the vendored, typed_ast-free
codeanalyzer.dataflow.scalpel slice instead of the external python-scalpel
package, and drop the now-dead ImportError fallback branch in
make_alias_oracle -- Scalpel can no longer be "absent" since it ships in
the package. TypeBasedAliasOracle remains the runtime safety net for a
per-callable Scalpel build failure only.

Reframe the two L4 tests whose premise this repoint invalidates:
test_make_alias_oracle_falls_back_when_scalpel_absent now forces a
per-callable build failure instead of poisoning sys.modules["scalpel"]
(which no longer affects the vendored import path), and
test_scalpel_oracle_copy_chain drops its pytest.importorskip("scalpel")
guard since the vendored oracle is always present.
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