Smallfoot 0.1 2005-12-15 Copyright 2001-2005 Cristiano Calcagno (ccris@doc.ic.ac.uk), Josh Berdine (berdine@dcs.qmul.ac.uk), Peter O'Hearn (ohearn@dcs.qmul.ac.uk) Smallfoot is an automatic verification tool which checks separation logic specifications of concurrent programs which manipulate dynamically-allocated recursive data structures. For further information see: http://www.dcs.qmul.ac.uk/research/logic/theory/projects/smallfoot/ This is a developmental release, intended only for experimentation. Installation ============ Precompiled MacOS X PPC and Linux x86 executables can be found in bin. OCaml (version 3.07 or later) is required to compile. After unpacking the tarball, performing "cd smallfoot ; make" will build the native code executable "smallfoot", and "make smallfoot.byte" will build the bytecode executable "smallfoot.byte". These programs do not hardcode any paths, so can be moved anywhere after compilation. Usage ===== "smallfoot [options] " where the following command line options are accepted: -verbose Display additional internal information -all_states Display intermediate states -show_induction Indicate when induction is used during verification -very_verbose Display more additional internal information -help Display usage message See the EXAMPLES directory for some sample programs. For instance: $ ./smallfoot EXAMPLES/parallel_tree_deallocate.sf Function tree_deallocate Valid $ indicates a successful verification, while: $ ./smallfoot EXAMPLES/heap_race.sf Function update Function heap_race File "EXAMPLES/heap_race.sf", line 9, characters 2-31: ERROR cannot find frame: parallel call 0!=c * c |-> tl:0 |- c |-> * c |-> NOT Valid $ indicates a failed verification, identifying the source code location associated with the error, and a brief description. Note that the source code locations are printed in standard form, and so e.g. emacs can parse them. That is, after executing the M-x compile function with "./smallfoot EXAMPLES/heap_race.sf" as the compile command, M-x next-error will indicate the source locations. This is particularly useful with e.g. "./smallfoot -all_states EXAMPLES/queue.sf". Input Language ============== Lexical structure ----------------- whitespace ::= blank | comment blank ::= horizontal tab | linefeed | vertical tab | formfeed | carriage return | space comment ::= "/*" anything "*/" Whitespace delimits tokens but is otherwise ignored. Comments nest. keywords: NULL dispose dlseg else emp false if list lseg local new resource then tree true when while with xlseg NULL is a synonym for 0 ident ::= letter alphanum* field ::= ident number ::= digit+ letter ::= "A"--"Z" | "_" | "a"--"z" alphanum ::= digit | letter digit ::= "0"--"9" Grammar ------- program ::= (field_seq ";")? (resource_decl | fun_decl)* The field_seq declares the valid field names, which by default includes the default fields of all the predicates, see below. resource_decl ::= "resource" ident "(" ident_seq ")" "[" formula "]" fun_decl ::= ident "(" formals ")" ("[" formula "]")? "{" local_decl* statement* "}" ("[" formula "]")? formals ::= (ident_seq ";")? ident_seq ident_seq ::= /* empty */ | ident ("," ident)* local_decl ::= "local" ident ("," ident)* ";" The formals consist of the reference parameters (which are optional) followed by the value parameters. If a function pre- or post-condition is omitted, it defaults to "emp". statement ::= ident "=" stmt_exp ";" | ident "=" stmt_exp "->" field ";" | stmt_exp "->" field "=" stmt_exp ";" | ident "=" "new" "(" ")" ";" | "dispose" stmt_exp ";" | "{" statement* "}" | "if" "(" stmt_exp ")" statement ("else" statement)? | "while" "(" stmt_exp ")" ("[" formula "]")? statement | "with" ident "when" "(" stmt_exp ")" statement | ident "(" actuals ")" ";" | ident "(" actuals ")" "||" ident "(" actuals ")" ";" actuals ::= stmt_exp_seq (";" stmt_exp_seq)? stmt_exp ::= "(" stmt_exp ")" | ident | number | "true" | "false" | prefix_op stmt_exp | stmt_exp infix_op stmt_exp stmt_exp_seq ::= /* empty */ | stmt_exp ("," stmt_exp)* infix_op ::= "==" | "!=" | "^" | "&&" | "*" | "/" | "%" | "+" | "-" | "<" | "<=" | ">" | ">=" prefix_op ::= "+" | "-" If a loop invariant is omitted, it defaults to "emp". All of the infix_op's except equality "==", non-equality "!=", and exclusive-or "^" are essentially unimplemented. formula ::= "(" formula ")" | "false" | form_exp "==" form_exp | form_exp "!=" form_exp | "emp" | formula "*" formula | form_exp "|->" ((field ":" form_exp)* | form_exp | form_exp "," form_exp) | "list" "(" (field ";")? form_exp ")" | "lseg" "(" (field ";")? form_exp "," form_exp ")" | ("dlseg" | "xlseg") "(" (field ";" field ";")? form_exp "," form_exp "," form_exp "," form_exp ")" | "tree" "(" (field ";" field ";")? form_exp ")" | "if" form_exp ("==" | "!=") form_exp "then" formula "else" formula form_exp ::= "(" form_exp ")" | ident | number | form_exp "^" form_exp Here, unlike in the related papers, formulae are not composed of distinct boolean (pure) and heap (spatial) parts. Instead "E==F" and "E!=F" are only satisfied by the empty heap, like "emp", and "*" is the only conjunction. For the "|->" predicate, in the second alternative the "tl" field is assumed, and in the third alternative "l" and "r" fields are assumed. For the inductive predicates, omitted fields default to: - "hd" and "tl" for lists; - "d", "l", and "r" for doubly-linked lists; - "d" and "l" for xor-linked lists; and - "d", "l", and "r" for trees. precedences (increasing) and associativities: 1 * && L 2 == != L 3 = < <= > >= L 4 + - L 5 ^ |-> / % L