A Simple and Extensible Approach to Program Analysis
David Darais University of Maryland University of Vermont
A Simple and Extensible Approach to Program Analysis David Darais - - PowerPoint PPT Presentation
A Simple and Extensible Approach to Program Analysis David Darais University of Maryland University of Vermont Does my program cause a runtime error? Does my program allocate too much? Does my program sanitize all untrusted inputs? Does my
A Simple and Extensible Approach to Program Analysis
David Darais University of Maryland University of Vermont
Does my program cause a runtime error? Does my program allocate too much? Does my program sanitize all untrusted inputs? Does my program have any data races?
Should I Write My Own Program Analyzer?
If you know how to write an interpreter
Sound Terminating Precise Extensible
Abstracting Definitional Interpreters
Hypothesis:β¨ β¨ Itβs easier to write a precise semantics than an abstract semantics. Approach:β¨ β¨ Write, maintain and debug one precise semantics. Systematically derive multiple static analyzers.
Concrete Interpreter Static Analyzer
if(Nβ 0){ x β 100/N }
if(Nβ 0){ x β 100/N } N=1
if(Nβ 0){ x β 100/N } if(true){ x β 100/N } N=1 N=1
if(Nβ 0){ x β 100/N } N=1 if(true){ x β 100/N } x β 100/N N=1 N=1
if(Nβ 0){ x β 100/N } N=1 if(true){ x β 100/N } x β 100/N N=1 x=100 N=1 N=1 100
eval : exp Γ env β val Γ env eval(Var(x),Ο) β (Ο(x),Ο) eval(Assign(x,e),Ο) β (v,Οβ²) β eval(e,Ο) (v,Οβ²[xβ¦v]) eval(Op(o,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) (vβ,Οβ³) β eval(eβ,Οβ²) (Ξ΄(o,vβ,vβ),Οβ³) eval(If(eβ,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) cases vβ = true β eval(eβ,Οβ²) vβ = false β eval(eβ,Οβ²) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β val
eval : exp Γ env β val Γ env eval(Var(x),Ο) β (Ο(x),Ο) eval(Assign(x,e),Ο) β (v,Οβ²) β eval(e,Ο) (v,Οβ²[xβ¦v]) eval(Op(o,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) (vβ,Οβ³) β eval(eβ,Οβ²) (Ξ΄(o,vβ,vβ),Οβ³) eval(If(eβ,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) cases vβ = true β eval(eβ,Οβ²) vβ = false β eval(eβ,Οβ²) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β val
eval : exp Γ env β val Γ env eval(Var(x),Ο) β (Ο(x),Ο) eval(Assign(x,e),Ο) β (v,Οβ²) β eval(e,Ο) (v,Οβ²[xβ¦v]) eval(Op(o,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) (vβ,Οβ³) β eval(eβ,Οβ²) (Ξ΄(o,vβ,vβ),Οβ³) eval(If(eβ,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) cases vβ = true β eval(eβ,Οβ²) vβ = false β eval(eβ,Οβ²) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β val
eval : exp Γ env β val Γ env eval(Var(x),Ο) β (Ο(x),Ο) eval(Assign(x,e),Ο) β (v,Οβ²) β eval(e,Ο) (v,Οβ²[xβ¦v]) eval(Op(o,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) (vβ,Οβ³) β eval(eβ,Οβ²) (Ξ΄(o,vβ,vβ),Οβ³) eval(If(eβ,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) cases vβ = true β eval(eβ,Οβ²) vβ = false β eval(eβ,Οβ²) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β val
eval : exp Γ env β val Γ env eval(Var(x),Ο) β (Ο(x),Ο) eval(Assign(x,e),Ο) β (v,Οβ²) β eval(e,Ο) (v,Οβ²[xβ¦v]) eval(Op(o,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) (vβ,Οβ³) β eval(eβ,Οβ²) (Ξ΄(o,vβ,vβ),Οβ³) eval(If(eβ,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) cases vβ = true β eval(eβ,Οβ²) vβ = false β eval(eβ,Οβ²) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β val
eval : exp Γ env β val Γ env eval(Var(x),Ο) β (Ο(x),Ο) eval(Assign(x,e),Ο) β (v,Οβ²) β eval(e,Ο) (v,Οβ²[xβ¦v]) eval(Op(o,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) (vβ,Οβ³) β eval(eβ,Οβ²) (Ξ΄(o,vβ,vβ),Οβ³) eval(If(eβ,eβ,eβ),Ο) β (vβ,Οβ²) β eval(eβ,Ο) cases vβ = true β eval(eβ,Οβ²) vβ = false β eval(eβ,Οβ²) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β val
eval : exp Γ env β val Γ env
eval : exp β M(val) M(val) β env β val Γ env eval : exp Γ env β val Γ env β
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) return Ξ΄(o,vβ,vβ) eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) cases vβ = true β eval(eβ) vβ = false β eval(eβ) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β valβ¨ M(A) β env β A Γ env
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) return Ξ΄(o,vβ,vβ) eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) cases vβ = true β eval(eβ) vβ = false β eval(eβ) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β valβ¨ M(A) β env β A Γ env
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) return Ξ΄(o,vβ,vβ) eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) cases vβ = true β eval(eβ) vβ = false β eval(eβ) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β valβ¨ M(A) β env β A Γ env
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) return Ξ΄(o,vβ,vβ) eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) cases vβ = true β eval(eβ) vβ = false β eval(eβ) env β var β val val β πΊ β β€ Ξ΄ : op Γ val Γ val β valβ¨ M(A) β env β A Γ env
if(N=0){ x β 100/N }
if(N=0){ x β 100/N } N=0
if(N=0){ x β 100/N } N=1
if(N=0){ x β 100/N } N=ANY
Abstract Values Join Results Variable Refinement
β€ β² {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . β {+,-} OR β
β€ β² {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . β {+,-} OR β
β€ β² {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . β {+,-} OR β
β€ β² {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . β {+,-} OR β
β€ β² {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . β {+,-} OR β
env β var β val val β β(πΊ) β β({-,0,+}) Ξ΄ : op Γ val Γ val β val Γ πΊ β¦_β§ : val β β(πΊ) refine : exp Γ πΊ β M(void)β¨ M(A) β env β β(A Γ env) Γ πΊ
Could the operation fail?
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ)
Abstract Values Join Results Variable Refinement
env β var β val val β β(πΊ) β β({-,0,+}) Ξ΄ : op Γ val Γ val β val Γ πΊ β¦_β§ : val β β(πΊ) refine : exp Γ πΊ β M(void)β¨ M(A) β env β β(A Γ env) Γ πΊ eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ)
Abstract Values Join Results Variable Refinement
if(Nβ 0){ x β 100/N } N=ANY
if(Nβ 0){ x β 100/N } N=ANY x β 100/N Nβ{-,+}
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) env β var β val val β β(πΊ) β β({-,0,+}) Ξ΄ : op Γ val Γ val β val Γ πΊ β¦_β§ : val β β(πΊ) refine : exp Γ πΊ β M(void)β¨ M(A) β env β β(A Γ env) Γ πΊ
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) env β var β val val β β(πΊ) β β({-,0,+}) Ξ΄ : op Γ val Γ val β val Γ πΊ β¦_β§ : val β β(πΊ) refine : exp Γ πΊ β M(void)β¨ M(A) β env β β(A Γ env) Γ πΊ
if(Nβ 0){ x β 100/N } N=ANY
VERIFIED
while(true){} <timeout>
fact(5) <timeout>
fact(ANY) <timeout>
if(ANY β€ 0) { 1 } else { ANY Γ fact(ANY-1) } fact(ANY)
{+} fact(ANY) if(ANY β€ 0) { 1 } else { ANY Γ fact(ANY-1) }
fact(ANY) {+}
β
fact(ANY) if(ANY β€ 0) { 1 } else { ANY Γ fact(ANY-1) }
β¦fact(ANY)β§ = {+} β β¦fact(ANY)β§
β¦fact(ANY)β§ = {+} β β¦fact(ANY)β§ β¦fact(ANY)β§ = lfp(X). {+} β X
β¦fact(ANY)β§ = {+} β β¦fact(ANY)β§ β¦fact(ANY)β§ = lfp(X). {+} β X β¦fact(ANY)β§ = {+}
Q: How to teach interpreters to solve least- fixpoint equations between evaluation configurations and analysis results? A: Caching
Darais, Labich, Nguyα» n, Van Horn. Abstracting Definitional Interpreters. ICFP β17.
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval-cache(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval-cache(eβ) vβ β eval-cache(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval-cache(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval-cache(eβ) β¦vββ§ β false β do refine(eβ,false) eval-cache(eβ) eval-cache : exp β M(val) eval-cache(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) }
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval-cache(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval-cache(eβ) vβ β eval-cache(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval-cache(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval-cache(eβ) β¦vββ§ β false β do refine(eβ,false) eval-cache(eβ) eval-cache : exp β M(val) eval-cache(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) }
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval-cache(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval-cache(eβ) vβ β eval-cache(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval-cache(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval-cache(eβ) β¦vββ§ β false β do refine(eβ,false) eval-cache(eβ) eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval-cache(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval-cache(eβ) vβ β eval-cache(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval-cache(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval-cache(eβ) β¦vββ§ β false β do refine(eβ,false) eval-cache(eβ) eval-cache : exp β M(val) eval-cache(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) }
EVAL CACHING
EVAL CACHING
$α΅’ $β
EVAL CACHING
$α΅’ $β
$β(fact(ANY)) β β $β(fact(ANY)) β {+} $β(fact(ANY)) β {+}
$β(fact(ANY)) β β $β(fact(ANY)) β {+} $β(fact(ANY)) β {+}
$β(fact(ANY)) β β $β(fact(ANY)) β {+} $β(fact(ANY)) β {+}
$β(fact(ANY)) β β $β(fact(ANY)) β {+} $β(fact(ANY)) β {+}
while(true){} {}
fact(ANY) {+}
EVAL CACHING
REACHABILITY CACHING EVAL
βUnfixedβ Interpreters
eval : exp β M(val) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval-cache(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval-cache(eβ) vβ β eval-cache(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval-cache(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval-cache(eβ) β¦vββ§ β false β do refine(eβ,false) eval-cache(eβ) eval-cache : exp β M(val) eval-cache(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) }
ev : (exp β M(val)) β (exp β M(val)) eval(Var(x)) β do Ο β get-env return Ο(x) eval(Assign(x,e)) β do v β eval-cache(e) Ο β get-env put-env Ο[xβ¦v] return v eval(Op(o,eβ,eβ)) β do vβ β eval-cache(eβ) vβ β eval-cache(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ eval(If(eβ,eβ,eβ)) β do vβ β eval-cache(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval-cache(eβ) β¦vββ§ β false β do refine(eβ,false) eval-cache(eβ) ev-cache : (exp β M(val)) β (exp β M(val)) eval-cache(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) }
ev-cache : (exp β M(val)) β (exp β M(val)) ev-cache(eval)(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) } ev : (exp β M(val)) β (exp β M(val)) ev(eval)(Var(x)) β do Ο β get-env return Ο(x) ev(eval)(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v ev(eval)(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ ev(eval)(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) ev : (exp β M(val)) β (exp β M(val)) ev(eval)(Var(x)) β do Ο β get-env return Ο(x) ev(eval)(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v ev(eval)(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ ev(eval)(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) ev-cache : (exp β M(val)) β (exp β M(val)) ev-cache(eval)(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) }
ev : (exp β M(val)) β (exp β M(val)) ev(eval)(Var(x)) β do Ο β get-env return Ο(x) ev(eval)(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v ev(eval)(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ)β¨ join-cases err = true β fail always β return vβ ev(eval)(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) ev-cache : (exp β M(val)) β (exp β M(val)) ev-cache(eval)(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } else { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) } ev-trace : (exp β M(val)) β (exp β M(val)) ev-trace(eval)(e) β do Ο β get-env
eval(e)
REACHABILITY CACHING EVAL fix(ev-cache(ev-trace(ev)))
if(fact(N)β€0){expensive()} dead = {expensive()} N=ANY
ev : (exp β M(val)) β (exp β M(val)) ev(eval)(Var(x)) β do Ο β get-env return Ο(x) ev(eval)(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v ev(eval)(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ) if(err) { fail } return vβ ev(eval)(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) ev-cache : (exp β M(val)) β (exp β M(val)) ev-cache(eval)(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) } ev-trace : (exp β M(val)) β (exp β M(val)) ev-trace(eval)(e) β do Ο β get-env
eval(e)
ev : (exp β M(val)) β (exp β M(val)) ev(eval)(Var(x)) β do Ο β get-env return Ο(x) ev(eval)(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v ev(eval)(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ) if(err) { fail } return vβ ev(eval)(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) ev-cache : (exp β M(val)) β (exp β M(val)) ev-cache(eval)(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) } ev-trace : (exp β M(val)) β (exp β M(val)) ev-trace(eval)(e) β do Ο β get-env
eval(e)
Sound Terminating Extensible Path+Flow-Sensitive Pushdown Polarity-Numeric Dead-code Analysis
ev : (exp β M(val)) β (exp β M(val)) ev(eval)(Var(x)) β do Ο β get-env return Ο(x) ev(eval)(Assign(x,e)) β do v β eval(e) Ο β get-env put-env Ο[xβ¦v] return v ev(eval)(Op(o,eβ,eβ)) β do vβ β eval(eβ) vβ β eval(eβ) (vβ,err) β Ξ΄(o,vβ,vβ) if(err) { fail } return vβ ev(eval)(If(eβ,eβ,eβ)) β do vβ β eval(eβ) join-cases β¦vββ§ β true β do refine(eβ,true) eval(eβ) β¦vββ§ β false β do refine(eβ,false) eval(eβ) ev-cache : (exp β M(val)) β (exp β M(val)) ev-cache(eval)(e) β do Ο β get-env if(seen(β¨e,Οβ©)) { return cached(β¨e,Οβ©) } { mark-seen(β¨e,Οβ©) v β eval(e) update-cache(β¨e,Οβ© β¦ v) } ev-trace : (exp β M(val)) β (exp β M(val)) ev-trace(eval)(e) β do Ο β get-env
eval(e)
Sound Terminating Extensible Path+Flow-Sensitive Pushdown Polarity-Numeric Dead-code Analysis (context sensitivity) (object sensitivity) (path+flow sens) (new numeric abs) (objects+closures) (symbolic execution) β¦
Q: How to easily obtain variations in path and flow sensitivity for an analyzer. A: Monads
Darais, Might, Van Horn. Galois Transformers and Modular Abstract Interpreters. OOPSLA β15.
REACHABILITY CACHING EVAL fix(ev-cache(ev-trace(ev))) Effects:β¨ State[Env] Nondet Failure
Effects: State[Env] Nondet Failure Monads:β¨
S[Οβ―] ND Fail
Effects: State[Env] Nondet Failure Monads:β¨
S[Οβ―] ND Fail
Monads:β¨
ND S[Οβ―] Fail
Effects:β¨ State[Env] Nondet Failure
Monads:β¨ Effects:β¨ State[Env] Nondet Failure
FS[Οβ―] Fail
ND S[Οβ―]
Concrete⨠Semantics
S[Ο] ND Fail S[Οβ―] ND Fail FS[Οβ―] Fail Fail
Pathβ¨ Sensitive Flowβ¨ Sensitive Flow Insensitive β β β β β
One Interpreter
Soundness [OOPSLA β15, ICFP β17] Pushdown Precision [ICFP β17] Sound Symbolic Execution [ICFP β17] Code Available in Haskell + Racket [OOPLA β15,ICFP β17]
Itβs just a slightly fancy interpreter
Sound Terminating Precise Extensible
Abstracting Definitional Interpreters