Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Static Analyzer Factory logo

SAF — Static Analyzer Factory

License: MIT Python 3.12+ Rust 1.85+

A Rust-powered static analysis framework with a Python SDK for finding bugs in C/C++ programs. SAF turns LLVM IR into analyzable graphs — pointer analysis, value-flow, taint tracking — and exposes them through a clean Python API and CLI.

Key Features

  • Pointer analysis — Andersen-style with field sensitivity, context-sensitive (k-CFA), and flow-sensitive variants
  • Value-flow graphs — SSA + memory + interprocedural edges for precise data-flow tracking
  • Taint analysis — source/sink/sanitizer framework with trace extraction
  • IFDS solver — interprocedural, finite, distributive subset analysis
  • Built-in checkers — memory leaks, null dereference, double-free, use-after-free, and more
  • Python SDK — first-class API for scripting custom analyses
  • CLI — full analysis pipeline from the command line
  • Deterministic — identical inputs always produce byte-identical outputs
  • SARIF export — standard format for IDE and CI integration

Quick Start

SAF runs inside Docker. Two image variants are published, one per supported LLVM version — pick the tag whose LLVM matches the clang you use to compile your source.

git clone https://github.com/Static-Analyzer-Factory/static-analyzer-factory.git
cd static-analyzer-factory
make shell            # dev shell backed by LLVM 18 (default)
make shell-llvm22     # dev shell backed by LLVM 22 (opt-in)

See docs/book/src/getting-started/llvm-versions.md for the support policy and forward-incompatibility caveats.

Python SDK

from saf import Project, sources, sinks

proj = Project.open("program.ll")
q = proj.query()

# Find taint flows from user input to dangerous sinks
findings = q.taint_flow(
    sources=sources.function_param("main", 1),   # argv
    sinks=sinks.call("system", arg_index=0),
)

for f in findings:
    print(f"{f.severity}: {f.message}")
    print(f"  {f.source_location} -> {f.sink_location}")

CLI

# Run all built-in checkers
saf run program.ll --checkers all --format json --output findings.json

# Export call graph as DOT
saf export callgraph --input program.ll --format dot --output cg.dot

# Query points-to set for a specific value
saf query points-to 0x00000042 --input program.ll

Architecture

crates/
  saf-core/       # AIR (Analysis IR), config, deterministic IDs
  saf-frontends/  # LLVM bitcode + AIR-JSON frontends
  saf-analysis/   # CFG, call graph, PTA, value-flow, checkers
  saf-cli/        # Command-line interface
  saf-python/     # Python SDK (PyO3 bindings)
  saf-wasm/       # Browser build (playground)

Data flow:

Input (.ll / .bc)
  → Frontend → AIR (canonical IR)
    → Graph builders (CFG, call graph, def-use)
      → Pointer analysis → Value-flow graph
        → Queries & checkers → Findings (JSON / SARIF)

Benchmark Results

SAF's memory-safety checkers evaluated on the NIST Juliet C/C++ Test Suite, compared against SVF and Lotus.

Memory Leak (CWE-401) — 1,408 tests

Tool TP FP FN TN Precision Recall F1
SAF 694 85 16 613 89.1% 97.7% 0.932
SVF 666 144 44 554 82.2% 93.8% 0.876

Double Free (CWE-415) — 385 tests

Tool TP FP FN TN Precision Recall F1
SAF 180 5 15 185 97.3% 92.3% 0.947
SVF 170 0 25 190 100.0% 87.2% 0.932
Lotus 163 34 32 156 82.7% 83.6% 0.829

Use-After-Free (CWE-416) — 236 tests

Tool TP FP FN TN Precision Recall F1
SAF 90 4 28 114 95.7% 76.3% 0.849
Lotus 92 14 26 104 86.8% 78.0% 0.784

Null Pointer Dereference (CWE-476) — 468 tests

Tool TP FP FN TN Precision Recall F1
SAF 188 79 46 155 70.4% 80.3% 0.750
Lotus 199 55 35 179 78.3% 85.0% 0.792

Comparison with Other Tools

SAF is one of several program-analysis frameworks for LLVM IR and source code. The table below shows how SAF and its peers handle the dimensions program-analysis users compare on most often. Each peer has its own strengths — SVF is the established LLVM-IR value-flow framework, Phasar is the reference IFDS/IDE solver, Lotus bundles a broad catalog of alias analyses and concurrency analyses, CodeQL has the largest query library across many languages, and Infer ships deep checker libraries for industrial source-level analysis. The table aims to be informative, not a ranking. The same data is also rendered at the Comparison page.

Compared with: SVF · Phasar · Lotus · CodeQL · Infer

