$ Chapter 5 — Advanced Static Analysis Techniques
Chapter 5 — Advanced Static Analysis Techniques
15 May 2021
  1. Constructions of Abstract Domains
    1. Product Domain
  2. Advanced Iteration Techniques
    1. Loop Unrolling
    2. Delayed Widening
    3. Refinement of an Abstract Approximation of a Least Fixpoint
  3. Sparse Analysis
    1. Exploiting Spartial Sparsity
  4. Modular Analysis
  5. Backward Analysis
    1. Forward Semantics and backward Semantics
    2. Possible Applications
    3. Precision Refinement by Combined Forward and Backward Analysis

Constructions of Abstract Domains

Product Domain

Example: Coalescent product
  • let M#M_{\bot}^{\#} to be the abstract element defined by M#(x)=M#(y)=M_{\bot}^{\#}(x) = M_{\bot}^{\#}(y) = \bot

  • when M#M^{\#} maps any variable into \bot, it should be reduced into M#M_{\bot}^{\#}

  • => can improve the analysis precision of condition tests, etc.

  • this technique is also used in Julia abstract interpretation, e.g. abstract_statement

    • NOTE: this is why the abstract element is initialized NOT_FOUND, rather than Bottom, I think


Note
A static analysis based on a reduced product is in general more precise than a product of static analysis. Because the former can refine abstract information at any time, rather than only at the very end.

Advanced Iteration Techniques

M0#=M#Mk+1#=Mk#F#(Mk#)Mlim#:lfpF#:abstract interation function M_0^{\#} = M^{\#}\\ M_{k+1}^{\#} = M_k^{\#} \triangledown F^{\#}(M_k^{\#}) \\ M_{lim}^{\#}: \text{lfp} \\ F^{\#}: \text{abstract interation function}

Loop Unrolling

In practice, the first iteration(s) of a loop often has a special effect. => unroll the first NN iterations, and delays the abstract joins, which introduces a loss of precision.

M0#=M#Mk+1#={F#(Mk#)if k<NMk#F#(Mk#)otherwise M_0^{\#} = M^{\#}\\ M_{k+1}^{\#} = \begin{cases} F^{\#}(M_k^{\#}) &\text{if } k < N \\ M_k^{\#} \triangledown F^{\#}(M_k^{\#}) &\text{otherwise} \end{cases}

Delayed Widening

Use regular abstract union #\sqcup^{\#} for the first NN iterations in the loop.

M0#=M#Mk+1#={Mk##F#(Mk#)if kNMk#F#(Mk#)otherwise M_0^{\#} = M^{\#}\\ M_{k+1}^{\#} = \begin{cases} M_k^{\#} \sqcup^{\#} F^{\#}(M_k^{\#}) &\text{if } k \le N \\ M_k^{\#} \triangledown F^{\#}(M_k^{\#}) &\text{otherwise} \end{cases}

Refinement of an Abstract Approximation of a Least Fixpoint

Given a concrete fixpoint of the concrete function GG, applying G#G^{\#} again to any sound approximation of this concrete fixpoint produces another sound approximation.
This means that, once the algorithm stabilizes, we can simply compute one more iteration in the abstract level and still obtain a sound approximation of the states at the loop head.

x = 0;
while (rand() && x < 50) {
  x += 1;
}

Sparse Analysis

Exploiting Spartial Sparsity

Modular Analysis

E.g.:

xref: https://research.fb.com/inferbo-infer-based-buffer-overrun-analyzer/

Backward Analysis

We can actually design static analyses to compute over-approximate pre-conditions from a post-condition.x

Forward Semantics and backward Semantics

e.g. Boolean filter FBℱ_B reconciled.

FBℱ_B: takes as inputs a boolean expression BB and a set of states, filters out the states such that BB evaluate to false, keeping only those states such that BB evaluates to true.

FB(M)={mMB(m)=true} ℱ_B(M) = \{ m \in M | \llbracket B \rrbracket(m) = \text{true} \}

can be re-defined with backward semantics Bbwd\llbracket B \rrbracket_{\textbf{bwd}}:

Bbwd(v)={mMB(m)=v}FB(M)=MBbwd(true) \llbracket B \rrbracket_{\textbf{bwd}}(v) = \{ m \in M | \llbracket B \rrbracket(m) = v \} \\ ℱ_B(M) = M \cap \llbracket B \rrbracket_{\textbf{bwd}}(\text{true})

The semantics Bbwd\llbracket B \rrbracket_{\textbf{bwd}} is defined in backward style, as it takes a value (i.e. a result) and returns the set of states that lead to this value.

Possible Applications

Example program: given the abstract post-condition {x0,x1[,3]}\{x_0 \mapsto \top, x_1 \mapsto [-\infty, -3]\}, a backward-analysis returns an empty set (i.e. no pre-condition exists)

int x₀, x₁;
input(x₀);
if (x₀ > 0) {
  x₁ := x₀;
} else {
  x₁ := -x₀;
}

By computing an over-approximation of the sets of states leading to some given behavior, backward analysis:

Precision Refinement by Combined Forward and Backward Analysis

L0  ...
    if (y ≤ x) {
L1    ...
      if (x ≤ 4) {
L2      ...
        if (5 ≤ y) {
L3        ...

Backward analysis can be applied very locally to refine the analysis of tests, etc. as Julia's compiler does.