; 1 array 8 32 ; 2 var 32 start ; 3 var 32 end ; 4 var 32 p ; 5 var 1 flag ; 6 zero 8 ; 7 one 32 ; 8 one 1 ; next(start) ; 9 var 32 start_in ; 10 ne 1 5 8 ; 11 cond 32 10 9 2 ; 12 next 32 2 11 ; next(end) 13 var 32 end_in 14 cond 32 10 13 3 15 next 32 3 14 ; next(p) 16 add 32 4 7 17 ult 1 4 3 18 cond 32 17 16 4 19 cond 32 10 9 18 20 next 32 4 19 ; next(flag) 21 next 1 5 8 ; next(memory) 22 write 8 32 1 4 6 23 eq 1 5 8 24 ult 1 4 3 25 and 1 23 24 26 acond 8 32 25 22 1 27 anext 8 32 1 26 ; check property 28 var 32 i 29 read 8 1 28 30 ne 1 29 6 31 ult 1 2 3 32 ult 1 28 2 33 ult 1 28 3 34 and 1 -32 33 35 and 1 34 -10 36 and 1 31 35 37 and 1 30 36 38 eq 1 4 3 39 and 1 38 37 40 root 1 39 ; The 'State' predicate. ; State refers to 'start' 'end' 'p' 'flag' 'memory' (define-sort BV32 () (_ BitVec 32)) (define-sort Ar () (Array (_ BitVec 8) (_ BitVec 32))) (declare-fun State (BV32 BV32 BV32 Bool Ar) Bool) ; Initial state ; Registers are initialized to zero. Memories are uninitialized as ; this is the general case for main memory in software, ; and memory units in hardware. (assert (forall ((memory Ar)) (State #x00000000 #x00000000 #x00000000 false memory))) ; Successor states: (assert (forall ((start BV32) (start1 BV32) (start_in BV32) (end BV32) (end1 BV32) (end_in BV32) (p BV32) (p1 BV32) (flag Bool) (flag1 Bool) (memory Ar) (memory1 Ar)) (=> (let (($1 array) ($2 start) ($3 end) ($4 p) ($5 end) ($6 #x00) ($7 #x00000001) ($8 #x01) ($9 start_in)) (let (($10 (not (= $5 $8)))) (let (($11 (if $10 $9 $2))) (let (($12 (= start1 $11))) (let (($13 end_in)) (let (($14 (if $10 $13 $3))) (let (($15 (= end1 $14))) (let (($16 (bvadd $4 $7))) (let (($17 (bvult $4 $3))) (let (($18 (if $17 $16 $4))) (let (($19 (if $10 $9 $18)) (let (($20 (= p1 $19))) (and $12 $14 $20 (State start end p flag memory))))))))) ) (State start1 end1 p1 flag1 memory1)))) ; Checking property: (assert (forall ((start BV32) (end BV32) (p BV32) (flag Bool) (memory Ar) (i BV32)) (let (($29 (select memory i))) (let (($30 (not (= $29 $6)))) (let (($31 (bvult start end))) .... (let (($39 (and $38 $37))) (=> (State start end p flag memory) $39))))))) ; check satisfiability of formula. (check-sat) ; ------------------------------------------------------- ; Z3 specific features for encoding Horn clauses. ; Z3 uses 'declare-rel' for declaring recursive relations. ; The specialized format enables more readable specifications, ; It is not necessary for BTOR problems. (declare-rel State (BV32 BV32 BV32 Bool Ar)) ; We also use "rule" instead "assert" (rule (forall ((memory Ar)) (State #x00000000 #x00000000 #x00000000 false memory))) ; Property checking uses 'query' (not rule). (query (exists ((start BV32) (end BV32) (p BV32) (flag Bool) (memory Ar) (i BV32)) (let (($29 (select memory i))) (let (($30 (not (= $29 $6)))) (let (($31 (bvult start end))) .... (let (($39 (and $38 $37))) (and (State start end p flag memory) (not $39)))))))) ; We also have a way to declare variables globally so we don't have to ; bind them with quantifiers. ; Example (declare-var start BV32) (declare-var start1 BV32) (declare-var end BV32) (declare-var end1 BV32) (declare-var p BV32) (declare-var p1 BV32) (declare-var flag Bool) (declare-var flag1 Bool) (declare-var memory Ar) (declare-var memory1 Ar) (declare-var i (_ BitVec 8)) ; Now I don't have to quantify variables used in query. (query (let (($29 (select memory i))) (let (($30 (not (= $29 $6)))) (let (($31 (bvult start end))) .... (let (($39 (and $38 $37))) (and (State start end p flag memory) (not $39)))))))