Spec_stackVSU specification of the Stack module
- stdlib.c (and stdlib.h) characterizing the external library functions, malloc, free, exit.
- stack2.c (and stack2.h) with newstack, push, pop.
- triang2.c (and triang2.h) with push_increasing, pop_and_add, and triang.
- main2.c with a main function that calls triang.
/* stack2.h */ #include <stddef.h> struct stack; struct stack *newstack(void); void push (struct stack *p, int i); int pop (struct stack *p);
Let's verify!
Abstract Predicate Declaration (APD)
As you recall from Verif_stack, the stack module implements an abstract data type; that is, a data structure with a private representation and public operators. In the C program, the name of the type is struct stack, and in the header file above, we emphasize that the representation is private by writing struct stack; instead of struct stack {...fields...};.
Record StackAPD := {
stackrep: list Z → val → mpred;
stackrep_local_facts: ∀ il p, stackrep il p |-- !! (isptr p);
stackrep_valid_pointer: ∀ il p, stackrep il p |-- valid_pointer p
}.
stackrep: list Z → val → mpred;
stackrep_local_facts: ∀ il p, stackrep il p |-- !! (isptr p);
stackrep_valid_pointer: ∀ il p, stackrep il p |-- valid_pointer p
}.
Here, stackrep serves the same purpose as stack in Verif_stack;
that is, it is the separation-logic representation relation for stacks.
In particular, stackrep il p is an mpred that says, "at address p is
a data structure representing the sequence il". But the difference here
is that we don't say what the representation is, we just give its type
signature, list Z → val → mpred. In addition, we must provide
the local_facts and the valid_pointer lemmas for this relation, just
as we did in Verif_stack; but here we just present them as axioms,
not as theorems. All of this is bundled into a Record, the abstract
predicate declaration (APD). The client need never know how the
data structure is really represented, that is, the details of the stackrep
predicate.
If we examine the type of stackrep, ...
we find that, given an instance S:StackAPD, then
stackrep S will be a relation of type list Z → val → mpred.
At the moment, we don't yet have an instance; after all, this is an
abstract data type whose representation will be provided by the
implementation of a module, and in this file we are describing only
the interface, not the implementation.
Now, just as we did in Verif_stack, we add the lemmas/axioms
about stackrep to the respective hint databases.
#[export] Hint Resolve stackrep_local_facts : saturate_local.
#[export] Hint Resolve stackrep_valid_pointer: valid_pointer.
#[export] Hint Resolve stackrep_valid_pointer: valid_pointer.
Abstract Specification Interface (ASI)
Now the funspecs look just as they did in Verif_stack, except that
we write mem_mgr M instead of mem_mgr, and we write stackrep STACK
instead of stack. By the way, in Verif_stack the identifier
mem_mgr referred to VST.floyd.library.mem_mgr, but here we are
referring to Spec_stdlib.mem_mgr which is not the same.
We'll explain that one in Chapter Spec_stdlib.
Locate mem_mgr. (* short for VC.Spec_stdlib.mem_mgr *)
Check mem_mgr. (* MallocFreeAPD -> globals -> mpred. *)
Definition newstack_spec : ident × funspec :=
DECLARE _newstack
WITH gv: globals
PRE [ ]
PROP () PARAMS() GLOBALS(gv) SEP (mem_mgr M gv)
POST [ tptr (Tstruct _stack noattr) ]
EX p: val, PROP ( ) RETURN (p)
SEP (stackrep STACK nil p; mem_mgr M gv).
Definition push_spec : ident × funspec :=
DECLARE _push
WITH p: val, i: Z, il: list Z, gv: globals
PRE [ tptr (Tstruct _stack noattr), tint ]
PROP (Int.min_signed ≤ i ≤ Int.max_signed)
PARAMS (p; Vint (Int.repr i)) GLOBALS(gv)
SEP (stackrep STACK il p; mem_mgr M gv)
POST [ tvoid ]
PROP ( ) RETURN ()
SEP (stackrep STACK (i::il) p; mem_mgr M gv).
Definition pop_spec : ident × funspec :=
DECLARE _pop
WITH p: val, i: Z, il: list Z, gv: globals
PRE [ tptr (Tstruct _stack noattr) ]
PROP ()
PARAMS (p) GLOBALS(gv)
SEP (stackrep STACK (i::il) p; mem_mgr M gv)
POST [ tint ]
PROP ( ) RETURN (Vint (Int.repr i))
SEP (stackrep STACK il p; mem_mgr M gv).
Check mem_mgr. (* MallocFreeAPD -> globals -> mpred. *)
Definition newstack_spec : ident × funspec :=
DECLARE _newstack
WITH gv: globals
PRE [ ]
PROP () PARAMS() GLOBALS(gv) SEP (mem_mgr M gv)
POST [ tptr (Tstruct _stack noattr) ]
EX p: val, PROP ( ) RETURN (p)
SEP (stackrep STACK nil p; mem_mgr M gv).
Definition push_spec : ident × funspec :=
DECLARE _push
WITH p: val, i: Z, il: list Z, gv: globals
PRE [ tptr (Tstruct _stack noattr), tint ]
PROP (Int.min_signed ≤ i ≤ Int.max_signed)
PARAMS (p; Vint (Int.repr i)) GLOBALS(gv)
SEP (stackrep STACK il p; mem_mgr M gv)
POST [ tvoid ]
PROP ( ) RETURN ()
SEP (stackrep STACK (i::il) p; mem_mgr M gv).
Definition pop_spec : ident × funspec :=
DECLARE _pop
WITH p: val, i: Z, il: list Z, gv: globals
PRE [ tptr (Tstruct _stack noattr) ]
PROP ()
PARAMS (p) GLOBALS(gv)
SEP (stackrep STACK (i::il) p; mem_mgr M gv)
POST [ tint ]
PROP ( ) RETURN (Vint (Int.repr i))
SEP (stackrep STACK il p; mem_mgr M gv).
Now the "Stack Abstract Specification Interface" is just a list of the
exported funspecs
And remember that StackASI is parameterized by the Variables of the Section:
Next Chapter: Spec_triang
(* 2024-01-02 15:44 *)