Dimension SAF SVF Phasar Lotus CodeQL Infer
Primary IR / target LLVM IR (C/C++) LLVM IR (C/C++) LLVM IR (C/C++) LLVM IR (C/C++) Source DB (10+ langs) Source AST (C/C++/ObjC/Java)
Pointer analysis CI, FS, CS, DDA CI, FS, CS, DDA Computed internally (CG + AA) Many bundled (DyckAA, SparrowAA, Sea-DSA, …) Different paradigm Different paradigm
PTA solver backends Worklist + Datalog (Ascent) Worklist (wave + bit-vector) LLVM AA + own CG algorithms Inclusion + unification + DDA QL → Datalog evaluation Separation logic
Value-flow / SVFG Yes Yes (headline) No (IFDS-based) DyckVFG variant DataFlow module No
Memory SSA Yes (hybrid: skeleton + demand-driven) Yes (MemSSA + MemRegion) No (IFDS-based instead) DyckVFG instead Different paradigm Different paradigm
IFDS / IDE solver Yes No Yes (specialty) Bundles Phasar No No
Taint analysis Yes (source/sink/sanitizer) Built on SVFG Yes (IFDS + IDE clients) Within KINT Yes (TaintTracking::Global) Yes (Quandary + Pulse)
Numeric / abstract domains Intervals, octagons, nullness, SCCP Intervals, numeric, relational (AE) Monotone framework (intra + inter) Symbolic execution + constant-time analysis Range analysis (built into queries) Pulse abstract domain + InferBO intervals
Concurrency / MTA Lockset + MHP LockAnalysis, MHP, TCT Out of scope Race, MPI, OpenMP, CUDA, kernel Race-detection queries RacerD
SMT-backed reasoning Z3 (conditions, reachability, alias) Saber path-sensitive solver PathSensitivity module SMT solvers + KINT + symbolic execution Datalog evaluation, no SMT Pulse uses SMT
Built-in checkers 5+ memory + taint 3 SABER (leak, dbl-free, file) 15+ IFDS/IDE clients Many (FiTx, KINT, Saber, Concurrency, Security) Hundreds per language 30+ (Pulse, RacerD, …)
Custom checker authoring Declarative YAML specs (may_reach modes) C++ subclassing (Saber framework) C++ IFDS/IDE problem subclasses C++ checker plug-ins QL queries (the language is the checker) OCaml + Infer.AI abstract domain
Interactive graph query API Python SDK + CLI (points-to, flows, taint) C++ API (raw graph traversal) C++ API (solver results) C++ API (raw) QL (queries are the model) Results only
Specialized data structures Roaring + FxHash + frozen indexer + Rayon Bit-vector points-to (BVDataPTAImpl) EdgeFunctionSingletonCache + SOO Varies by bundled backend BDDs + Datalog indexes Bi-abductive summaries + cache
SARIF export Native No No No Native (default) External adapter
License MIT AGPL-3.0 MIT MIT (mixed deps) Queries MIT; CLI proprietary MIT
Primary SDK Python (Rust core) C++ (Pysvf wrapper) C++ (C++20) C++ QL (DSL) OCaml
Multi-LLVM (simultaneous) LLVM 18 + 22 One per build (broad history) LLVM 16 + 17 LLVM 14 N/A N/A
Browser / WASM playground Yes (Pyodide + WASM) No No No No No
Byte-deterministic output Contractual (NFR-DET-001) Not advertised as contract Not advertised as contract Not advertised as contract Not advertised as contract Not advertised as contract
AI-agent skills 2 (feature-dev, checker-dev) No No AGENTS.md present No No

Every claim above is sourced in plans/189-research-notes.md.

Known Limitations

Analysis precision:

  • Default pointer analysis is context-insensitive; context-sensitive (k-CFA), flow-sensitive, and demand-driven variants are available but may be slower on large programs
  • Array elements are treated as a single abstract object — no per-index tracking

Indirect calls:

  • Indirect call resolution depends on PTA precision — targets that PTA misses are invisible to downstream analyses (ICFG, IFDS, taint)
  • When a call site resolves to multiple targets, only the first is used in value-flow and SVFG

Not yet supported:

  • Source-level frontends (Clang AST, rust-analyzer) — architecture is ready, implementation is planned
  • Symbolic execution

AI-Assisted Development

SAF ships coding-agent skills that guide AI assistants through SAF-specific development workflows. These work with Claude Code, Codex, and other coding agents.

Skill Purpose Install
saf-feature-dev 8-phase workflow for adding features (frontends, analysis, SDK, CLI) claude plugin add skills/saf-feature-dev/claude-code
saf-checker-dev Spec-first workflow for creating bug-finding checkers claude plugin add skills/saf-checker-dev/claude-code

These skills provide SAF-specific guidance including e2e testing recipes, SAF_LOG debug instrumentation, benchmark validation, and determinism checks. See each skill's README for details.

Documentation

  • Docs — concepts, API reference, getting started
  • Tutorials — step-by-step guides from hello-taint to custom checkers
  • Playground — try SAF in the browser (WASM build)
  • API Docs — Rust API reference (rustdoc)

Contributing

See CONTRIBUTING.md for development setup, coding conventions, and PR guidelines.

License

MIT

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

70 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages