140 likes | 156 Views
An analysis tool for static analysis of programs, focusing on nullness and control flow graph analysis. Provides automated sharing of knowledge between analyzers.
E N D
Ridiculously Generic Program Analysis James Koppel, MIT
Actually writing a static analyzer Value val=null;if (left==NullConstant.v()) {if (right!=NullConstant.v()) {val = right; }} else if (right==NullConstant.v()) {if (left!=NullConstant.v()) {val = left; }}if (val!=null && valinstanceofLocal) {if (eqExprinstanceofJEqExpr) //a==nullhandleEquality(val,outBranch); else if…….. } NullnessAnalysis Source: Soot Framework
Problems • Syntactic pattern-matching • Runs on IR • Lots of cases; easy to miss • Specific to one version of one language • Must hard-code use of other analyzers
Goals • Define analyzers semantically • Derive most of tool automatically • Reuse work between languages • Reuse work between tools • Analyzers can automatically share knowledge
Ideas • Parametric interpretation, parametric syntax • From one program, multiple tools for multiple languages • Type-level obligations • Constrain what analyzers and languages may combine • Generalized nodes • One type definition gives AST, CFG, etc • Modular monadic semantics • Automatically combine different analyzers • Monads without lambdas!
General Type public interface Exp<C,L,S> { ….} Language Sort Eval Context
Parametric Interpretation Interpreter cond.eval(); // returns false elseBranch.eval(); ConcreteEvalContext Compiler <cond code> testeax jnzelse_branch <stmt 1 code> jmp end else_branch: <stmt2 code> end: Single Source of Truth public class If { …. public void eval(EvalContextctx) { ctx.eval(cond).branch( () -> ctx.eval(thenBranch), () -> ctx.eval(elseBranch)); } } DeferredEvalContext Abstract boolean type Control flow graph FlowGraphContext thenBranch . . . . . . . Dataflow analysis Symbolic execution
Parametric Syntax (C_PP, Assign) ∈ Has (C_PP, Deref) )∈ Has (Java, Assign) ∈ Has public class Assign<L> { …. public Assign(Var<L> lhs, Exp<L> rhs, Has<L, Assign> h) { …. } }
Statically checking compatibility prog :: ∀c ⊆ Stateful[c] ∩ Cont[c], Exp[c] Assign[U ⊆ Stateful[U]] CallCC[U ⊆ Cont [U]] Each expression constrains what EvalContext’s the program can run in prog[ConcreteEvalContext] prog[FlowGraphContext]
Generalized representation 1 + * x ConcreteExp public class BinOp extendsConcreteExp { private Exp lhs; private Exprhs; … } y z DataflowExp t1 := y *z t2 := x + t1
Generalized Representation 2 public class Seq<C> extendsConcreteExp<C, Void> { … publicContextVal<C, Void> eval(C c) { … } } public class IntLit<C> extendsConcreteExp<C, Integer> { … publicContextVal<C, Integer> eval(C c) { … } }
Monadic Combination Transfer: (Label -> Bool, Var -> NullnessLattice) -> (Var -> NullnessLattice, Label -> Bool) ReachabilityAnalyzer lift NullnessAnalyzer Transfer: (Var-> NullnessLattice) -> (Var -> NullnessLattice)
Monads without Lambdas public class Seq { … public void eval(EvalContextctx) { ctx.eval(stmt1); ctx.eval(stmt2); } } Could both be nondeterministic
Result: Nullness Analysis Analyzer a = new Analyzer(); a.addDataflowState( newNullnessLattice()); a.overrideTransferFunction( newBooleanConstantProp()); Evaluation will automatically case-split on (x == null) if(x != null || y != null) { … } else{ … } Evaluate condition; propagate states to branches