Theory Reference: Separation Logic

cvc5 supports a syntax for separation logic as an extension of the SMT-LIB 2.6 language.

Signature

Given a (decidable) base theory \(T\), cvc5 implements a decision procedure for quantifier-free \(SL(T)_{Loc,Data}\) formulas [RISK16], where \(Loc\) and \(Data\) are any sort belonging to \(T\).

A \(SL(T)_{Loc,Data}\) formula is one from the following grammar:

F : L | sep.emp | (pto t u) | (sep F1 ... Fn) | (wand F1 F2) | ~F1 | F1 op ... op Fn

where op is any classical Boolean connective, t and u are terms built from symbols in the signature of \(T\) of sort \(Loc\) and \(Data\) respectively, and \(L\) is a \(T\)-literal.

The operator sep.emp denotes the empty heap constraint, the operator pto denotes the points-to predicate, the operator sep denotes separation start and is variadic, and the operator wand denote magic wand.

Semantics

A satisfiability relation \(I,h \models_{SL} \varphi\) is defined for \(SL(T)_{Loc,Data}\) formulas \(\varphi\), where \(I\) is an interpretation, and \(h\) is a heap.

The semantics of separation logic operators are as follows:

\(I,h \models_{SL} L\)

Iff

\(I \models L\), if \(L\) is a \(T\)-literal

\(I,h \models_{SL}\) (emp \(t \ u\))

Iff

\(h = \emptyset\)

\(I,h \models_{SL}\) (pto \(t \ u\))

Iff

\(h = \{(t^I,u^I)\} \text{ and } t^I\not=nil^I\)

\(I,h \models_{SL}\) (sep \(\phi_1 \ldots \phi_n)\)

Iff

there exist heaps \(h_1,\ldots,h_n\) s.t. \(h=h_1\uplus \ldots \uplus h_n\)

and \(I,h_i \models_{SL} \phi_i, i = 1,\ldots,n\)

\(I,h \models_{SL}\) (wand \(\phi_1 \ \phi_2\))

Iff

for all heaps \(h'\) if \(h'\#h\) and \(I,h' \models_{SL} \phi_1\)

then \(I,h'\uplus h \models_{SL} \phi_2\)

where \(h_1 \uplus \ldots \uplus h_n\) denotes the disjoint union of heaps \(h_1, \ldots, h_n\) and \(h'\#h\) denotes that heaps \(h'\) and \(h\) are disjoint, and \(nil\) is a distinguished variable of sort \(Loc\). All classical Boolean connectives are interpreted as expected.

Syntax

Separation logic in cvc5 requires the QF_ALL logic, and for the types of the heap to be declared via the declare-heap command:

(declare-heap (T1 T2))

This command must be executed when the solver is in its Start mode (see page 52 of the SMT-LIB 2.6 standard [BFT17]). This command sets the location type of the heap \(Loc\) to \(T1\) and the data type \(Data\) to \(T2\), where \(T1\) and \(T2\) are any defined types. This command can only be executed once in any context, and is reset only via a reset command.

The syntax for the operators of separation logic is summarized in the following table. For the C++ API examples in this table, we assume that we have created a cvc5::Solver object.

SMTLIB language

C++ API

Logic String

(set-logic QF_ALL)

solver.setLogic("QF_ALL");

Empty Heap

sep.emp

solver.mkSepEmp();

where x and y are of sort <Sort_1> and <Sort_2>

Points-To

(pto x y)

solver.mkTerm(Kind::SEP_PTO, {x, y});

Separation Star

(sep c1 .. cn)

solver.mkTerm(Kind::SEP_STAR, {c1, ..., cn});

Magic Wand

(wand c1 c1)

solver.mkTerm(Kind::SEP_WAND, {c1, c2});

Nil Element

(as sep.nil <Sort>)

solver.mkSepNil(cvc5::Sort sort);

Examples

The following input on heaps Int -> Int is unsatisfiable:

(set-logic QF_ALL)
(declare-heap (Int Int))
(set-info :status unsat)
(declare-const x Int)
(declare-const a Int)
(declare-const b Int)
(assert (and (pto x a) (pto x b)))
(assert (not (= a b)))
(check-sat)

The following input on heaps U -> Int is satisfiable. Notice that the formula (not sep.emp) is satisfied by heaps U -> Int whose domain is non-empty.

(set-logic QF_ALL)
(set-info :status sat)
(declare-sort U 0)
(declare-heap (U Int))
(declare-const x U)
(declare-const a Int)
(assert (and (not sep.emp) (pto x a)))
(check-sat)

The following input on heaps Int -> Node is satisfiable, where Node denotes a user-defined inductive Theory Reference: Datatypes.

(set-logic QF_ALL)
(set-info :status sat)
(declare-const x Int)
(declare-const y Int)
(declare-const z Int)
(declare-datatype Node ((node (data Int) (left Int) (right Int))))
(declare-heap (Int Node))
(assert (pto x (node 0 y z)))
(check-sat)

Note

Given a separation logic input, the sorts \(Loc\) and \(Data\) declared via the declare-heap command must match all separation logic predicates in the input. cvc5 does not accept an input such as:

(set-logic QF_ALL)
(declare-sort U 0)
(declare-heap (U Int))
(declare-const x U)
(assert (and (pto x 0) (pto 1 2)))
(check-sat)

since the second points-to predicate uses Int for its location type.