alloy - people.csail.mit.edupeople.csail.mit.edu/dnj/talks/madison09/madison09.pdf · university of...
TRANSCRIPT
The first principle is that you must not fool yourself, and you are the
easiest person to fool. Richard P. Feynman
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
not code
very painful
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
agile methods
not code
very painful
formalize design
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
agile methods
not code
very painful
formalize designJava, ML, Ruby, C, ...
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
agile methods
not code
very painful
formalize designJava, ML, Ruby, C, ...
exercise design
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
agile methods
not code
very painful
formalize designJava, ML, Ruby, C, ...
exercise designwrite tests
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
agile methods
not code
very painful
verbose
painfulpoor coverage
formalize designJava, ML, Ruby, C, ...
exercise designwrite tests
early formalization
formal methods
formalize designZ, VDM, B, ...
exercise designwrite proofs
agile methods
not code
very painful
a dream?
succinct, expressive modelsanimation & property checkinghigh coverage without proofs
no unit tests to writecode synthesized automatically
a heresy
what matters most?finding subtle bugs?
instant feedback
Small Tower of 6 Gears, Arthur Ganson
a heresy
what matters most?finding subtle bugs?
instant feedback
Small Tower of 6 Gears, Arthur Ganson
transatlantic alloymotivation
structural description + automation
Oxford, home of Z Pittsburgh, home of SMV
how we got here
version language analysis sample case study
Nitpick (1995) relational calculussubset of Z
relation enumeration
IPv6 routing
Alloy 1 (1999) + navigation expsquantifiers
WalkSAT, DP intentionalnaming
Alloy 2 (2001) + relational opshigher arity
Chaff, Berkminsymmetry, sharing
key management,Unison filesync
Alloy 3 (2004) + subtyping, overloading
atomization(bad)
Mondexelectronic purse
Alloy 4 (2007) + meta, sequences, arithmetic
sparse matricesbetter sharing
flash file systems,code analyses
simpli!ed voting
AliceBobCarol
!
Alice 125Bob 63Carol 168
voters
ballots
boxes
tally
tally should correspond to voter’s choiceswhat properties establish this requirement?
basic structuresig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) } class diagram
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
adding factssig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
adding factssig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }
fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
adding factssig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }
run { }
fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
adding factssig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }
run { }
checking an assertionsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
checking an assertionsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
pred CountingCorrect { all c: Candidate | Tally.count[c] = #ballot.choice.c }check CountingCorrect
checking an assertionsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
pred CountingCorrect { all c: Candidate | Tally.count[c] = #ballot.choice.c }check CountingCorrect
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
5
5
5 5
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
1
5
5
5 5
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
16
1
5
5
5 5
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
16
1
5
5
5 5
225
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
16
1
5
5
5 5
225
total space: 2235
!xing & recheckingsig Candidate {}sig Voter { ballot: lone Ballot }sig Ballot { choice: lone Candidate}sig Box { cast: set Ballot }one sig Tally { ballots: set Ballot, count: Candidate -> one Int } { all c: Candidate | count[c] = #(ballots & choice.c) }
fact AllVotersCastBallots { all v: Voter | some x: Box | v.ballot in x.cast }fact NoBoxStuffing { all x: Box, b: x.cast | some v: Voter | v.ballot = b }fact NoTallyStuffing { all b: Tally.ballots | some x: Box | b in x.cast }fact NoBallotsLost { all x: Box | x.cast in Tally.ballots }
fact NoSharedBallots { all b: Ballot | lone ballot.b }check CountingCorrect for 5
16
1
5
5
5 5
225
total space: 2235
!ve ideas
analysis ideasanalysis as solving
small scope analysissolving by SAT
language ideasgeneralizing dot
funky idioms
idea: analysis = solvingdoes system S have property P?
S(beh) ∧¬P(beh)
is operation op deterministic?op(s,s’) ∧ op(s,s”) ∧ s’ ≠ s”
idea: analysis = solvingdoes system S have property P?
S(beh) ∧¬P(beh)
is operation op deterministic?op(s,s’) ∧ op(s,s”) ∧ s’ ≠ s”
does method m meet pre, post?m(s,s’) ∧ pre(s) ∧ ¬post(s,s’)
idea: analysis = solvingdoes system S have property P?
S(beh) ∧¬P(beh)
is operation op deterministic?op(s,s’) ∧ op(s,s”) ∧ s’ ≠ s”
does method m meet pre, post?m(s,s’) ∧ pre(s) ∧ ¬post(s,s’)
is op’ a valid refactoring of op?op’(s,s’) ∧ ¬op(s,s’)
traditional viewanalysis should be ‘sound’
consider all casesensures no bugs missedis a cast-iron guarantee
traditional viewanalysis should be ‘sound’
consider all casesensures no bugs missedis a cast-iron guarantee
but sound ⇒ spurious errors⇒ annoyance⇒ bugs missed
traditional viewanalysis should be ‘sound’
consider all casesensures no bugs missedis a cast-iron guarantee
but sound ⇒ spurious errors⇒ annoyance⇒ bugs missed
and not a guarantee anyway?even theorem proving isn’t watertight
inconsistent axioms may undermine proof
idea: generalizing dot
x.fv.ballot
v.ballot.choiceb.cast
Voter
Ballot
Box
Candidate
choice
castballot
idea: generalizing dot
x.fv.ballot
v.ballot.choiceb.cast
b.cast.choice
Voter
Ballot
Box
Candidate
choice
castballot
idea: generalizing dot
x.fv.ballot
v.ballot.choiceb.cast
b.cast.choicechoice.c
Voter
Ballot
Box
Candidate
choice
castballot
idea: generalizing dot
x.fv.ballot
v.ballot.choiceb.cast
b.cast.choicechoice.c
ballot.choice.c
Voter
Ballot
Box
Candidate
choice
castballot
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choice
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0 B0V1 B2V2 B1
V0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0 B0V1 B2V2 B1
V0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0 B0V1 B2V2 B1
V0
B0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0 C0B1 C1B2 C0
B0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0 C0B1 C1B2 C0
B0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0 C0B1 C1B2 C0
B0
C0
a de!nitiongeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choice
C0
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choice
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0 B0V1 B2V2 B1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0 C0B1 C1B2 C0
V0 B0V1 B2V2 B1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0 C0B1 C1B2 C0
V0 B0V1 B2V2 B1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceB0 C0B1 C1B2 C0
V0 B0V1 B2V2 B1
V0 C0V1 C0V2 C1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choice
V0 C0V1 C0V2 C1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0
V0 C0V1 C0V2 C1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0
V0 C0V1 C0V2 C1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choiceV0
C0
V0 C0V1 C0V2 C1
right associatinggeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
v.ballot.choice
C0
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.c
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cC0
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cB0 C0B1 C1B2 C0
C0
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cB0 C0B1 C1B2 C0
C0
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cB0 C0B1 C1B2 C0
C0
B0B2
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cB0B2
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cV0 B0V1 B2V2 B1
B0B2
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cV0 B0V1 B2V2 B1
B0B2
navigating backgeneralized join
a.b = { (a0,..., an-1, b1,..., bm) | (a0,..., an) ∈ a ∧ (an, b1,..., bm) ∈ b}
ballot.choice.cV0 B0V1 B2V2 B1
B0B2V0
V1
.idea: solving by SAT
v ballot = b1 0 00 0 10 1 0
V0 V1 V2B0B1B2
100
V0V1V2
100
B0B1B2
V0 B0V1 B2V2 B1
.idea: solving by SAT
v ballot = bf00 f01 f02
f10 f11 f12
f20 f21 f22
v0
v1
v2
V0 V1 V2B0B1B2
V0V1V2
b0
b1
b2
B0B1B2
.idea: solving by SAT
v ballot = bf00 f01 f02
f10 f11 f12
f20 f21 f22
v0
v1
v2
V0 V1 V2B0B1B2
V0V1V2
b0
b1
b2
B0B1B2
b0 = v0 ∧ f00 ∨ v1 ∧ f10 ∨ v02 ∧ f20
b1 = v0 ∧ f01 ∨ v1 ∧ f11 ∨ v02 ∧ f21
b2 = v0 ∧ f02 ∨ v1 ∧ f12 ∨ v02 ∧ f22
analyzer architecture
kodkod engine
alloyformula bounds
booleanformula
booleaninstance
alloyinstance
translateformula
translateinstance
SATsolver
mapping
alloycommand
alloy front end
elaborate typecheck visualize
visualoutput
API
API
idea: funky idioms
alloy is just a logicwith subtypes, navigation, etc
but no states or mutation
for dynamic modelsmany ways to represent behaviour
idea: funky idioms
alloy is just a logicwith subtypes, navigation, etc
but no states or mutation
for dynamic modelsmany ways to represent behaviour
a surpriseleast conventional most useful
funky idioms: stateful objectssig Candidate {}sig Voter { intent: Candidate }sig Ballot { choice: Candidate }sig Tally { ballots: set Ballot, count: Candidate -> one Int }sig Precinct { registered: set Voter, cast: Ballot -> Time, voted: Voter -> Time }
funky idioms: stateful objectssig Candidate {}sig Voter { intent: Candidate }sig Ballot { choice: Candidate }sig Tally { ballots: set Ballot, count: Candidate -> one Int }sig Precinct { registered: set Voter, cast: Ballot -> Time, voted: Voter -> Time }
cast: a ternary relation
funky idioms: stateful objectssig Candidate {}sig Voter { intent: Candidate }sig Ballot { choice: Candidate }sig Tally { ballots: set Ballot, count: Candidate -> one Int }sig Precinct { registered: set Voter, cast: Ballot -> Time, voted: Voter -> Time }
cast: a ternary relationcast: Precinct -> Ballot -> Timep.cast: Ballot -> Timecast.t: Precinct -> Ballot
funky idioms: stateful objectssig Candidate {}sig Voter { intent: Candidate }sig Ballot { choice: Candidate }sig Tally { ballots: set Ballot, count: Candidate -> one Int }sig Precinct { registered: set Voter, cast: Ballot -> Time, voted: Voter -> Time }
cast: a ternary relation
cast: projected onto Time
cast: Precinct -> Ballot -> Timep.cast: Ballot -> Timecast.t: Precinct -> Ballot
funky idioms: eventsopen util/ordering[Time]sig Time {}abstract sig Event {before, after: Time}pred Event.follows (that: Event) { this.before = that.after }fact { all t: Time - last | one before.t -- one event starting in every time instant all e: Event | e.after = e.before.next -- events execute in time order }
funky idioms: eventsopen util/ordering[Time]sig Time {}abstract sig Event {before, after: Time}pred Event.follows (that: Event) { this.before = that.after }fact { all t: Time - last | one before.t -- one event starting in every time instant all e: Event | e.after = e.before.next -- events execute in time order }
a generic model of events
funky idioms: eventsopen util/ordering[Time]sig Time {}abstract sig Event {before, after: Time}pred Event.follows (that: Event) { this.before = that.after }fact { all t: Time - last | one before.t -- one event starting in every time instant all e: Event | e.after = e.before.next -- events execute in time order }
sig Cast extends Event { voter: Voter, ballot: Ballot, precinct: Precinct } { ballot.choice = voter.intent -- marks ballot according to intent voter in precinct.registered - precinct.voted.before -- registered but hasn’t voted yet voted.after = voted.before + precinct -> voter -- has now voted cast.after = cast.before + precinct -> ballot -- ballot is cast }sig Count extends Event { tally: Tally } { tally.ballots = Precinct.cast.before -- ballots tallied are those cast in all precincts }
a generic model of events
funky idioms: dynamicsfact { no cast.first -- at first, ballot boxes are empty all v: Voter | some c: Cast | c.voter = v -- all voters cast ballots no ca: Cast, co: Count | ca.follows [co] -- no casting after counting }
funky idioms: dynamicsfact { no cast.first -- at first, ballot boxes are empty all v: Voter | some c: Cast | c.voter = v -- all voters cast ballots no ca: Cast, co: Count | ca.follows [co] -- no casting after counting }
check { all e: Count | all c: Candidate | e.tally.count[c] = #intent.c } for 4 -- tally matches voter intent
what else?
languageimplicit subtyping
sequences, arithmeticmeta features
analysiscoverage by unsat core
partial instancessharing, symmetry, etc
navigations are succinct
tally count for candidate c is # intent.c
in Z| intent∼⦇{c}⦈|
in SQLselect count(*) from voter where intent = c
navigations are succinct
tally count for candidate c is # intent.c
in Z| intent∼⦇{c}⦈|
in SQLselect count(*) from voter where intent = c
in Javaaagh!
design analyses
Mondex [Ramanandro, 2006]reduced Z to Alloy & checked
flash file systems [Kang, 2008]designs checked against POSIX
Chord [Zave, 2009]a peer to peer protocol
typically a few billion cases and ...kloc of Alloy
months of modelingminutes of analysis
a typical story
Ion Stoica et al. Chord: A Scalable Peer to Peer Lookup Servicefor Internet Applications, SIGCOMM 2001 (also TON, 2003)
a typical story
Pamela Zave. Invariant-Based Verification of Routing Protocols: The Case of Chord, 2009
Ion Stoica et al. Chord: A Scalable Peer to Peer Lookup Servicefor Internet Applications, SIGCOMM 2001 (also TON, 2003)
code analysis studies
graph libraries (Taghdiri, 2006−2008)Open JGraph, Quartz graph API
KOA Remote Voting System (Dennis, 2007)found 19 methods not meeting specs
Burr Proton Therapy Center (Seater, 2008)checked various dependability arguments
small scope hypothesis
analysis of KOA voting code19 methods violating specs
how many bugs found in scope of k?[Greg Dennis, 2008]
small scope hypothesis
analysis of KOA voting code19 methods violating specs
how many bugs found in scope of k?[Greg Dennis, 2008]
0
5
10
15
20
0 1 2 3 4 5
scope
small scope hypothesis
analysis of KOA voting code19 methods violating specs
how many bugs found in scope of k?[Greg Dennis, 2008]
0
5
10
15
20
0 1 2 3 4 5
scope
0
5
10
15
20
0 1 2 3 4 5
bitwidth
small scope hypothesis
analysis of KOA voting code19 methods violating specs
how many bugs found in scope of k?[Greg Dennis, 2008]
0
5
10
15
20
0 1 2 3 4 5
scope
0
5
10
15
20
0 1 2 3 4 5
bitwidth
0
5
10
15
20
0 1 2 3 4 5
unrolling
code analysis: jforge plugin
plugin implemented by Kuat Yessenov; underlying Forge analyzer by Greg Dennis
code synthesis
WebAlloy [Chang 2009]data model + policy in Alloygenerate entire sitegateway enforces policy
results3 real websites in ~100 lines of Alloy each
declarative con!guration
‘We don’t need hackersto break systems because
they’re falling apartby themselves’Peter Neumann
bad configurations responsible for80% of USAF vulnerabilities
NSA
declarative con!guration
ConfigAssure[Telcordia, 2008]
use Kodkod to findnetwork configuration
that meets rules & goals
declarative con!guration
ConfigAssure[Telcordia, 2008]
use Kodkod to findnetwork configuration
that meets rules & goals
declarative con!guration
ConfigAssure[Telcordia, 2008]
use Kodkod to findnetwork configuration
that meets rules & goals
some other uses of Alloybytecode security checking
Reynolds
mixed programmingRayside et al
product-line test generationUzuncaova et al
memory model analysisTorlak
security policy analysisKrishnamurthi & Fisler, Hassan
ontology analysisDong
architectural stylesKim & Garlan, Sullivan
HOL to AlloyBlanchette
UML to AlloyDingel & Zito, Bordbar, Roquette
multiobjective optimizationRayside & Estler
Therac 25
AECL fault tree analysis (1983)did not include software
P(computer selects wrong energy) = 10-11
Leveson & Turner (1993)race conditions, lack of interlocks, etc
A Direct Path to Dependable Software, CACM, March 2009wordle thanks to Jonathan Feinberg, IBM Research, Cambridge
dependability arguments
solve the real problemnot just software: operators & peripherals too
top-to-bottom, end-to-end
be realisticnot ‘full correctness’: prioritize requirements
don’t be a masochist use a safe language
design to localize critical properties
the future of modelling
it will happen, reallydomain-specific approachesRails is a modelling language
the future of modelling
it will happen, reallydomain-specific approachesRails is a modelling language
animation now, analysis laterexploration, test case generation
then maybe checking
the future of modelling
it will happen, reallydomain-specific approachesRails is a modelling language
animation now, analysis laterexploration, test case generation
then maybe checking
relational modellingnon-transparent ORMs must go
what I learnt from this projectwhat worked
drive research by case studiesrobust tools: x10 cost, but worth it
semantics is a verb: helps keep it simple
what I learnt from this projectwhat worked
drive research by case studiesrobust tools: x10 cost, but worth it
semantics is a verb: helps keep it simple
what didn’t worklanguage design is a hard sell
software engineering is a really hard selleasy to get new idea funded once popular
what I learnt from this projectwhat worked
drive research by case studiesrobust tools: x10 cost, but worth it
semantics is a verb: helps keep it simple
what didn’t worklanguage design is a hard sell
software engineering is a really hard selleasy to get new idea funded once popular
a mistake?keeping Alloy general & pure
limited impact, except in teaching
for more infohttp://sdg.csail.mit.eduother fun things my group does
http://alloy.mit.educommunity, downloads, tutorial
http://softwareabstractions.orgsample chapters, models