A Simple and Extensible Approach to Program Analysis David Darais - - PowerPoint PPT Presentation

β–Ά
a simple and extensible approach to program analysis
SMART_READER_LITE
LIVE PREVIEW

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


slide-1
SLIDE 1

A Simple and Extensible Approach to Program Analysis

David Darais University of Maryland University of Vermont

slide-2
SLIDE 2

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?

slide-3
SLIDE 3

My PL Doesn’t Have a Program Analyzer ☹

slide-4
SLIDE 4

Should I Write My Own Program Analyzer?

πŸ€•

slide-5
SLIDE 5

Writing Your Own Program Analyzer is Easy πŸ˜‹

If you know how to write an interpreter

slide-6
SLIDE 6

Interpreter => Analyzer

Sound Terminating Precise Extensible

Abstracting Definitional Interpreters

slide-7
SLIDE 7

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.

slide-8
SLIDE 8

Concrete Interpreter Static Analyzer

slide-9
SLIDE 9

Concrete
 Interpreter

slide-10
SLIDE 10

if(Nβ‰ 0){ x ≔ 100/N }

slide-11
SLIDE 11

if(Nβ‰ 0){ x ≔ 100/N } N=1

slide-12
SLIDE 12

if(Nβ‰ 0){ x ≔ 100/N } if(true){ x ≔ 100/N } N=1 N=1

slide-13
SLIDE 13

if(Nβ‰ 0){ x ≔ 100/N } N=1 if(true){ x ≔ 100/N } x ≔ 100/N N=1 N=1

slide-14
SLIDE 14

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

slide-15
SLIDE 15

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

slide-16
SLIDE 16

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

slide-17
SLIDE 17

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

slide-18
SLIDE 18

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

slide-19
SLIDE 19

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

slide-20
SLIDE 20

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

slide-21
SLIDE 21

Concrete
 Interpreter

slide-22
SLIDE 22

Monadic Concrete
 Interpreter

slide-23
SLIDE 23

eval : exp Γ— env ⇀ val Γ— env

slide-24
SLIDE 24

eval : exp β†’ M(val) M(val) ≔ env ⇀ val Γ— env eval : exp Γ— env ⇀ val Γ— env β‰ˆ

slide-25
SLIDE 25

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

slide-26
SLIDE 26

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

slide-27
SLIDE 27

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

slide-28
SLIDE 28

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

slide-29
SLIDE 29

if(N=0){ x ≔ 100/N }

slide-30
SLIDE 30

if(N=0){ x ≔ 100/N } N=0

βœ—

slide-31
SLIDE 31

if(N=0){ x ≔ 100/N } N=1

βœ“

slide-32
SLIDE 32

if(N=0){ x ≔ 100/N } N=ANY

?

slide-33
SLIDE 33

Monadic Concrete
 Interpreter

slide-34
SLIDE 34

Monadic Abstract
 Interpreter

slide-35
SLIDE 35

Abstract Values Join Results Variable Refinement

slide-36
SLIDE 36

β„€ ⌲ {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . βœ“ {+,-} OR βœ—

slide-37
SLIDE 37

β„€ ⌲ {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . βœ“ {+,-} OR βœ—

slide-38
SLIDE 38

β„€ ⌲ {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . βœ“ {+,-} OR βœ—

slide-39
SLIDE 39

β„€ ⌲ {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . βœ“ {+,-} OR βœ—

slide-40
SLIDE 40

β„€ ⌲ {-,0,+} 2 / ( 3 - 1 ) {+} / ({+} - {+}) {+} / {-,0,+} . βœ“ {+,-} OR βœ—

slide-41
SLIDE 41

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₃)

slide-42
SLIDE 42

Abstract Values Join Results Variable Refinement

slide-43
SLIDE 43

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₃)

slide-44
SLIDE 44

Abstract Values Join Results Variable Refinement

slide-45
SLIDE 45

if(Nβ‰ 0){ x ≔ 100/N } N=ANY

slide-46
SLIDE 46

if(Nβ‰ 0){ x ≔ 100/N } N=ANY x ≔ 100/N N∈{-,+}

slide-47
SLIDE 47

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) Γ— 𝔺

slide-48
SLIDE 48

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) Γ— 𝔺

slide-49
SLIDE 49

if(Nβ‰ 0){ x ≔ 100/N } N=ANY

βœ“

VERIFIED

slide-50
SLIDE 50

while(true){} <timeout>

slide-51
SLIDE 51

fact(5) <timeout>

slide-52
SLIDE 52

Monadic Abstract
 Interpreter

slide-53
SLIDE 53

Total Monadic Abstract
 Interpreter

slide-54
SLIDE 54

fact(ANY) <timeout>

slide-55
SLIDE 55

if(ANY ≀ 0) { 1 } else { ANY Γ— fact(ANY-1) } fact(ANY)

slide-56
SLIDE 56

{+} fact(ANY) if(ANY ≀ 0) { 1 } else { ANY Γ— fact(ANY-1) }

slide-57
SLIDE 57

