Static Analysis

Structural Medium oracle Predictive

Pattern-matching and dataflow analysis over the source without executing it. Covers the space between a linter (style and local patterns) and a type checker (type soundness): null dereferences, unreachable code, resource leaks, taint flow, API misuse. It subsumes neither neighbor: it carries no style rules and proves no types. It also gets adopted differently. A linter arrives with the toolchain and runs from the first commit; a dataflow analyzer is slower, noisier out of the box, and has to be tuned against the codebase before its output is worth reading, so teams switch it on deliberately and usually later. What it buys for that cost is reasoning that follows values across function boundaries and down particular execution paths, which neither neighbor attempts.

In practice

A reading is a finding with a rule, a location, and usually a trace:

infer run -- javac ./src
src/Checkout.java:42: error: NULL_DEREFERENCE
  object `user` last assigned on line 38 could be null
  -> called from placeOrder(src/Checkout.java:24)
  -> where `user` is the return of findById(session, id)

The trace is the value. A linter points at a line; a static analyzer reconstructs how a value got there, which is what makes the finding actionable rather than just located.

How it gets gamed

  • Disable, don’t fix. Like the linter, // nolint and rule exclusions turn findings into noise by decree. The suppression ratio is the meta-signal.
  • Narrow the analysis scope. Excluding generated directories, vendored code, or “legacy” modules shrinks what the analyzer sees while keeping its name on the pipeline.
  • Tune for silence. Lowering sensitivity thresholds until the finding count drops to zero keeps the sensor and discards its reach.
  • Baseline erosion. Freezing known findings into a baseline and only failing on new ones, while the baseline grows forever because old findings are “someone else’s problem.”

The meta-signal is the trend of the unsuppressed finding count per commit. A rising baseline or a falling suppression ratio both indicate the sensor being neutered.

What it cannot detect

Static analysis cannot detect behavioral correctness — it reasons about the code, not its execution. It will not catch a wrong algorithm that type-checks and follows every pattern rule. It also produces false positives on code paths the analyzer’s abstraction can’t prove safe, which is the cost of path-sensitivity: precision trades against noise. A clean scan says nothing about what the code does at runtime — that belongs to observability events and runtime invariants.

Categories: Structural

References

Publications

Tooling

  • InferSeparation logic and taint analysis by Meta
  • CodeQLSemantic code analysis engine by GitHub
  • SemgrepMulti-language static analysis with custom rules
  • Clang Static AnalyzerPath-sensitive analysis for C/C++/Objective-C
  • PylintPython static analysis and style checker