fact(ANY) {+}

βŠ”

fact(ANY) if(ANY ≀ 0) { 1 } else { ANY Γ— fact(ANY-1) }

slide-58
SLIDE 58

⟦fact(ANY)⟧ = {+} βŠ” ⟦fact(ANY)⟧

slide-59
SLIDE 59

⟦fact(ANY)⟧ = {+} βŠ” ⟦fact(ANY)⟧ ⟦fact(ANY)⟧ = lfp(X). {+} βŠ” X

slide-60
SLIDE 60

⟦fact(ANY)⟧ = {+} βŠ” ⟦fact(ANY)⟧ ⟦fact(ANY)⟧ = lfp(X). {+} βŠ” X ⟦fact(ANY)⟧ = {+}

slide-61
SLIDE 61

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.

slide-62
SLIDE 62

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) }

slide-63
SLIDE 63

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) }

slide-64
SLIDE 64

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) }

slide-65
SLIDE 65

EVAL CACHING

slide-66
SLIDE 66

EVAL CACHING

$α΅’ $β‚’

slide-67
SLIDE 67

EVAL CACHING

$α΅’ $β‚’

slide-68
SLIDE 68

$β‚€(fact(ANY)) ≔ βˆ… $₁(fact(ANY)) ≔ {+} $β‚‚(fact(ANY)) ≔ {+}

slide-69
SLIDE 69

$β‚€(fact(ANY)) ≔ βˆ… $₁(fact(ANY)) ≔ {+} $β‚‚(fact(ANY)) ≔ {+}

slide-70
SLIDE 70

$β‚€(fact(ANY)) ≔ βˆ… $₁(fact(ANY)) ≔ {+} $β‚‚(fact(ANY)) ≔ {+}

slide-71
SLIDE 71

$β‚€(fact(ANY)) ≔ βˆ… $₁(fact(ANY)) ≔ {+} $β‚‚(fact(ANY)) ≔ {+}

βœ“

slide-72
SLIDE 72

while(true){} {}

slide-73
SLIDE 73

fact(ANY) {+}

slide-74
SLIDE 74

Total Monadic Abstract
 Interpreter

slide-75
SLIDE 75

Total Monadic Abstract Extensible
 Interpreter

slide-76
SLIDE 76

EVAL CACHING

slide-77
SLIDE 77

REACHABILITY CACHING EVAL

slide-78
SLIDE 78

β€œUnfixed” Interpreters

slide-79
SLIDE 79

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) }

slide-80
SLIDE 80

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) }

slide-81
SLIDE 81

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) }

slide-82
SLIDE 82

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

  • utput-trace ⟨e,ρ⟩

eval(e)

slide-83
SLIDE 83

REACHABILITY CACHING EVAL fix(ev-cache(ev-trace(ev)))

slide-84
SLIDE 84

if(fact(N)≀0){expensive()} dead = {expensive()} N=ANY

slide-85
SLIDE 85

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

  • utput ⟨ρ,e⟩

eval(e)

slide-86
SLIDE 86

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

  • utput ⟨ρ,e⟩

eval(e)

Sound Terminating Extensible Path+Flow-Sensitive Pushdown Polarity-Numeric Dead-code Analysis

slide-87
SLIDE 87

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

  • utput ⟨ρ,e⟩

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) …

slide-88
SLIDE 88

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.

slide-89
SLIDE 89

REACHABILITY CACHING EVAL fix(ev-cache(ev-trace(ev))) Effects:
 State[Env] Nondet Failure

slide-90
SLIDE 90

Effects: State[Env] Nondet Failure Monads:


S[Οƒβ™―] ND Fail

slide-91
SLIDE 91

Effects: State[Env] Nondet Failure Monads:


Path Sensitive

S[Οƒβ™―] ND Fail

slide-92
SLIDE 92

Monads:


ND S[Οƒβ™―] Fail

Effects:
 State[Env] Nondet Failure

Flow Insensitive

slide-93
SLIDE 93

Monads:
 Effects:
 State[Env] Nondet Failure

Flow Sensitive

FS[Οƒβ™―] Fail

slide-94
SLIDE 94

ND S[Οƒβ™―]

Concrete
 Semantics

S[Οƒ] ND Fail S[Οƒβ™―] ND Fail FS[Οƒβ™―] Fail Fail

Path
 Sensitive Flow
 Sensitive Flow Insensitive βŠ‘ βŠ‘ βŠ‘ βŠ‘ βŠ‘

One Interpreter

slide-95
SLIDE 95

More in the Papers

Soundness [OOPSLA ’15, ICFP ’17] Pushdown Precision [ICFP ’17] Sound Symbolic Execution [ICFP ’17] Code Available in Haskell + Racket [OOPLA ’15,ICFP ’17]

slide-96
SLIDE 96

Go and Write Your Own Program Analyzer πŸ˜‹

It’s just a slightly fancy interpreter

slide-97
SLIDE 97

Interpreter => Analyzer

Sound Terminating Precise Extensible

Abstracting Definitional Interpreters