├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .ocamlformat ├── LICENSE ├── README.md ├── Raven.opam ├── bench_results └── bench_20250228_072408.csv ├── bin ├── dune └── raven.ml ├── conventions.md ├── dune ├── dune-project ├── lib ├── ast │ ├── ast.ml │ ├── astDef.ml │ ├── dune │ ├── progUtils.ml │ ├── rewriter.ml │ ├── symbolTbl.ml │ └── traverser.ml ├── backend │ ├── checker.ml │ ├── dependencies.ml │ ├── dune │ ├── smtLibAST.ml │ └── smt_solver.ml ├── config │ ├── config.ml │ └── dune ├── frontend │ ├── dune │ ├── lexer.mll │ ├── parser.mly │ ├── rewrites │ │ ├── atomicityAnalysis.ml │ │ ├── dune │ │ ├── heapsExplicitTrnsl.ml │ │ ├── masks.ml │ │ └── rewrites.ml │ └── typing.ml ├── library │ ├── base_types.rav │ ├── dune │ ├── library.ml │ ├── library.t │ └── resource_algebra.rav └── util │ ├── dune │ ├── error.ml │ ├── graph.ml │ ├── loc.ml │ ├── option.ml │ └── print.ml ├── logo.png ├── package-lock.json ├── scripts └── bench.sh ├── test ├── adt │ └── list.rav ├── arrays │ ├── array.rav │ ├── array_utils.rav │ ├── ordered_array.rav │ ├── parray.rav │ └── union-find.rav ├── bugs │ ├── bogus_error_msg.rav │ ├── co_recursion.rav │ ├── diamond_modules.rav │ ├── faulty_skolems.rav │ ├── rec_func_contract.rav │ ├── return_proc.rav │ └── unsound-with.rav ├── ci │ ├── back-end │ │ ├── agree_inhale.rav │ │ ├── agree_inhale.t │ │ ├── anti-aliasing.rav │ │ ├── anti-aliasing.t │ │ ├── atomic_spec │ │ │ ├── counter_no_inv.rav │ │ │ ├── counter_no_inv.t │ │ │ ├── dune │ │ │ ├── treiber_stack_atomics.rav │ │ │ └── treiber_stack_atomics.t │ │ ├── auth_inhale.rav │ │ ├── auth_inhale.t │ │ ├── bind_3.rav │ │ ├── bind_3.t │ │ ├── data_recursion.rav │ │ ├── data_recursion.t │ │ ├── dune │ │ ├── exhale_existential_quant_elim.rav │ │ ├── exhale_existential_quant_elim.t │ │ ├── fail │ │ │ ├── alloc_ref_twice.rav │ │ │ ├── alloc_ref_twice.t │ │ │ ├── bind_2.rav │ │ │ ├── bind_2.t │ │ │ ├── bind_4.rav │ │ │ ├── bind_4.t │ │ │ ├── dune │ │ │ ├── fpu_fail.rav │ │ │ ├── fpu_fail.t │ │ │ ├── masks_1.rav │ │ │ ├── masks_1.t │ │ │ ├── missing_permissions.rav │ │ │ ├── missing_permissions.t │ │ │ ├── multiple_witness_soundness_fix.rav │ │ │ ├── multiple_witness_soundness_fix.t │ │ │ ├── new_stmt_validity_check.rav │ │ │ ├── new_stmt_validity_check.t │ │ │ ├── while_loop.rav │ │ │ └── while_loop.t │ │ ├── forward_trg_assertions.rav │ │ ├── forward_trg_assertions.t │ │ ├── frac_ra_fpu.rav │ │ ├── frac_ra_fpu.t │ │ ├── heap_valid_no_null_test.rav │ │ ├── heap_valid_no_null_test.t │ │ ├── inhale_exhale.rav │ │ ├── inhale_exhale.t │ │ ├── isc_multiquant.rav │ │ ├── isc_multiquant.t │ │ ├── ite_preds.rav │ │ ├── ite_preds.t │ │ ├── iterated-star │ │ │ ├── array-max.rav │ │ │ ├── array-max.t │ │ │ ├── dune │ │ │ ├── dutch-flag.rav │ │ │ ├── dutch-flag.t │ │ │ ├── dutch-flag_unsound.rav │ │ │ └── dutch-flag_unsound.t │ │ ├── iterated_sep_star_encoding.rav │ │ ├── iterated_sep_star_encoding.t │ │ ├── nat_ra_fpu.rav │ │ ├── nat_ra_fpu.t │ │ ├── nested_invariants.rav │ │ ├── nested_invariants.t │ │ ├── pred_vs_inv.rav │ │ ├── pred_vs_inv.t │ │ ├── witness_comp.rav │ │ ├── witness_comp.t │ │ ├── witness_comp2.rav │ │ ├── witness_comp2.t │ │ ├── witness_placeholders.rav │ │ └── witness_placeholders.t │ └── front-end │ │ ├── adt.rav │ │ ├── adt.t │ │ ├── atomics │ │ ├── atomicity_check_ghost_fields_vars.rav │ │ ├── atomicity_check_ghost_fields_vars.t │ │ ├── atomics.t │ │ ├── dune │ │ ├── fail │ │ │ ├── fail1.rav │ │ │ └── fail2.rav │ │ ├── invariant_alloc.rav │ │ ├── invariant_alloc.t │ │ ├── invariant_alloc_fail.rav │ │ ├── invariant_alloc_fail.t │ │ ├── test1.rav │ │ ├── test2.rav │ │ ├── test3.rav │ │ └── test4.rav │ │ ├── binders_typing.rav │ │ ├── binders_typing.t │ │ ├── bool_perm_ite.rav │ │ ├── bool_perm_ite.t │ │ ├── bool_perm_typecheck.rav │ │ ├── bool_perm_typecheck.t │ │ ├── cas_rewriter_test.rav │ │ ├── cas_rewriter_test.t │ │ ├── custom_fields_data_type.rav │ │ ├── custom_fields_data_type.t │ │ ├── data_type.rav │ │ ├── data_type.t │ │ ├── data_type_inherit.rav │ │ ├── data_type_inherit.t │ │ ├── datatype_test.rav │ │ ├── datatype_test.t │ │ ├── dune │ │ ├── exhale_existential_qual_pred_elim.rav │ │ ├── exhale_existential_qual_pred_elim.t │ │ ├── fail │ │ ├── dune │ │ ├── tuple.rav │ │ ├── tuple.t │ │ ├── tuple_typing.t │ │ ├── tuple_typing1.rav │ │ ├── tuple_typing2.rav │ │ └── tuple_typing3.rav │ │ ├── field_type_test.rav │ │ ├── field_type_test.t │ │ ├── field_typing.rav │ │ ├── field_typing.t │ │ ├── inlined_fold_witness.rav │ │ ├── inlined_fold_witness.t │ │ ├── inlined_unfold_bind.rav │ │ ├── inlined_unfold_bind.t │ │ ├── inst_mod_frac_field.rav │ │ ├── inst_mod_frac_field.t │ │ ├── loop-rewriter_test.rav │ │ ├── loop-rewriter_test.t │ │ ├── loop_inv_vars.rav │ │ ├── loop_inv_vars.t │ │ ├── map_compr.rav │ │ ├── map_compr.t │ │ ├── map_empty_set.rav │ │ ├── map_empty_set.t │ │ ├── merge_inherited_members.rav │ │ ├── merge_inherited_members.t │ │ ├── own_expr_rewriter_test.rav │ │ ├── own_expr_rewriter_test.t │ │ ├── parametric_frac.rav │ │ ├── parametric_frac.t │ │ ├── predicates.rav │ │ ├── predicates.t │ │ ├── simple.rav │ │ ├── simple.t │ │ ├── tuple.rav │ │ ├── tuple.t │ │ ├── type_alias_1.rav │ │ ├── type_alias_1.t │ │ ├── type_alias_2.rav │ │ ├── type_alias_2.t │ │ ├── type_alias_3.rav │ │ └── type_alias_3.t ├── comparison │ ├── adt_buggy.rav │ ├── adt_correct.rav │ ├── arc.rav │ ├── arc.t │ ├── arc_atomics.rav │ ├── arc_buggy.rav │ ├── arc_ra.rav │ ├── arc_ra.t │ ├── barrier.rav │ ├── barrier_buggy.rav │ ├── barrier_client.rav │ ├── bounded_counter.rav │ ├── cas_counter.rav │ ├── cas_counter_client.rav │ ├── dfrac_ra.rav │ ├── dune │ ├── fork_join.rav │ ├── fork_join_client.rav │ ├── inc_dec.rav │ ├── lclist.rav │ ├── lclist_buggy.rav │ ├── lclist_isc.rav │ ├── lclist_traverse.rav │ ├── lock_invariant.rav │ ├── msc_queue.rav │ ├── peterson.rav │ ├── peterson_buggy.rav │ ├── queue.rav │ ├── rwlock_duolock.rav │ ├── rwlock_duolock.t │ ├── rwlock_duolock_buggy.rav │ ├── rwlock_lockless_faa.rav │ ├── rwlock_ticket_bounded.rav │ ├── rwlock_ticket_unbounded.rav │ ├── shareable_predicates.rav │ ├── ticket_lock_client.rav │ └── tokens.rav ├── concurrent │ ├── counter │ │ ├── counter.rav │ │ ├── counter.t │ │ ├── counter_monotonic.rav │ │ ├── counter_monotonic.t │ │ ├── counter_no_inv.rav │ │ ├── counter_no_inv.t │ │ └── dune │ ├── lock │ │ ├── clh-lock.rav │ │ ├── dune │ │ ├── lock.rav │ │ ├── mcs-lock.rav │ │ ├── spin-lock.rav │ │ ├── spin-lock.t │ │ ├── spin-lock_compact.rav │ │ ├── ticket-lock.rav │ │ └── ticket-lock_atomics.rav │ ├── templates │ │ ├── bplustree.rav │ │ ├── ccm.rav │ │ ├── ccm_instances.rav │ │ ├── ccm_instances.t │ │ ├── dune │ │ ├── flows_ra.rav │ │ ├── flows_ra.t │ │ ├── give-up-simplified.rav │ │ ├── give-up.rav │ │ ├── give-up.t │ │ ├── keyset_ra.rav │ │ ├── single-node.rav │ │ └── single-node.t │ └── treiber_stack │ │ ├── dune │ │ ├── treiber_stack_atomic.rav │ │ ├── treiber_stack_atomic.t │ │ └── treiber_stack_rewritten.rav ├── dune ├── iterated-star │ ├── array-max.rav │ ├── array-max.t │ ├── binary-search.rav │ ├── dune │ ├── dutch-flag.rav │ ├── dutch-flag.t │ ├── graph_marking_buggy.rav │ └── graph_marking_correct.rav └── rec-preds │ ├── dune │ ├── list.rav │ ├── list.t │ ├── list_predicates2_wip.rav │ ├── list_predicates_wip.rav │ └── tree_delete.rav ├── todo.md └── tree_delete.rav /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Builds, tests & co 2 | 3 | on: 4 | pull_request: 5 | push: 6 | # Allows you to run this workflow manually from the Actions tab 7 | workflow_dispatch: 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | build: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: 17 | - macos-latest 18 | - ubuntu-latest 19 | ocaml-compiler: 20 | - "5.1" 21 | 22 | runs-on: ${{ matrix.os }} 23 | 24 | steps: 25 | - name: Checkout tree 26 | uses: actions/checkout@v4 27 | 28 | - name: Set-up OCaml ${{ matrix.ocaml-compiler }} 29 | uses: ocaml/setup-ocaml@v3 30 | with: 31 | ocaml-compiler: ${{ matrix.ocaml-compiler }} 32 | 33 | - run: opam install . --deps-only --with-test 34 | 35 | - run: opam exec -- dune build 36 | 37 | - run: opam exec -- dune runtest 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | *~ 3 | formalism/formalism.aux 4 | formalism/formalism.log 5 | formalism/formalism.synctex.gz 6 | .directory 7 | log*.smt2 8 | .vscode 9 | .DS_Store 10 | front_end_processed_output.log 11 | smt-encodings/* 12 | benchmarks.csv 13 | .dockerignore 14 | Dockerfile 15 | raven.tar -------------------------------------------------------------------------------- /.ocamlformat: -------------------------------------------------------------------------------- 1 | profile = default 2 | version = 0.26.2 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 2 | Ekanshdeep Gupta (eg3134@nyu.edu) 3 | Nisarg Patel (nisarg@nyu.edu) 4 | Thomas Wies (wies@cs.nyu.edu) 5 | 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | -------------------------------------------------------------------------------- /Raven.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | synopsis: 4 | "Intermediate verification language and deductive verifier for concurrent programs" 5 | description: 6 | "Raven is an intermediate verification language and SMT-based deductive verifier based on concurrent separation logic. It is intended as an intermediate layer for building program verification tools that target concurrent programs. Raven can also be used as a standalone educational tool." 7 | maintainer: ["Ekanshdeep Gupta" "Nisarg Patel" "Thomas Wies"] 8 | authors: ["Ekanshdeep Gupta" "Nisarg Patel" "Thomas Wies"] 9 | license: "MIT" 10 | homepage: "https://github.com/nyu-acsys/raven" 11 | bug-reports: "https://github.com/nyu-acsys/raven/issues" 12 | depends: [ 13 | "ocaml" {>= "4.12.0"} 14 | "dune" {>= "3.12" & >= "3.12"} 15 | "z3" {>= "4.13.0"} 16 | "ocamlformat" {>= "0.26.2"} 17 | "base" {>= "0.14"} 18 | "stdio" {>= "0.14"} 19 | "logs" {>= "0.7.0"} 20 | "fmt" {>= "0.9.0"} 21 | "cmdliner" {>= "1.2.0"} 22 | "ppx_custom_printf" {>= "0.14.1"} 23 | "ppx_compare" {>= "0.14.0"} 24 | "ppx_hash" {>= "0.14.0"} 25 | "ppx_sexp_conv" {>= "0.14.3"} 26 | "ppx_let" {>= "0.16.0"} 27 | "ppx_blob" {>= "0.7.2"} 28 | "odoc" {with-doc} 29 | ] 30 | build: [ 31 | ["dune" "subst"] {dev} 32 | [ 33 | "dune" 34 | "build" 35 | "-p" 36 | name 37 | "-j" 38 | jobs 39 | "@install" 40 | "@runtest" {with-test} 41 | "@doc" {with-doc} 42 | ] 43 | ] 44 | dev-repo: "git+https://github.com/nyu-acsys/raven.git" 45 | -------------------------------------------------------------------------------- /bench_results/bench_20250228_072408.csv: -------------------------------------------------------------------------------- 1 | File,Program Length,Proof Declarations,Proof Instructions,Runtime 2 | test/comparison/peterson.rav,29,11,40,1.663 3 | test/comparison/bounded_counter.rav,13,4,7,0.109 4 | test/comparison/inc_dec.rav,16,4,16,0.138 5 | test/comparison/lclist.rav,114,25,46,0.650 6 | test/comparison/barrier.rav,44,31,90,6.866 7 | test/concurrent/lock/clh-lock.rav,25,11,13,0.356 8 | test/comparison/fork_join.rav,11,11,7,0.127 9 | test/concurrent/lock/mcs-lock.rav,0,0,,0.000 10 | test/comparison/msc_queue.rav,34,13,29,0.338 11 | test/comparison/queue.rav,36,14,32,0.223 12 | 13 | test/comparison/rwlock_duolock.rav,45,14,23,0.400 14 | test/comparison/rwlock_lockless_faa.rav,19,7,25,0.309 15 | test/comparison/rwlock_ticket_bounded.rav,30,22,39,0.757 16 | test/comparison/rwlock_ticket_unbounded.rav,31,14,38,0.403 17 | 18 | test/comparison/fork_join_client.rav,10,6,3,0.118 19 | test/comparison/cas_counter_client.rav,12,6,4,0.147 20 | test/comparison/barrier_client.rav,35,50,87,0.754 21 | test/comparison/ticket_lock_client.rav,15,5,6,0.135 22 | 23 | test/concurrent/lock/spin-lock_compact.rav,10,6,8,0.148 24 | test/concurrent/lock/ticket-lock.rav,16,17,12,0.806 25 | test/comparison/arc.rav,24,18,50,0.357 26 | test/concurrent/treiber_stack/treiber_stack_atomics.rav,20,6,32,0.420 27 | test/comparison/cas_counter.rav,12,11,12,0.157 28 | 29 | test/comparison/tokens.rav,0,54,46,0.312 30 | 31 | test/concurrent/templates/ccm.rav,0,25,4,0.088 32 | test/concurrent/templates/flows_ra.rav,0,37,22,0.859 33 | test/concurrent/templates/keyset_ra.rav,0,23,0,0.257 34 | test/concurrent/templates/give-up.rav,38,57,120,4.976 35 | test/concurrent/templates/bplustree.rav,47,33,42,1.679 36 | test/arrays/array.rav,21,37,18,0.304 37 | test/arrays/ordered_array.rav,36,38,42,1.820 38 | 39 | WARMUP,0 40 | RUNS,1 41 | -------------------------------------------------------------------------------- /bin/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name raven) 3 | (public_name raven) 4 | (libraries 5 | base 6 | cmdliner 7 | fmt 8 | fmt.cli 9 | fmt.tty 10 | logs 11 | logs.cli 12 | logs.fmt 13 | config 14 | util 15 | ast 16 | frontend 17 | rewrites 18 | backend 19 | library) 20 | (preprocess 21 | (pps ppx_custom_printf)) 22 | (modes byte exe)) 23 | -------------------------------------------------------------------------------- /conventions.md: -------------------------------------------------------------------------------- 1 | # Coding conventions 2 | 3 | Here are some coding conventions that we should adhere to (in random order). 4 | 5 | * Reserve the use of exceptions for cases where program execution should be aborted. That is, there should only be one `try ... with` block in the entire code base, namely in the very top-level error handling function in `bin/raven.ml`. Use `Option.t` and friends instead of exceptions in other cases. Learn about monads/applicatives if you want nice syntax. 6 | 7 | * Do not write directly to standard output / standard error. Use the [Logs](https://erratique.ch/software/logs) module. 8 | 9 | * Use `begin ... end` blocks instead of `( ... )` whenever it improves code readability (e.g. for nested `match` expressions). 10 | 11 | * When the code of a lambda abstraction that is passed to a higher-order function spans many lines, replace it by an appropriately named function. 12 | 13 | * Avoid code duplication. When you are tempted to copy a large chunk of code, don't be lazy. Refactor it into a new function. 14 | 15 | * Try to keep error handling local. Instead of writing code like this: 16 | 17 | ```ocaml 18 | (match ... with 19 | | pattern(val) -> (* do a long complex computation with val *) 20 | | ... | ... | -> a bunch of error cases) 21 | ``` 22 | 23 | write it like this: 24 | 25 | ```ocaml 26 | let val = match ... with 27 | | pattern(val) -> val 28 | | ... | ... | -> a bunch of error cases 29 | in 30 | (* do a long complex computation with val *) 31 | ``` 32 | 33 | This increases the readability of the code. -------------------------------------------------------------------------------- /dune: -------------------------------------------------------------------------------- 1 | (env 2 | (dev 3 | (flags 4 | (:standard -warn-error -A -w -39 -w -27 -w -32))) 5 | (debug 6 | (flags 7 | (:standard -warn-error -A -w -39 -w -27 -w -32)) 8 | (ocamlopt_flags 9 | (:standard -g -Oclassic -inline 0)))) 10 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 3.12) 2 | (using menhir 2.1) 3 | (map_workspace_root false) 4 | 5 | (generate_opam_files) 6 | 7 | (source (github nyu-acsys/raven)) 8 | 9 | (authors "Ekanshdeep Gupta" "Nisarg Patel" "Thomas Wies") 10 | 11 | (maintainers "Ekanshdeep Gupta" "Nisarg Patel" "Thomas Wies") 12 | 13 | (license MIT) 14 | 15 | (package 16 | (name Raven) 17 | (synopsis "Intermediate verification language and deductive verifier for concurrent programs") 18 | (description "Raven is an intermediate verification language and SMT-based deductive verifier based on concurrent separation logic. It is intended as an intermediate layer for building program verification tools that target concurrent programs. Raven can also be used as a standalone educational tool.") 19 | (depends 20 | (ocaml 21 | (>= 4.12.0)) 22 | (dune 23 | (>= 3.12)) 24 | (z3 25 | (>= 4.13.0)) 26 | (ocamlformat 27 | (>= 0.26.2)) 28 | (base 29 | (>= 0.14)) 30 | (stdio 31 | (>= 0.14)) 32 | (logs 33 | (>= 0.7.0)) 34 | (fmt 35 | (>= 0.9.0)) 36 | (cmdliner 37 | (>= 1.2.0)) 38 | (ppx_custom_printf 39 | (>= 0.14.1)) 40 | (ppx_compare 41 | (>= 0.14.0)) 42 | (ppx_hash 43 | (>= 0.14.0)) 44 | (ppx_sexp_conv 45 | (>= 0.14.3)) 46 | (ppx_let 47 | (>= 0.16.0)) 48 | (ppx_blob 49 | (>= 0.7.2)) 50 | ) 51 | ) 52 | -------------------------------------------------------------------------------- /lib/ast/ast.ml: -------------------------------------------------------------------------------- 1 | (** External interface to AST-related modules *) 2 | 3 | include AstDef 4 | 5 | module SymbolTbl = struct 6 | include SymbolTbl 7 | end 8 | 9 | module Rewriter = struct 10 | include Rewriter 11 | end 12 | 13 | module ProgUtils = struct 14 | include ProgUtils 15 | end 16 | -------------------------------------------------------------------------------- /lib/ast/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name ast) 3 | (libraries base util) 4 | (preprocess 5 | (pps ppx_hash ppx_compare ppx_sexp_conv ppx_custom_printf))) 6 | -------------------------------------------------------------------------------- /lib/ast/traverser.ml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyu-acsys/raven/942dd316c5ee510c3c021c2da1f2f5cdfecc2273/lib/ast/traverser.ml -------------------------------------------------------------------------------- /lib/backend/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name backend) 3 | (libraries base ast frontend util unix str) 4 | (preprocess 5 | (pps ppx_hash ppx_compare ppx_sexp_conv ppx_custom_printf))) 6 | -------------------------------------------------------------------------------- /lib/config/config.ml: -------------------------------------------------------------------------------- 1 | (** Configuration and command line options *) 2 | 3 | (** Version string *) 4 | let version = "1.0.0" 5 | 6 | (** The command line options *) 7 | let cmd_options_spec = [] 8 | -------------------------------------------------------------------------------- /lib/config/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name config) 3 | (libraries base logs)) 4 | -------------------------------------------------------------------------------- /lib/frontend/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name frontend) 3 | (libraries base ast) 4 | (preprocess 5 | (pps ppx_hash ppx_compare ppx_sexp_conv ppx_custom_printf ppx_let))) 6 | 7 | ; (library 8 | ; (name rewrites) 9 | ; (libraries base ast frontend) 10 | ; ) 11 | 12 | (ocamllex 13 | (modules lexer)) 14 | 15 | (menhir 16 | (modules parser) 17 | (flags --explain)) 18 | -------------------------------------------------------------------------------- /lib/frontend/rewrites/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name rewrites) 3 | ; (modules rewrites) 4 | (libraries base ast util frontend) 5 | (preprocess 6 | (pps ppx_hash ppx_compare ppx_sexp_conv ppx_custom_printf ppx_let))) 7 | 8 | ; (library 9 | ; (name heap_explicit_trnsl) 10 | ; (modules heap_explicit_trnsl) 11 | ; (libraries base ast util typing) 12 | ; (preprocess (pps ppx_hash ppx_compare ppx_sexp_conv ppx_custom_printf ppx_let)) 13 | ; ) 14 | -------------------------------------------------------------------------------- /lib/frontend/rewrites/masks.ml: -------------------------------------------------------------------------------- 1 | open Base 2 | open Ast 3 | open Util 4 | 5 | let fixpoint_compute_masks (c : Callable.t) : (Callable.t, bool) Rewriter.t_ext 6 | = 7 | let open Rewriter.Syntax in 8 | 9 | let* new_mask = 10 | match c.call_decl.call_decl_kind with 11 | | Pred | Invariant -> ( 12 | let* fully_qual_iden = 13 | Rewriter.resolve (QualIdent.from_ident c.call_decl.call_decl_name) 14 | in 15 | 16 | let mask_set = 17 | match c.call_decl.call_decl_kind with 18 | | Pred -> Set.empty (module QualIdent) 19 | | Invariant -> Set.singleton (module QualIdent) fully_qual_iden 20 | | _ -> assert false 21 | in 22 | 23 | match c.call_def with 24 | | FuncDef { func_body = Some body } -> 25 | let* preds_list = ProgUtils.expr_preds_mentioned body in 26 | 27 | let* preds_symbols = 28 | Rewriter.List.map preds_list ~f:(fun pred -> 29 | Rewriter.find_and_reify pred) 30 | in 31 | 32 | let mask_set = 33 | List.fold preds_symbols ~init:mask_set ~f:(fun acc pred -> 34 | match pred with 35 | | CallDef pred_callable -> ( 36 | match pred_callable.call_decl.call_decl_mask with 37 | | None -> acc 38 | | Some mask -> Set.union acc mask) 39 | | _ -> assert false) 40 | in 41 | 42 | Rewriter.return mask_set 43 | (* assert false *) 44 | | FuncDef { func_body = None } -> Rewriter.return mask_set 45 | | ProcDef _ -> assert false) 46 | | Lemma | Proc -> 47 | let specs = 48 | c.call_decl.call_decl_precond @ c.call_decl.call_decl_postcond 49 | in 50 | 51 | let* preds_list = 52 | Rewriter.List.fold_left specs ~init:[] ~f:(fun acc spec -> 53 | let+ preds = 54 | ProgUtils.expr_preds_mentioned spec.spec_form 55 | in 56 | 57 | preds @ acc) 58 | in 59 | 60 | Logs.debug (fun m -> 61 | m "Masks.fixpoint_compute_masks: Callable: %a; preds_list: %a" 62 | Ident.pr c.call_decl.call_decl_name 63 | (Util.Print.pr_list_comma QualIdent.pr) 64 | preds_list); 65 | 66 | let* preds_symbols = 67 | Rewriter.List.map preds_list ~f:(fun pred -> 68 | Rewriter.find_and_reify pred) 69 | in 70 | 71 | let mask_set = 72 | List.fold preds_symbols 73 | ~init:(Set.empty (module QualIdent)) 74 | ~f:(fun acc pred -> 75 | match pred with 76 | | CallDef pred_callable -> ( 77 | match pred_callable.call_decl.call_decl_mask with 78 | | None -> acc 79 | | Some mask -> Set.union acc mask) 80 | | _ -> assert false) 81 | in 82 | 83 | Logs.debug (fun m -> 84 | m "Masks.fixpoint_compute_masks: Callable: %a; mask_set: %a" 85 | Ident.pr c.call_decl.call_decl_name 86 | (Util.Print.pr_list_comma QualIdent.pr) 87 | (Set.elements mask_set)); 88 | 89 | Rewriter.return mask_set 90 | | Func -> Rewriter.return (Set.empty (module QualIdent)) 91 | in 92 | 93 | if 94 | Option.is_some c.call_decl.call_decl_mask 95 | && Set.equal new_mask (Option.value_exn c.call_decl.call_decl_mask) 96 | then Rewriter.return c 97 | else 98 | let c = 99 | { c with call_decl = { c.call_decl with call_decl_mask = Some new_mask } } 100 | in 101 | let* _ = Rewriter.set_user_state true in 102 | Rewriter.return c 103 | 104 | let rec compute_iteration (m : Module.t) : (Module.t, bool) Rewriter.t_ext = 105 | let open Rewriter.Syntax in 106 | let* flag = Rewriter.current_user_state in 107 | 108 | if flag then 109 | let* _ = Rewriter.set_user_state false in 110 | let* m = Rewriter.Module.rewrite_callables ~f:fixpoint_compute_masks m in 111 | compute_iteration m 112 | else Rewriter.return m 113 | 114 | let compute_masks (m : Module.t) : Module.t Rewriter.t = 115 | Rewriter.eval_with_user_state ~init:true (compute_iteration m) 116 | -------------------------------------------------------------------------------- /lib/library/base_types.rav: -------------------------------------------------------------------------------- 1 | interface Type { 2 | rep type T 3 | } 4 | 5 | module IntType: Type { 6 | rep type T = Int 7 | } 8 | 9 | module BoolType: Type { 10 | rep type T = Bool 11 | } 12 | 13 | module RefType: Type { 14 | rep type T = Ref 15 | } 16 | 17 | module Option[E: Type] : Type { 18 | rep type T = data { 19 | case none 20 | case some(value: E) 21 | } 22 | } 23 | 24 | module List[E: Type] : Type { 25 | rep type T = data { 26 | case nil 27 | case cons(head: E, tail: T) 28 | } 29 | } 30 | 31 | // An ordered type 32 | interface OrderedType : Type { 33 | 34 | func lt(x: T, y: T) returns (res: Bool) 35 | 36 | func le(x: T, y: T) returns (res: Bool) { 37 | lt(x, y) || x == y 38 | } 39 | 40 | func compare(x: T, y: T) returns (res: Int) 41 | { 42 | x == y ? 0 : (lt(x, y) ? -1 : 1) 43 | } 44 | 45 | /*val bot: T 46 | val top: T 47 | 48 | auto axiom bot_smallest() 49 | ensures forall a: T :: {lt(a, bot)} !lt(a, bot) 50 | auto axiom top_largest() 51 | ensures forall a: T :: {lt(top, a)} !lt(top, a) 52 | auto axiom nontrivial() 53 | ensures bot != top*/ 54 | 55 | auto axiom lt_irreflexive() 56 | ensures forall a: T :: {lt(a, a)} !lt(a, a) 57 | auto axiom lt_antisymmetric() 58 | ensures forall a: T, b: T :: {lt(a, b)} {lt(b, a)} !lt(a, b) || !lt(b, a) 59 | auto axiom lt_total() 60 | ensures forall a: T, b: T :: {lt(a, b)} {lt(b, a)} lt(a, b) || lt(b, a) || a == b 61 | auto axiom lt_transitive() 62 | ensures forall a: T, b: T, c: T :: {lt(a, b), lt(b, c)} lt(a, b) && lt(b, c) ==> lt(a, c) 63 | 64 | } 65 | -------------------------------------------------------------------------------- /lib/library/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name library) 3 | (preprocessor_deps 4 | (file base_types.rav) 5 | (file resource_algebra.rav)) 6 | (preprocess 7 | (pps ppx_blob))) 8 | 9 | (cram 10 | (deps 11 | %{project_root}/bin/raven.exe 12 | %{project_root}/lib/library/base_types.rav 13 | %{project_root}/lib/library/resource_algebra.rav 14 | (:rav 15 | (glob_files_rec *.rav)))) 16 | -------------------------------------------------------------------------------- /lib/library/library.ml: -------------------------------------------------------------------------------- 1 | let base_types = [%blob "base_types.rav"] 2 | let resource_algebra = [%blob "resource_algebra.rav"] 3 | 4 | let sources = 5 | [ ("base_types.rav", base_types); 6 | ("resource_algebra.rav", resource_algebra) ] 7 | -------------------------------------------------------------------------------- /lib/library/library.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh --nostdlib base_types.rav resource_algebra.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /lib/util/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name util) 3 | (libraries base str logs fmt logs.fmt stdio library) 4 | (preprocess 5 | (pps ppx_hash ppx_compare ppx_sexp_conv ppx_custom_printf))) 6 | -------------------------------------------------------------------------------- /lib/util/error.ml: -------------------------------------------------------------------------------- 1 | (** Error messages and exceptions *) 2 | 3 | open Base 4 | 5 | type error_kind = 6 | | Generic 7 | | Lexical 8 | | Syntax 9 | | Type 10 | | Internal 11 | | Unsupported 12 | | Verification 13 | | RelatedLoc 14 | 15 | let error_kind_to_lsp_string = function 16 | | Generic -> "Generic" 17 | | Lexical -> "Lexical" 18 | | Syntax -> "Syntax" 19 | | Type -> "Type" 20 | | Internal -> "Internal" 21 | | Unsupported -> "Unsupported" 22 | | Verification -> "Verification" 23 | | RelatedLoc -> "RelatedLoc" 24 | 25 | 26 | let error_kind_to_string = function 27 | | Generic -> "Error" 28 | | Lexical -> "Lexical Error" 29 | | Syntax -> "Syntax Error" 30 | | Type -> "Type Error" 31 | | Internal -> "Internal Error" 32 | | Unsupported -> "Unsupported Error" 33 | | Verification -> "Verification Error" 34 | | RelatedLoc -> "Related Location" 35 | 36 | type t = error_kind * Loc.t * String.t 37 | 38 | exception Msg of t list 39 | 40 | let fail ?(lbl = Generic) loc msg = raise (Msg [ (lbl, loc, msg) ]) 41 | let fail_with errors = raise (Msg errors) 42 | 43 | let to_string (kind, (loc : Loc.t), msg) = 44 | let label = 45 | kind |> error_kind_to_string |> fun lbl -> 46 | Fmt.to_to_string 47 | (fun ppf lbl -> 48 | Fmt.pf ppf "%a: " Fmt.(styled Logs_fmt.err_style string) lbl) 49 | lbl 50 | in 51 | if Loc.(loc = Loc.dummy) then Printf.sprintf !"%{String}%{String}" label msg 52 | else 53 | (*if !Config.flycheck_mode 54 | then Printf.sprintf "%s:%s" (flycheck_string_of_src_pos pos) msg*) 55 | Printf.sprintf !"%{Loc}%{String}%{String}." loc label msg 56 | 57 | let to_lsp_string ppf (kind, (loc : Loc.t), msg) = 58 | let r = Str.regexp "\n" in 59 | let split_msg = Str.split r msg in 60 | let pr_string ppf s = Stdlib.Format.fprintf ppf "%s" s in 61 | Stdlib.Format.fprintf ppf !"@\n{ \"file\": \"%{String}\", \"start_line\": %d, \"start_col\": %d, \"end_line\": %d, \"end_col\": %d, \"kind\": \"%s\", \"message\": [\"%a\"] }" 62 | (Loc.file_name loc) (Loc.start_line loc) (Loc.start_col loc) (Loc.end_line loc) (Loc.end_col loc) (error_kind_to_lsp_string kind) (Print.pr_list_sep "\", \"" pr_string) split_msg 63 | 64 | let errors_to_lsp_string errs = 65 | let print_list ppf errs = Stdlib.Format.fprintf ppf "[@[<2>%a@]]" (Print.pr_list_comma to_lsp_string) errs in 66 | Print.string_of_format print_list errs 67 | 68 | (** Predefined error messags *) 69 | 70 | let internal_error loc msg = fail loc ~lbl:Internal msg 71 | let error loc msg = fail loc ~lbl:Generic msg 72 | let error_simple msg = fail Loc.dummy msg 73 | let lexical_error loc msg = fail loc ~lbl:Lexical msg 74 | let unsupported_error loc msg = fail loc ~lbl:Unsupported msg 75 | let type_error loc msg = fail loc ~lbl:Type msg 76 | let syntax_error loc msg = fail loc ~lbl:Syntax msg 77 | 78 | let redeclaration_error loc name = 79 | error loc 80 | (Printf.sprintf 81 | !"Identifier %{String} has already been declared in this scope" 82 | name) 83 | 84 | let verification_error loc msg = fail loc ~lbl:Verification msg 85 | -------------------------------------------------------------------------------- /lib/util/graph.ml: -------------------------------------------------------------------------------- 1 | open Base 2 | 3 | module type Vertex = sig 4 | type t 5 | 6 | val hash : t -> int 7 | 8 | include Comparable.S with type t := t 9 | include Sexpable.S with type t := t 10 | end 11 | 12 | (*module type Graph = sig 13 | type vertex 14 | type t 15 | 16 | module VertexSet = Set.M(String) 17 | module VertexMap = Set.M(String).t 18 | 19 | type t = VertexSet.t * VertexSet.t VertexMap.t 20 | 21 | end*) 22 | 23 | module Make (V : Vertex) = struct 24 | module VertexSet = Set.M (V) 25 | module VertexMap = Map.M (V) 26 | module H = Hashtbl.M (V) 27 | 28 | type vertex = V.t 29 | type t = VertexSet.t * VertexSet.t VertexMap.t 30 | 31 | let vertices (vs, _) = vs 32 | let empty_vertex_set = Set.empty (module V) 33 | let empty_vertex_map = Map.empty (module V) 34 | let empty = (empty_vertex_set, empty_vertex_map) 35 | 36 | let add_vertex (vs, es) (v : vertex) : t = 37 | (Set.add vs v, Map.add_exn ~key:v ~data:empty_vertex_set es) 38 | 39 | let add_edge (vs, es) (src : vertex) (dst : vertex) : t = 40 | ( Set.add vs src, 41 | Map.update es src ~f:(fun old_dsts_opt -> 42 | let old_dsts = Option.value old_dsts_opt ~default:empty_vertex_set in 43 | Set.add old_dsts dst) ) 44 | 45 | let add_edges (vs, es) (src : vertex) dsts : t = 46 | ( Set.add vs src, 47 | Map.update es src ~f:(fun old_dsts_opt -> 48 | let old_dsts = Option.value old_dsts_opt ~default:empty_vertex_set in 49 | Set.union old_dsts dsts) ) 50 | 51 | let union (vs1, es1) (vs2, es2) = 52 | Set.union vs1 vs2, 53 | Map.merge es1 es2 ~f:(fun ~key m -> 54 | Map.Merge_element.values m ~left_default:empty_vertex_set ~right_default:empty_vertex_set 55 | |> (fun (e1, e2) -> Some (Set.union e1 e2))) 56 | 57 | let succs (vs, es) v : VertexSet.t = 58 | Map.find es v |> Option.value ~default:empty_vertex_set 59 | 60 | let targets (vs, es) : VertexSet.t = 61 | Map.fold es ~f:(fun ~key ~data -> Set.union data) ~init:empty_vertex_set 62 | 63 | let pr pr_v ppf (vs, es) = 64 | let pr_es ppf (v, vs) = Stdlib.Format.fprintf ppf "%a -> %a" pr_v v (Print.pr_list_comma pr_v) (Set.elements vs) in 65 | Print.pr_list_nl pr_es ppf (Map.to_alist es) 66 | 67 | 68 | let topsort ((vs, es) : t) : V.t list list = 69 | let index = ref 0 in 70 | let indexes = Hashtbl.create (module V) in 71 | let lowlinks = Hashtbl.create (module V) in 72 | let s = Stack.create () in 73 | 74 | let rec tarjan (sccs : V.t list list) (v : V.t) = 75 | Hashtbl.set indexes ~key:v ~data:!index; 76 | Hashtbl.set lowlinks ~key:v ~data:!index; 77 | Int.incr index; 78 | let succs = Map.find es v |> Option.value ~default:empty_vertex_set in 79 | Stack.push s v; 80 | let sccs1 : V.t list list = 81 | Set.fold 82 | ~f:(fun sccs v' -> 83 | if not (Hashtbl.mem indexes v') then ( 84 | let sccs1 = tarjan sccs v' in 85 | Hashtbl.set lowlinks ~key:v 86 | ~data: 87 | (min 88 | (Hashtbl.find_exn lowlinks v) 89 | (Hashtbl.find_exn lowlinks v')); 90 | sccs1) 91 | else ( 92 | if Stack.exists s ~f:(fun y -> V.(v' = y)) then 93 | Hashtbl.set lowlinks ~key:v 94 | ~data: 95 | (min 96 | (Hashtbl.find_exn lowlinks v) 97 | (Hashtbl.find_exn indexes v')); 98 | sccs)) 99 | succs ~init:sccs 100 | in 101 | if Hashtbl.find_exn lowlinks v = Hashtbl.find_exn indexes v then 102 | let rec loop acc = 103 | let v' = Stack.pop_exn s in 104 | if V.(v = v') then v' :: acc else loop (v' :: acc) 105 | in 106 | loop [] :: sccs1 107 | else sccs1 108 | in 109 | let sccs = 110 | Set.fold 111 | ~f:(fun sccs v -> 112 | if not (Hashtbl.mem indexes v) then tarjan sccs v else sccs) 113 | vs ~init:[] 114 | in 115 | List.rev sccs 116 | end 117 | -------------------------------------------------------------------------------- /lib/util/loc.ml: -------------------------------------------------------------------------------- 1 | (** Source code locations *) 2 | 3 | module Opt = Option 4 | 5 | open Base 6 | 7 | type position = Lexing.position = { 8 | pos_fname : string; 9 | pos_lnum : int; 10 | pos_bol : int; 11 | pos_cnum : int; 12 | } 13 | [@@deriving sexp] 14 | 15 | let compare_position p1 p2 = 16 | let open Lexing in 17 | let f1 = Stdlib.Obj.magic p1.pos_fname in 18 | let f2 = Stdlib.Obj.magic p2.pos_fname in 19 | let c1 = compare_int f1 f2 in 20 | if c1 <> 0 then c1 else compare_int p1.pos_cnum p2.pos_cnum 21 | 22 | let equal_position p1 p2 = 23 | let open Lexing in 24 | phys_equal p1 p2 25 | || String.equal p1.pos_fname p2.pos_fname 26 | && Int.equal p1.pos_lnum p2.pos_lnum 27 | && Int.equal p1.pos_cnum p2.pos_cnum 28 | 29 | type t = { loc_start : position; loc_end : position } 30 | [@@deriving compare, equal, sexp] 31 | 32 | let make p1 p2 = { loc_start = p1; loc_end = p2 } 33 | let dummy = { loc_start = Lexing.dummy_pos; loc_end = Lexing.dummy_pos } 34 | 35 | open Lexing 36 | 37 | let column p = p.pos_cnum - p.pos_bol 38 | let start_line loc = loc.loc_start.pos_lnum 39 | let end_line loc = loc.loc_end.pos_lnum 40 | let start_col loc = column loc.loc_start 41 | let end_col loc = column loc.loc_end 42 | let start_bol loc = loc.loc_start.pos_bol 43 | let end_bol loc = loc.loc_end.pos_bol 44 | let file_name loc = loc.loc_start.pos_fname 45 | let to_end loc = { loc with loc_start = loc.loc_end } 46 | let to_start loc = { loc with loc_end = loc.loc_start } 47 | 48 | let start_index loc = loc.loc_start.pos_cnum 49 | let end_index loc = loc.loc_end.pos_cnum 50 | 51 | 52 | let merge l1 l2 = 53 | assert (String.equal (file_name l1) (file_name l2)); 54 | let spos = 55 | let c = compare_position l1.loc_start l2.loc_start in 56 | if c <= 0 then l1.loc_start else l2.loc_start 57 | in 58 | let epos = 59 | let c = compare_position l1.loc_end l2.loc_end in 60 | if c >= 0 then l1.loc_end else l2.loc_end 61 | in 62 | make spos epos 63 | 64 | let to_string_simple loc = 65 | if start_line loc <> end_line loc then 66 | Printf.sprintf "%s:%d:%d" (file_name loc) (start_line loc) (start_col loc) 67 | else 68 | let start_col, end_col = 69 | if start_col loc = end_col loc then 70 | if start_col loc = 0 then (0, 1) else (start_col loc - 1, end_col loc) 71 | else (start_col loc, end_col loc) 72 | in 73 | Printf.sprintf "%s:%d:%d-%d" (file_name loc) (start_line loc) start_col 74 | end_col 75 | 76 | let context loc = 77 | let rec in_channel_line ic (line_num : int) = 78 | let next_line = 79 | match Stdio.In_channel.input_line ic with 80 | | None -> Printf.sprintf "Cannot find line %s" (to_string_simple loc) 81 | | Some s -> s 82 | in 83 | 84 | if line_num = 0 then next_line 85 | else ( 86 | assert (line_num > 0); 87 | in_channel_line ic (line_num - 1)) 88 | in 89 | let ctx = 90 | List.find_map Library.sources ~f:(fun (lib_file_name, lib_source) -> 91 | if String.(file_name loc = lib_file_name) then 92 | let lib_source_str = String.split_lines lib_source in 93 | let ctx = List.nth_exn lib_source_str (start_line loc - 1) in 94 | Some ctx 95 | else None) 96 | |> Opt.lazy_value ~default:(fun () -> 97 | let ic = Stdio.In_channel.create (file_name loc) in 98 | let ctx = in_channel_line ic (start_line loc - 1) in 99 | let _ = Stdio.In_channel.close ic in 100 | ctx) 101 | in 102 | 103 | let highlight_prefix_len = 104 | 1 + String.length (Int.to_string @@ start_line loc) + 2 + start_col loc 105 | in 106 | let highlight_suffix_len = 107 | max 1 108 | @@ (if start_line loc = end_line loc then end_col loc else String.length ctx) 109 | - start_col loc 110 | in 111 | Printf.sprintf "%d | %s\n%s%s\n" (start_line loc) ctx 112 | (String.make highlight_prefix_len ' ') 113 | (String.make highlight_suffix_len '^') 114 | 115 | let to_string loc = 116 | if loc.loc_start.pos_lnum = loc.loc_end.pos_lnum then 117 | Printf.sprintf "File \"%s\", line %d, columns %d-%d:\n%s" (file_name loc) 118 | (start_line loc) (start_col loc) (end_col loc) (context loc) 119 | else 120 | Printf.sprintf "File \"%s\", line %d, column %d to line %d, column %d:\n%s" 121 | (file_name loc) (start_line loc) (start_col loc) (end_line loc) 122 | (end_col loc) (context loc) 123 | 124 | let ( = ) = equal 125 | -------------------------------------------------------------------------------- /lib/util/option.ml: -------------------------------------------------------------------------------- 1 | open Base 2 | include Option 3 | 4 | let lazy_value ~default = function Some x -> x | None -> default () 5 | let or_else ~f y = function Some x -> Some x | None -> f y 6 | let map_or_else ~m ~e y = function Some x -> Some (m x) | None -> e y 7 | let flat_map ~f = function Some x -> f x | None -> None 8 | let flat_map_or_else ~m ~e = function Some x -> m x | None -> e () 9 | 10 | module Syntax = struct 11 | let ( let+ ) m f = map m ~f 12 | let ( and+ ) = both 13 | let ( let* ) m f = bind m ~f 14 | let ( and* ) = both 15 | end 16 | -------------------------------------------------------------------------------- /lib/util/print.ml: -------------------------------------------------------------------------------- 1 | (** Pretty printing utility functions *) 2 | 3 | open Stdlib.Format 4 | 5 | let rec pr_list i pr_sep pr_x ppf = function 6 | | [] -> () 7 | | [ x ] -> fprintf ppf "%a" (pr_x i) x 8 | | x :: xs -> 9 | fprintf ppf "%a%a%a" (pr_x i) x pr_sep () (pr_list (i + 1) pr_sep pr_x) xs 10 | 11 | let pr_list_sep sep pr_x ppf = 12 | pr_list 0 (fun ppf _ -> fprintf ppf sep) (fun _ -> pr_x) ppf 13 | 14 | let pr_list_comma pr_x ppf = pr_list_sep ", " pr_x ppf 15 | let pr_list_nl pr_x ppf = pr_list_sep "@\n" pr_x ppf 16 | 17 | let pr_option pr_x ppf x = 18 | match x with None -> fprintf ppf "None" | Some x' -> pr_x ppf x' 19 | 20 | let pr_null ppf _ = fprintf ppf "..." 21 | 22 | (* Print.pr_map ~key:QualIdent.pr ~value:Expr.pr) quant_renaming_map *) 23 | let pr_map ~key ~value ppf map = 24 | let pr_binding ppf (k, v) = fprintf ppf "%a -> %a" key k value v in 25 | fprintf ppf "{ %a }" (pr_list_comma pr_binding) (Base.Map.to_alist map) 26 | 27 | let print_of_format pr x out_ch = 28 | fprintf (formatter_of_out_channel out_ch) "%a@?" pr x 29 | 30 | let string_of_format pr t = 31 | pr str_formatter t; 32 | flush_str_formatter () 33 | 34 | let print_list out_ch pr xs = print_of_format (pr_list_comma pr) xs out_ch 35 | 36 | let _ = 37 | pp_set_margin str_formatter 80; 38 | Stdlib.Format.set_max_indent 40 39 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyu-acsys/raven/942dd316c5ee510c3c021c2da1f2f5cdfecc2273/logo.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "raven", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /test/adt/list.rav: -------------------------------------------------------------------------------- 1 | module List { 2 | rep type T = data { 3 | case cons(head: Int, tail:T); 4 | case nil 5 | } 6 | 7 | proc max_elem(l: T) returns (r: Int) 8 | { 9 | if (l == cons(l.head, l.tail)) { 10 | val m: Int := max_elem(l.tail); 11 | r := l.head <= m ? m : l.head; 12 | } else { 13 | r := 0; 14 | } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/bugs/bogus_error_msg.rav: -------------------------------------------------------------------------------- 1 | field v: Int 2 | field l: Ref 3 | field r: Ref 4 | 5 | pred tree(x: Ref) { 6 | x == null 7 | ? true 8 | : (exists vv: Int, vl: Ref, vr: Ref :: own(x.v, vv) 9 | && own(x.l, vl) && tree(vl) 10 | && own(x.r, vr) && tree(vr)) 11 | } 12 | 13 | 14 | proc tree_delete_min(x: Ref) returns (z: Ref) 15 | requires x != null && tree(x) 16 | ensures tree(z) /* POST1 */ 17 | { 18 | var p: Ref := x; 19 | 20 | unfold tree(p); 21 | var pl := p.l; 22 | 23 | if (pl == null) { 24 | z := p.r; 25 | } else { 26 | var abort := true; 27 | while (!abort) 28 | invariant p != null && own(p.l, pl) && tree(pl) && pl != null 29 | { 30 | unfold tree(pl); 31 | var pll := pl.l; 32 | 33 | if (pll != null) { 34 | p := pl; 35 | pl := pl.l; 36 | } else { 37 | abort := true; 38 | } 39 | 40 | } 41 | 42 | unfold tree(pl); 43 | 44 | var plr := pl.r; 45 | p.l := plr; 46 | 47 | z := x; 48 | assume false; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/bugs/co_recursion.rav: -------------------------------------------------------------------------------- 1 | lemma p() 2 | ensures false 3 | { 4 | q(); 5 | } 6 | 7 | lemma q() 8 | ensures false 9 | { 10 | // assert false; 11 | p(); 12 | } 13 | 14 | proc invalid() 15 | ensures false 16 | { 17 | // assert false; 18 | p(); 19 | } -------------------------------------------------------------------------------- /test/bugs/diamond_modules.rav: -------------------------------------------------------------------------------- 1 | interface A { 2 | type T 3 | } 4 | 5 | interface B { 6 | module A1 : A 7 | 8 | proc p1(x: A1.T) { 9 | 10 | } 11 | } 12 | 13 | interface C { 14 | module A2 : A 15 | proc p2(x: A2.T) 16 | } 17 | 18 | interface D[B1: B] : C { 19 | module A2 = B1.A1 20 | 21 | 22 | proc p2(x: A2.T) { 23 | B1.p1(x); 24 | } 25 | 26 | // proc p2(x: B1.A1.T) { 27 | // B1.p1(x); 28 | // } 29 | } -------------------------------------------------------------------------------- /test/bugs/faulty_skolems.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | func g(a: Int, b: Int) returns (r: Bool) { true } 4 | 5 | proc p() { 6 | var x: Ref; 7 | 8 | inhale own(x.f, 5, 1.0); 9 | exhale exists a: Int, b: Int :: g(a,b) ==> own(x.f, a, 1.0); 10 | } -------------------------------------------------------------------------------- /test/bugs/rec_func_contract.rav: -------------------------------------------------------------------------------- 1 | func sum(n: Int) returns (res: Int) 2 | ensures res >= n 3 | { 4 | n <= 0 ? 0 : n + sum(n-1) 5 | } 6 | 7 | /* The following verifies, as it should. */ 8 | lemma sum_contract(n: Int) 9 | ensures sum(n) >= n 10 | { 11 | if (n > 0) { 12 | sum_contract(n-1); 13 | } 14 | } -------------------------------------------------------------------------------- /test/bugs/return_proc.rav: -------------------------------------------------------------------------------- 1 | proc p() 2 | returns (ret: Bool) 3 | { 4 | return true; 5 | } 6 | 7 | proc q() 8 | returns (ret: Bool) 9 | ensures ret == true 10 | { 11 | return p(); 12 | } -------------------------------------------------------------------------------- /test/bugs/unsound-with.rav: -------------------------------------------------------------------------------- 1 | // 'with' clauses are only sound for assert statements involving pure formulas. 2 | // Presently, Raven does not prevent the unsound use of 'with' as shown below. 3 | 4 | field f: () 5 | 6 | pred p(x: Ref) { 7 | own(x.f, ()) 8 | } 9 | 10 | proc unsound(x: Ref) 11 | requires own(x.f, ()) 12 | ensures false 13 | { 14 | assert p(x) with { 15 | fold p(x); 16 | } 17 | 18 | unfold p(x); 19 | } -------------------------------------------------------------------------------- /test/ci/back-end/agree_inhale.rav: -------------------------------------------------------------------------------- 1 | module IntType : Library.Type { 2 | rep type T = Int; 3 | } 4 | 5 | module NatAgree = Library.Agree[IntType] 6 | 7 | field f: NatAgree 8 | 9 | proc p() { 10 | var x: Ref; 11 | var a1: Int; 12 | var a2: Int; 13 | 14 | assume (a1 != a2); 15 | 16 | inhale own(x.f, NatAgree.agree(a1)); 17 | inhale own(x.f, NatAgree.agree(a2)); 18 | 19 | assert false; 20 | } -------------------------------------------------------------------------------- /test/ci/back-end/agree_inhale.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh agree_inhale.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/anti-aliasing.rav: -------------------------------------------------------------------------------- 1 | module Main { 2 | field f : Int 3 | 4 | proc test(x: Ref, y: Ref) 5 | requires own(x.f, 1, 0.75) 6 | requires own(y.f, 1, 0.75) 7 | ensures x != y 8 | { } 9 | } -------------------------------------------------------------------------------- /test/ci/back-end/anti-aliasing.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./anti-aliasing.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/atomic_spec/counter_no_inv.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | pred counter(x: Ref; v: Int) { 4 | own(x.c, v, 1.0) 5 | } 6 | 7 | proc incr(x: Ref, implicit ghost v: Int) 8 | atomic requires counter(x, v) 9 | atomic ensures counter(x, v + 1) 10 | { 11 | ghost var phi := bindAU(); 12 | 13 | 14 | ghost var v0: Int := openAU(phi); 15 | unfold counter(x, v0); 16 | var v1 := x.c; 17 | fold counter(x, v0); 18 | abortAU(phi); 19 | var new_v1 : Int := v1 + 1; 20 | 21 | ghost var v2: Int := openAU(phi); 22 | unfold counter(x,v2); 23 | 24 | var res := cas(x.c, v1, new_v1); 25 | 26 | if (!res) { 27 | fold counter(x, v2); 28 | abortAU(phi); 29 | ghost var v3: Int := openAU(phi); 30 | incr(x); 31 | commitAU(phi); 32 | } else { 33 | fold counter(x, new_v1); 34 | commitAU(phi); 35 | } 36 | } 37 | 38 | proc read(x: Ref, implicit ghost v: Int) 39 | returns (v2: Int) 40 | atomic requires counter(x, v) 41 | atomic ensures counter(x, v) && v2 == v 42 | { 43 | ghost var phi := bindAU(); 44 | 45 | ghost var v0: Int := openAU(phi); 46 | unfold counter(x, v0); 47 | var v1 := x.c; 48 | fold counter(x, v0); 49 | commitAU(phi, v1); 50 | 51 | return v1; 52 | } 53 | -------------------------------------------------------------------------------- /test/ci/back-end/atomic_spec/counter_no_inv.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./counter_no_inv.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/atomic_spec/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/ci/back-end/atomic_spec/treiber_stack_atomics.rav: -------------------------------------------------------------------------------- 1 | type IntOption = data { 2 | case none; 3 | case some(i: Int) 4 | } 5 | 6 | field head: Ref 7 | field next: Ref 8 | field value: Int 9 | 10 | type IntList = data { 11 | case nil; 12 | case cons(elem: Int, tl: IntList) 13 | } 14 | 15 | pred is_list(hd: Ref; xs: IntList) { 16 | hd == null ? 17 | xs == nil() : 18 | (xs != nil() && (exists tl0: Ref, q:Real :: q > 0.0 && (own(hd.value, xs.elem, q) && own(hd.next, tl0, q) && is_list(tl0, xs.tl)))) 19 | } 20 | 21 | pred is_stack(s: Ref; xs: IntList) { 22 | exists hd: Ref :: (is_list(hd, xs) && own(s.head, hd, 1.0)) 23 | } 24 | 25 | proc push(s: Ref, x: Int, implicit ghost xs: IntList) 26 | atomic requires is_stack(s, xs) 27 | atomic ensures is_stack(s, cons(x, xs)) 28 | { 29 | ghost var phi := bindAU(); 30 | ghost var xs0: IntList := openAU(phi); 31 | 32 | unfold is_stack(s, xs0); 33 | var hd: Ref := s.head; 34 | fold is_stack(s, xs0); 35 | 36 | abortAU(phi); 37 | 38 | var s0 : Ref; 39 | s0 := new(value: x, next: hd); 40 | 41 | ghost var xs1: IntList := openAU(phi); 42 | 43 | ghost var hd1: Ref; 44 | unfold is_stack(s, xs1)[hd1 := hd]; 45 | 46 | var res : Bool := cas(s.head, hd, s0); 47 | 48 | if (!res) { 49 | fold is_stack(s, xs1); 50 | abortAU(phi); 51 | ghost var xs2: IntList := openAU(phi); 52 | assert is_stack(s, xs2); 53 | push(s, x); 54 | commitAU(phi); 55 | } else { 56 | fold is_list(s0, cons(x, xs1))[q := 1.0]; 57 | fold is_stack(s, cons(x, xs1)); 58 | commitAU(phi); 59 | } 60 | 61 | // assert false; 62 | } 63 | 64 | proc pop(s: Ref, implicit ghost xs: IntList) 65 | returns (result: IntOption) 66 | atomic requires is_stack(s, xs) 67 | atomic ensures 68 | xs == nil() ? 69 | (is_stack(s, xs) && result == none()) : 70 | (is_stack(s, xs.tl) && result == some(xs.elem)) 71 | { 72 | ghost var phi := bindAU(); 73 | ghost var xs0: IntList := openAU(phi); 74 | 75 | unfold is_stack(s, xs0); 76 | 77 | var hd: Ref := s.(head); 78 | 79 | if (hd == null) { 80 | unfold is_list(hd, xs0); 81 | fold is_list(hd, xs0); 82 | fold is_stack(s, xs0); 83 | commitAU(phi, none()); 84 | } else { 85 | ghost var q:Real; 86 | ghost var tl0: Ref; 87 | unfold is_list(hd, xs0)[tl0 := tl0, q := q]; 88 | 89 | fold is_list(hd, xs0)[tl0 := tl0, q := q/2.0]; 90 | fold is_stack(s, xs0); 91 | abortAU(phi); 92 | } 93 | 94 | if (hd == null) { 95 | return none(); 96 | } 97 | 98 | var hd_next: Ref := hd.next; 99 | var hd_value: Int := hd.value; 100 | 101 | ghost var xs1: IntList := openAU(phi); 102 | 103 | ghost var hd1: Ref; 104 | unfold is_stack(s, xs1); 105 | hd1 :| is_list(hd1, xs1) && own(s.head, hd1, 1.0); 106 | 107 | var res : Bool := cas(s.head, hd, hd_next); 108 | 109 | if (res) { 110 | unfold is_list(hd1, xs1); 111 | assert hd1 != null; 112 | assert xs1 != nil(); 113 | fold is_stack(s, xs1.tl); 114 | commitAU(phi, some(hd_value)); 115 | 116 | return some(hd_value); 117 | } else { 118 | fold is_stack(s, xs1); 119 | abortAU(phi); 120 | ghost var xs2: IntList := openAU(phi); 121 | assert is_stack(s, xs2); 122 | var ret: IntOption := pop(s); 123 | commitAU(phi, ret); 124 | 125 | return ret; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /test/ci/back-end/atomic_spec/treiber_stack_atomics.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./treiber_stack_atomics.rav 2 | [Warning] File "./treiber_stack_atomics.rav", line 18, columns 21-134: 3 | 18 | (xs != nil() && (exists tl0: Ref, q:Real :: q > 0.0 && (own(hd.value, xs.elem, q) && own(hd.next, tl0, q) && is_list(tl0, xs.tl)))) 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | Verification Error: No witnesses could be computed for: q. 6 | Verification successful. 7 | -------------------------------------------------------------------------------- /test/ci/back-end/auth_inhale.rav: -------------------------------------------------------------------------------- 1 | module NatAuth = Library.Auth[Library.Nat] 2 | 3 | field f: NatAuth 4 | 5 | proc p() { 6 | var x: Ref; 7 | var a1: Int; 8 | var a2: Int; 9 | var b: Int; 10 | 11 | // assume (a1 != a2); 12 | 13 | inhale own(x.f, NatAuth.auth_frag(a1, b)); 14 | inhale own(x.f, NatAuth.auth_frag(a2, b)); 15 | 16 | assert false; 17 | } -------------------------------------------------------------------------------- /test/ci/back-end/auth_inhale.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh auth_inhale.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/bind_3.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | proc p(x: Ref) 4 | requires own(x.f, 5, 1.0) 5 | { 6 | ghost var v: Int; 7 | v :| own(x.f, v, 0.5); 8 | assert v == 5; 9 | } -------------------------------------------------------------------------------- /test/ci/back-end/bind_3.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh bind_3.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/data_recursion.rav: -------------------------------------------------------------------------------- 1 | type T = data { 2 | case tCase1(x: Int); 3 | case tCase2(y: R) 4 | } 5 | 6 | type R = data { 7 | case rCase1(z: Int, w: T) 8 | } 9 | 10 | field tData: T; 11 | 12 | proc tagY(x: Int, y: T) 13 | returns (r: Ref) 14 | ensures own(r, tData, tCase2(rCase1(1, y)), 1.0) { 15 | r := new (tData: tCase2(rCase1(1, y))); 16 | } 17 | -------------------------------------------------------------------------------- /test/ci/back-end/data_recursion.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh data_recursion.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/base_types.rav 5 | %{project_root}/lib/library/resource_algebra.rav 6 | (:rav 7 | (glob_files_rec *.rav)))) 8 | -------------------------------------------------------------------------------- /test/ci/back-end/exhale_existential_quant_elim.rav: -------------------------------------------------------------------------------- 1 | module NatAuth = Library.Auth[Library.Nat] 2 | module IntSetRA = Library.SetRA[Library.IntType] 3 | 4 | field f: NatAuth 5 | field g: Int 6 | field h: IntSetRA 7 | 8 | proc p() { 9 | var x: Ref; 10 | 11 | inhale own(x.f, NatAuth.auth_frag(3, 1)); 12 | inhale own(x.h, IntSetRA.set_constr({|3|})); 13 | exhale exists v: Int :: own(x.h, IntSetRA.set_constr({|v|})) && own(x.f, NatAuth.auth_frag(v, 0)); 14 | 15 | inhale forall z: Ref :: z != x ==> own(z.f, NatAuth.auth_frag(3, 1)); 16 | exhale forall z: Ref :: z != x ==> (exists v2: Int :: own(z.f, NatAuth.auth_frag(v2, 0))); 17 | } -------------------------------------------------------------------------------- /test/ci/back-end/exhale_existential_quant_elim.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./exhale_existential_quant_elim.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/alloc_ref_twice.rav: -------------------------------------------------------------------------------- 1 | module Agree_Int = Library.Agree[Library.IntType] 2 | 3 | field f: Agree_Int 4 | 5 | proc p() { 6 | var l: Ref; 7 | l := new(f: Agree_Int.agree(1)); 8 | l := new(f: Agree_Int.agree(2)); 9 | assert false; 10 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/alloc_ref_twice.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./alloc_ref_twice.rav 2 | [Error] File "./alloc_ref_twice.rav", line 9, columns 11-16: 3 | 9 | assert false; 4 | ^^^^^ 5 | Verification Error: This assertion may be violated. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/bind_2.rav: -------------------------------------------------------------------------------- 1 | proc p() { 2 | ghost var x: Int; 3 | x :| x < 7 && 10 < x; 4 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/bind_2.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh bind_2.rav 2 | [Error] File "bind_2.rav", line 3, columns 7-22: 3 | 3 | x :| x < 7 && 10 < x; 4 | ^^^^^^^^^^^^^^^ 5 | Verification Error: The right-hand side of this bind statement may not hold. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/bind_4.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | proc p(x: Ref) 4 | requires own(x.f, 5, 0.5) 5 | { 6 | ghost var v: Int; 7 | v :| own(x.f, v, 1.0); 8 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/bind_4.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh bind_4.rav 2 | [Error] File "bind_4.rav", line 7, columns 7-23: 3 | 7 | v :| own(x.f, v, 1.0); 4 | ^^^^^^^^^^^^^^^^ 5 | Verification Error: The right-hand side of this bind statement may not hold. 6 | [Error] File "bind_4.rav", line 7, columns 7-23: 7 | 7 | v :| own(x.f, v, 1.0); 8 | ^^^^^^^^^^^^^^^^ 9 | Related Location: This own predicate may not hold. 10 | [1] 11 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/fpu_fail.rav: -------------------------------------------------------------------------------- 1 | ghost field f: Int 2 | 3 | proc p(x:Ref, v:Int) 4 | requires own(x.f, v, 0.75) 5 | 6 | { 7 | fpu(x.f, 4); 8 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/fpu_fail.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./fpu_fail.rav 2 | [Error] File "./fpu_fail.rav", line 7, columns 2-14: 3 | 7 | fpu(x.f, 4); 4 | ^^^^^^^^^^^^ 5 | Verification Error: This update may not be frame-preserving. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/masks_1.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | inv inv1(x: Ref, v: Int) { 4 | own(x.f, v, 1.0) 5 | } 6 | 7 | inv inv2(x: Ref, v: Int) { 8 | inv1(x, v) 9 | } 10 | 11 | 12 | proc q(x: Ref, v: Int) 13 | requires inv1(x, v) 14 | requires own(x.f, v, 1.0) 15 | ensures false 16 | { 17 | unfold inv1(x, v); 18 | fold inv1(x, v); 19 | } 20 | 21 | proc p(x: Ref, v: Int) 22 | requires inv2(x, v) 23 | ensures false 24 | { 25 | unfold inv2(x,v); 26 | fold inv2(x,v); 27 | unfold inv1(x,v); 28 | q(x, v); 29 | fold inv1(x,v); 30 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/masks_1.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./masks_1.rav 2 | [Error] File "./masks_1.rav", line 28, columns 2-10: 3 | 28 | q(x, v); 4 | ^^^^^^^^ 5 | Verification Error: Cannot call q. The invariant inv1 required by q is not available in the current mask. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/missing_permissions.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | field f: Int 3 | 4 | proc q(x: Ref) 5 | requires exists v:Int :: own(x.f, v, 0.1) 6 | // ensures exists v:Int :: own(x.f, v, 0.1) 7 | { 8 | 9 | } 10 | 11 | proc p(x: Ref) 12 | requires exists v:Int :: own(x.f, v, 1.0) 13 | ensures exists v:Int :: own(x.f, v, 1.0) 14 | { 15 | q(x); 16 | } 17 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/missing_permissions.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./missing_permissions.rav 2 | [Error] File "./missing_permissions.rav", line 16, columns 3-3: 3 | 16 | } 4 | ^ 5 | Verification Error: A postcondition may not hold at this return point. 6 | [Error] File "./missing_permissions.rav", line 13, columns 28-44: 7 | 13 | ensures exists v:Int :: own(x.f, v, 1.0) 8 | ^^^^^^^^^^^^^^^^ 9 | Related Location: This own predicate may not hold. 10 | [1] 11 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/multiple_witness_soundness_fix.rav: -------------------------------------------------------------------------------- 1 | module Agree = Library.Agree[Library.RefType] 2 | 3 | func f1(l: Ref) returns (ret: Bool) {true} 4 | func f2(l: Ref) returns (ret: Bool) {true} 5 | 6 | 7 | field lock: Ref 8 | ghost field agr: Agree 9 | 10 | pred is_list(n: Ref) { 11 | exists l: Ref :: 12 | (f1(l) ==> own(n.lock, l, 0.5)) && 13 | (f2(l) ==> own(n.lock, l, 0.5)) && 14 | (f2(l) ==> own(n.agr, Agree.agree(l))) 15 | } 16 | 17 | proc create_buggy() 18 | { 19 | var r := new(lock: null, agr: Agree.agree(null)); 20 | 21 | var l: Ref; 22 | assume l != null; 23 | r.lock := l; 24 | assert own(r.lock, l, 1.0); 25 | 26 | // The following fails, as it should: 27 | fold is_list(r); 28 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/multiple_witness_soundness_fix.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh multiple_witness_soundness_fix.rav 2 | [Error] File "multiple_witness_soundness_fix.rav", line 27, columns 4-20: 3 | 27 | fold is_list(r); 4 | ^^^^^^^^^^^^^^^^ 5 | Verification Error: Failed to fold predicate. The body of the predicate may not hold at this point. 6 | [Error] File "multiple_witness_soundness_fix.rav", line 12, columns 19-38: 7 | 12 | (f1(l) ==> own(n.lock, l, 0.5)) && 8 | ^^^^^^^^^^^^^^^^^^^ 9 | Related Location: This own predicate may not hold. 10 | [1] 11 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/new_stmt_validity_check.rav: -------------------------------------------------------------------------------- 1 | module Agree_Int = Library.Agree[Library.IntType] 2 | 3 | field f: Agree_Int 4 | 5 | proc p() { 6 | var l: Ref; 7 | l := new(f: Agree_Int.agree_top); 8 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/new_stmt_validity_check.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh new_stmt_validity_check.rav 2 | [Error] File "new_stmt_validity_check.rav", line 7, columns 4-37: 3 | 7 | l := new(f: Agree_Int.agree_top); 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | Verification Error: Could not prove validity of initially-allocated value. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/fail/while_loop.rav: -------------------------------------------------------------------------------- 1 | proc p() { 2 | var s: Int := 0; 3 | var p: Map[Int, Int] := {| v: Int :: 0 |}; 4 | 5 | while (s < 10) 6 | invariant s >= 0 7 | invariant forall i: Int :: 0 <= i < s ==> p[i] == i 8 | // invariant s <= 8 9 | 10 | { 11 | p := p[s := s]; 12 | s := s + 1; 13 | } 14 | 15 | assert p[9] == 1; 16 | assert false; 17 | } -------------------------------------------------------------------------------- /test/ci/back-end/fail/while_loop.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./while_loop.rav 2 | [Error] File "./while_loop.rav", line 15, columns 9-18: 3 | 15 | assert p[9] == 1; 4 | ^^^^^^^^^ 5 | Verification Error: This assertion may be violated. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/forward_trg_assertions.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | 4 | func loc_id(x: Ref) 5 | returns (r: Ref) 6 | { x } 7 | 8 | func t(x: Ref) 9 | returns (r: Bool) 10 | { true } 11 | 12 | func guard(x: Ref, b: Bool) 13 | returns (r: Bool) 14 | { true } 15 | 16 | proc p() { 17 | var b: Bool := true; 18 | 19 | if (b) { 20 | inhale forall x: Ref :: { t(x) } guard(x, b) ==> own(loc_id(x).f, 1, 1.0); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /test/ci/back-end/forward_trg_assertions.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./forward_trg_assertions.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/frac_ra_fpu.rav: -------------------------------------------------------------------------------- 1 | module Main { 2 | 3 | module M1: Library.Type { 4 | rep type T = Int 5 | } 6 | 7 | module M2 = Library.Frac[M1] 8 | 9 | ghost field f : M2 10 | 11 | proc test(x: Ref) 12 | requires own(x.f, M2.frac_chunk(4, 1.0)) 13 | { 14 | fpu(x, f, M2.frac_chunk(4, 1.0), M2.frac_chunk(5, 1.0)); 15 | } 16 | } -------------------------------------------------------------------------------- /test/ci/back-end/frac_ra_fpu.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./frac_ra_fpu.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/heap_valid_no_null_test.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | field g: Library.Nat 3 | 4 | proc p() { 5 | var x: Ref; 6 | x := new(f: 1, g: 1); 7 | x := new(g: 1); 8 | 9 | inhale own(x.f, 1, 1.0); 10 | inhale own(x.g, 1); 11 | 12 | exhale own(x.f, 1, 1.0); 13 | exhale own(x.g, 1); 14 | } 15 | -------------------------------------------------------------------------------- /test/ci/back-end/heap_valid_no_null_test.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./heap_valid_no_null_test.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/inhale_exhale.rav: -------------------------------------------------------------------------------- 1 | module IntType : Library.Type { 2 | rep type T = Int; 3 | } 4 | 5 | module FracInt = Library.Frac[IntType]; 6 | 7 | field f: FracInt 8 | field g: Int 9 | 10 | func p(v: Ref) returns (ret: Bool) { 11 | true 12 | } 13 | 14 | proc pr() { 15 | var x: Ref; 16 | ghost var myMap: Map[Ref, Int]; 17 | 18 | inhale forall x: Ref :: p(x) ==> (exists v: Int :: own(x.f, FracInt.frac_chunk(v, 1.0))); 19 | myMap :| forall x: Ref :: p(x) ==> (own(x.f, FracInt.frac_chunk(myMap[x], 1.0))); 20 | 21 | assert forall x: Ref :: p(x) ==> own(x.f, FracInt.frac_chunk(myMap[x], 1.0)); 22 | exhale forall x: Ref :: p(x) ==> (exists v: Int :: own(x.f, FracInt.frac_chunk(v, 1.0))); 23 | 24 | 25 | ghost var skolem: Int; 26 | inhale exists v:Int :: own(x.f, FracInt.frac_chunk(v, 1.0)); 27 | skolem :| own(x.f, FracInt.frac_chunk(skolem, 1.0)); 28 | 29 | assert own(x.f, FracInt.frac_chunk(skolem, 1.0)); 30 | exhale exists v:Int :: own(x.f, FracInt.frac_chunk(v, 1.0)); 31 | } -------------------------------------------------------------------------------- /test/ci/back-end/inhale_exhale.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./inhale_exhale.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/isc_multiquant.rav: -------------------------------------------------------------------------------- 1 | interface Foo { 2 | type Server 3 | type Broker 4 | type Time 5 | 6 | func loc(s: Server, b: Broker, t: Time) returns (r: Ref) 7 | func sindex(r: Ref) returns (s: Server) 8 | func bindex(r: Ref) returns (b: Broker) 9 | func tindex(r: Ref) returns (t: Time) 10 | 11 | auto axiom aall_diff() 12 | ensures forall s: Server, b: Broker, t: Time :: {loc(s, b, t)} 13 | sindex(loc(s,b,t)) == s && bindex(loc(s,b,t)) == b && tindex(loc(s,b,t)) == t 14 | 15 | field value: () 16 | 17 | proc foo(s: Server, b: Broker, t: Time, brks: Set[Broker]) 18 | requires b in brks 19 | requires forall b: Broker, t: Time :: b in brks ==> own(loc(s,b,t).value, ()) 20 | { 21 | val u := loc(s, b, t).value; 22 | } 23 | } -------------------------------------------------------------------------------- /test/ci/back-end/isc_multiquant.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./isc_multiquant.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/ite_preds.rav: -------------------------------------------------------------------------------- 1 | interface Test { 2 | pred p(x: Int, y: Int) { 3 | true 4 | } 5 | 6 | pred q(x: Int) { 7 | true 8 | } 9 | 10 | field field1: Int 11 | 12 | func f(x: Int) returns (ret: Ref) 13 | func f2(x: Int) returns (ret: Int) 14 | 15 | func g(x: Ref) returns (ret: Bool) 16 | 17 | auto lemma f_diff() 18 | ensures forall x1: Int, x2: Int :: f(x1) == f(x2) ==> x1 == x2 19 | 20 | auto lemma f2_diff() 21 | ensures forall x1: Int, x2: Int :: f2(x1) == f2(x2) ==> x1 == x2 22 | 23 | 24 | proc p2() { 25 | inhale forall x: Int, y: Int :: 0 <= x <= 10 && 0 <= y <= 10 ==> 26 | p(x, y); 27 | exhale forall x: Int, y: Int :: 0 <= x <= 10 && 0 <= y <= 10 ==> 28 | p(x, y); 29 | 30 | inhale forall x: Int :: 0 <= x <= 5 ==> 31 | own(f(x).field1, x, 1.0 ); 32 | exhale forall x: Int :: 0 <= x <= 5 ==> 33 | own(f(x).field1, x, 1.0 ); 34 | 35 | inhale forall y: Ref :: g(y) ==> own(y.field1, 1, 1.0); 36 | exhale forall y: Ref :: g(y) ==> own(y.field1, 1, 1.0); 37 | 38 | inhale forall x: Int :: 0 <= x && x <= 5 ==> 39 | q(x); 40 | exhale forall x: Int :: 0 <= x && x <= 5 ==> 41 | q(x); 42 | 43 | inhale forall x: Int, y: Int :: 0 <= x && x <= 10 && 0 <= y <= 10 ==> 44 | p(f2(x), y); 45 | 46 | exhale forall x: Int, y: Int :: 0 <= x && x <= 10 && 0 <= y <= 10 ==> 47 | p(f2(x), y); 48 | } 49 | } -------------------------------------------------------------------------------- /test/ci/back-end/ite_preds.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./ite_preds.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/array-max.rav: -------------------------------------------------------------------------------- 1 | /* Encoding of arrays */ 2 | 3 | interface IArray { 4 | rep type T 5 | 6 | func loc(a: T, i: Int) returns (r: Ref) 7 | func len(a: T) returns (l: Int) 8 | func first(r: Ref) returns (a: T) 9 | func second(r: Ref) returns (i: Int) 10 | 11 | auto lemma all_diff() 12 | ensures forall a:T, i: Int :: {loc(a, i)} first(loc(a, i)) == a && second(loc(a, i)) == i 13 | 14 | auto lemma len_nonneg() 15 | ensures forall a:T :: {len(a)} len(a) >= 0 16 | } 17 | 18 | module ArrayMax[M: IArray] { 19 | field value: Int 20 | 21 | pred arr(a: M, m: Map[Int, Int]) { 22 | forall j: Int :: 0 <= j < M.len(a) ==> own(M.loc(a, j).value, m[j], 1.0) 23 | } 24 | 25 | val x: Int := 4 26 | 27 | func is_max(i: Int, m: Map[Int, Int], u: Int) 28 | returns (res: Bool) 29 | { 30 | forall j: Int :: {m[j]} 0 <= j && j < u ==> m[j] <= m[i] 31 | } 32 | 33 | proc max(a: M, implicit ghost m: Map[Int, Int]) 34 | returns (x: Int) 35 | requires arr(a, m) 36 | ensures arr(a, m) 37 | ensures M.len(a) == 0 ? x == -1 : (0 <= x && x < M.len(a)) 38 | ensures is_max(x, m, M.len(a)) 39 | { 40 | M.all_diff(); 41 | M.len_nonneg(); 42 | var z : Int; 43 | if (M.len(a) == 0) { 44 | x := -1; 45 | } else { 46 | var y: Int; 47 | x := 0; 48 | y := M.len(a) - 1; 49 | 50 | while (x != y) 51 | invariant arr(a, m) 52 | invariant 0 <= x && x <= y && y < M.len(a) 53 | invariant (forall i: Int :: 54 | (((0 <= i && i < x) || (y < i && i < M.len(a))) 55 | ==> m[i] < m[x]) || 56 | (((0 <= i && i < x) || (y < i && i < M.len(a))) 57 | ==> m[i] <= m[y]) 58 | ) 59 | { 60 | M.all_diff(); 61 | unfold arr(a,m); 62 | 63 | var tmp1 : Int := M.loc(a, x).value; 64 | var tmp2 : Int := M.loc(a, y).value; 65 | 66 | if (tmp1 <= tmp2) { 67 | x := x + 1; 68 | } else { 69 | y := y - 1; 70 | } 71 | fold arr(a,m); 72 | } 73 | } 74 | 75 | //fold is_max(x, m, M.len(a)); 76 | } 77 | 78 | 79 | /* 80 | method client() { 81 | var a: IArray 82 | inhale len(a) == 3 83 | inhale access(a) 84 | inhale forall i: Int :: 0 <= i && i < len(a) ==> loc(a, i).value == i 85 | 86 | var x: Int 87 | x := max(a) 88 | 89 | assert loc(a, 0).value <= x 90 | 91 | assert x == loc(a, len(a) - 1).value 92 | /* Necessary to prove the final assertion (due to triggering) */ 93 | 94 | assert x == 2 95 | 96 | assert loc(a, 1).value < x 97 | } 98 | */ 99 | } 100 | 101 | 102 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/array-max.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./array-max.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/dutch-flag.rav: -------------------------------------------------------------------------------- 1 | interface IArray { 2 | rep type T 3 | 4 | func loc(a: T, i: Int) returns (r: Ref) 5 | func len(a: T) returns (l: Int) 6 | func first(r: Ref) returns (a: T) 7 | func second(r: Ref) returns (i: Int) 8 | 9 | auto lemma all_diff() 10 | ensures forall a:T, i: Int :: first(loc(a, i)) == a && second(loc(a, i)) == i 11 | 12 | auto lemma len_nonneg() 13 | ensures forall a:T :: len(a) >= 0 14 | } 15 | 16 | module DutchFlag[Arr: IArray] { 17 | field value: Int; 18 | 19 | pred ordered(m: Map[Int, Int], len: Int) { 20 | forall i: Int, j: Int :: 0 <= i && i < j && j < len ==> m[i] <= m[j] 21 | } 22 | 23 | pred access(a: Arr, implicit ghost m: Map[Int, Int]) { 24 | forall i: Int :: 0 <= i && i < Arr.len(a) ==> own(Arr.loc(a, i).value, m[i], 1.0) 25 | } 26 | 27 | proc dutchFlag(a: Arr, implicit ghost m: Map[Int, Int]) 28 | returns (ghost m2: Map[Int, Int]) 29 | requires access(a,m) 30 | requires forall i: Int :: 0 <= i && i < Arr.len(a) ==> m[i] == 0 || m[i] == 1 || m[i] == 2 31 | ensures access(a,m2) && ordered(m2, Arr.len(a)) 32 | { 33 | var unsorted : Int := 0; 34 | var white : Int := 0; 35 | var blue : Int := Arr.len(a); 36 | m2 := m; 37 | 38 | while (unsorted < blue) 39 | invariant access(a, m2) 40 | invariant 0 <= white && white <= unsorted && unsorted <= blue && blue <= Arr.len(a) 41 | invariant forall i: Int :: 0 <= i && i < Arr.len(a) ==> m2[i] == 0 || m2[i] == 1 || m2[i] == 2 42 | invariant forall i : Int :: 0 <= i && i < white ==> m2[i] == 0 43 | invariant forall i : Int :: white <= i && i < unsorted ==> m2[i] == 1 44 | invariant forall i : Int :: blue <= i && i < Arr.len(a) ==> m2[i] == 2 45 | { 46 | unfold access(a, m2); 47 | var tmp : Int := Arr.loc(a,unsorted).value; 48 | 49 | if (tmp == 1) { 50 | unsorted := unsorted + 1; 51 | } else if (tmp == 0) { 52 | var tmp1 : Int := Arr.loc(a,white).value; 53 | Arr.loc(a,unsorted).value := tmp1; 54 | var tmp2 : Int := Arr.loc(a,white).value; 55 | m2 := m2[unsorted := tmp2]; 56 | 57 | Arr.loc(a,white).value := tmp; 58 | m2 := m2[white := tmp]; 59 | 60 | white := white + 1; 61 | unsorted := unsorted + 1; 62 | } else { 63 | var tmp1 : Int := Arr.loc(a,blue - 1).value; 64 | Arr.loc(a,unsorted).value := tmp1; 65 | 66 | var tmp2 : Int := Arr.loc(a,blue - 1).value; 67 | m2 := m2[unsorted := tmp2]; 68 | 69 | blue := blue - 1; 70 | Arr.loc(a,blue).value := tmp; 71 | m2 := m2[blue := tmp ]; 72 | } 73 | fold access(a, m2); 74 | } 75 | 76 | fold ordered(m2, Arr.len(a)); 77 | } 78 | 79 | proc test1(x: Ref, y: Ref) 80 | requires own(x.value, 5, 0.75) 81 | requires own(y.value, 5, 0.75) 82 | ensures (x != y) 83 | { } 84 | 85 | proc test2(l: Ref) 86 | requires own(l.value, 5, 1.0/2.0) 87 | requires own(l.value, 5, 0.5) 88 | ensures own(l.value, 5, 1.0) 89 | { } 90 | 91 | } 92 | 93 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/dutch-flag.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./dutch-flag.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/dutch-flag_unsound.rav: -------------------------------------------------------------------------------- 1 | interface IArray { 2 | rep type T 3 | 4 | func loc(a: T, i: Int) returns (r: Ref) 5 | func len(a: T) returns (l: Int) 6 | func first(r: Ref) returns (a: T) 7 | func second(r: Ref) returns (i: Int) 8 | 9 | auto lemma all_diff() 10 | ensures forall a:T, i: Int :: first(loc(a, i)) == a && second(loc(a, i)) == i 11 | 12 | auto lemma len_nonneg() 13 | ensures forall a:T :: len(a) >= 0 14 | } 15 | 16 | module DutchFlag[Arr: IArray] { 17 | field value: Int; 18 | 19 | pred ordered(m: Map[Int, Int], len: Int) { 20 | forall i: Int, j: Int :: 0 <= i && i < j && j < len ==> m[i] <= m[j] 21 | } 22 | 23 | pred access(a: Arr, implicit ghost m: Map[Int, Int]) { 24 | forall i: Int :: 0 <= i && i < Arr.len(a) ==> own(Arr.loc(a, i).value, m[i], 1.0) 25 | } 26 | 27 | proc dutchFlag(a: Arr, implicit ghost m: Map[Int, Int]) 28 | returns (ghost m2: Map[Int, Int]) 29 | requires access(a,m) 30 | requires forall i: Int :: 0 <= i && i < Arr.len(a) ==> m[i] == 0 || m[i] == 1 || m[i] == 2 31 | ensures access(a,m2) && ordered(m2, Arr.len(a)) 32 | // ensures access(a,m) && ordered(m, Arr.len(a)) 33 | { 34 | var unsorted : Int := 0; 35 | var white : Int := 0; 36 | var blue : Int := Arr.len(a); 37 | m2 := m; 38 | 39 | while (unsorted < blue) 40 | invariant access(a, m) 41 | invariant 0 <= white && white <= unsorted && unsorted <= blue && blue <= Arr.len(a) 42 | // invariant forall i: Int :: 0 <= i && i < Arr.len(a) ==> m[i] == 0 || m[i] == 1 || m[i] == 2 43 | // invariant forall i : Int :: 0 <= i && i < white ==> m[i] == 0 44 | // invariant forall i : Int :: white <= i && i < unsorted ==> m[i] == 1 45 | // invariant forall i : Int :: blue <= i && i < Arr.len(a) ==> m[i] == 2 46 | { 47 | unfold access(a, m); 48 | // assert false; 49 | var tmp : Int := Arr.loc(a,unsorted).value; 50 | assert false; 51 | 52 | 53 | if (tmp == 1) { 54 | unsorted := unsorted + 1; 55 | } else if (tmp == 0) { 56 | assert false; 57 | 58 | var tmp1 : Int := Arr.loc(a,white).value; 59 | Arr.loc(a,unsorted).value := tmp1; 60 | var tmp2 : Int := Arr.loc(a,white).value; 61 | m2 := m2[unsorted := tmp2]; 62 | 63 | Arr.loc(a,white).value := tmp; 64 | m2 := m2[white := tmp]; 65 | 66 | white := white + 1; 67 | unsorted := unsorted + 1; 68 | } else { 69 | assert false; 70 | 71 | var tmp1 : Int := Arr.loc(a,blue - 1).value; 72 | Arr.loc(a,unsorted).value := tmp1; 73 | 74 | var tmp2 : Int := Arr.loc(a,blue - 1).value; 75 | m2 := m2[unsorted := tmp2]; 76 | 77 | blue := blue - 1; 78 | Arr.loc(a,blue).value := tmp; 79 | m2 := m2[blue := tmp ]; 80 | } 81 | assert false; 82 | fold access(a, m); 83 | } 84 | 85 | assume false; 86 | fold ordered(m, Arr.len(a)); 87 | } 88 | 89 | proc test1(x: Ref, y: Ref) 90 | requires own(x.value, 5, 0.75) 91 | requires own(y.value, 5, 0.75) 92 | ensures (x != y) 93 | { } 94 | 95 | proc test2(l: Ref) 96 | requires own(l.value, 5, 1.0/2.0) 97 | requires own(l.value, 5, 0.5) 98 | ensures own(l.value, 5, 1.0) 99 | { } 100 | 101 | } 102 | 103 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated-star/dutch-flag_unsound.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./dutch-flag_unsound.rav 2 | [Error] File "./dutch-flag_unsound.rav", line 50, columns 19-24: 3 | 50 | assert false; 4 | ^^^^^ 5 | Verification Error: This assertion may be violated. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated_sep_star_encoding.rav: -------------------------------------------------------------------------------- 1 | interface Test { 2 | pred p(x: Ref, y: Int) { 3 | true 4 | } 5 | 6 | field f: Int 7 | 8 | func lookup(x:Ref, y: Int) 9 | returns (ret: Ref) 10 | 11 | auto lemma all_diff() 12 | ensures forall a:Ref, b:Ref, i1: Int, i2: Int :: lookup(a, i1) == lookup(b, i2) ==> a == b && i1 == i2 13 | 14 | proc q() { 15 | inhale forall x: Ref, y: Int :: 0 <= y <= 10 ==> p(lookup(x, y), y); 16 | exhale forall x: Ref, y: Int :: 0 <= y <= 10 ==> p(lookup(x, y), y); 17 | 18 | inhale forall x: Ref, y: Int :: 0 <= y <= 10 ==> own(lookup(x, y).f, y, 1.0); 19 | exhale forall x: Ref, y: Int :: 0 <= y <= 10 ==> own(lookup(x, y).f, y, 1.0); 20 | 21 | inhale forall x: Ref, y: Int :: 0 <= y <= 10 ==> own(lookup(x, y).f, y, 1.0); 22 | 23 | var x: Ref; 24 | exhale own(lookup(x, 3).f, 3, 1.0); 25 | exhale own(lookup(x, 4).f, 4, 1.0); 26 | 27 | var y: Int; 28 | 29 | inhale own(x.f, y, 1.0); 30 | exhale own(x.f, y, 1.0); 31 | 32 | inhale own(x.f, y, 1.0) && p(x, y); 33 | exhale own(x.f, y, 1.0) && p(x, y); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/ci/back-end/iterated_sep_star_encoding.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./iterated_sep_star_encoding.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/nat_ra_fpu.rav: -------------------------------------------------------------------------------- 1 | module Main { 2 | ghost field f : Library.Nat 3 | 4 | proc test(x: Ref, k: Library.Nat) 5 | requires own(x.f, k) 6 | requires k > 0 7 | { 8 | fpu(x, f, k+1); 9 | fpu(x, f, k-1); 10 | } 11 | } -------------------------------------------------------------------------------- /test/ci/back-end/nat_ra_fpu.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./nat_ra_fpu.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/nested_invariants.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | inv inv1(x: Ref) { 4 | inv2(x) 5 | } 6 | 7 | inv inv2(x: Ref) { 8 | inv3(x) 9 | } 10 | 11 | inv inv3(x: Ref) { 12 | exists v: Int :: own(x.f, v, 1.0) 13 | } 14 | 15 | proc p(x: Ref) 16 | requires inv1(x) 17 | { 18 | unfold inv1(x); 19 | unfold inv2(x); 20 | unfold inv3(x); 21 | 22 | x.f := 2; 23 | 24 | fold inv3(x); 25 | fold inv2(x); 26 | fold inv1(x); 27 | } -------------------------------------------------------------------------------- /test/ci/back-end/nested_invariants.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./nested_invariants.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/pred_vs_inv.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Int, y: Int) { 2 | true 3 | } 4 | 5 | inv i1(x: Int, y: Int) { 6 | true 7 | } 8 | 9 | proc pr1() { 10 | inhale p1(1, 2); 11 | exhale p1(1, 2); 12 | // exhale p1(1, 2); 13 | 14 | inhale i1(1, 2); 15 | exhale i1(1, 2); 16 | exhale i1(1, 2); 17 | } -------------------------------------------------------------------------------- /test/ci/back-end/pred_vs_inv.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh pred_vs_inv.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/witness_comp.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | pred pred1(x:Ref, v:Int) { 4 | true 5 | } 6 | 7 | proc p() { 8 | var x: Ref; 9 | inhale exists v: Int :: own(x.c, v, 1.0) && pred1(x, v); 10 | exhale exists v: Int :: own(x.c, v, 1.0) && pred1(x, v); 11 | 12 | // After witness computation, the above exhale gets replaced by: 13 | // assume $skolem_expr_placeholder$v = c$Heap[x].frac_proj1; 14 | // exhale 15 | // own(x.c, $skolem_expr_placeholder$v, 1.0) && 16 | // pred1(x, $skolem_expr_placeholder$v); 17 | } -------------------------------------------------------------------------------- /test/ci/back-end/witness_comp.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh witness_comp.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/witness_comp2.rav: -------------------------------------------------------------------------------- 1 | field nxt: Ref 2 | 3 | proc p() { 4 | var x: Ref; var y: Ref; var z: Ref; 5 | 6 | inhale own(x.nxt, y) && own(y.nxt, z); 7 | 8 | exhale exists q: Ref :: (exists r: Ref :: (own(x.nxt, q) && own(q.nxt, r))); 9 | } -------------------------------------------------------------------------------- /test/ci/back-end/witness_comp2.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh witness_comp2.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/back-end/witness_placeholders.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | func g(a: Int, b: Int) returns (r: Bool) { true } 4 | 5 | proc p() { 6 | var x: Ref; 7 | 8 | inhale own(x.f, 5, 1.0); 9 | exhale exists a: Int :: true ==> own(x.f, a, 1.0); 10 | } -------------------------------------------------------------------------------- /test/ci/back-end/witness_placeholders.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh witness_placeholders.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/adt.rav: -------------------------------------------------------------------------------- 1 | module Pair[T1: Library.Type, T2: Library.Type] : Library.Type { 2 | rep type T = data { 3 | case pair(fst: T1, snd: T2) 4 | } 5 | } 6 | 7 | module Test { 8 | module IntT: Library.Type { 9 | rep type T = Int 10 | } 11 | 12 | module BoolT: Library.Type { 13 | rep type T = Bool 14 | } 15 | 16 | module P = Pair[IntT, BoolT] 17 | 18 | val q: P = P.pair(1, true) 19 | 20 | module P2 = Pair[BoolT, P] 21 | 22 | val p: P2 = P2.pair(true, P.pair(1, true)) 23 | 24 | val x: Bool = p.P2.fst 25 | } 26 | -------------------------------------------------------------------------------- /test/ci/front-end/adt.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh adt.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/atomicity_check_ghost_fields_vars.rav: -------------------------------------------------------------------------------- 1 | field f1: Int 2 | ghost field g1: Int 3 | 4 | inv inv1() { true } 5 | 6 | proc p1(x: Ref) 7 | requires inv1() 8 | requires exists nn:Int :: own(x.f1, nn, 1.0) 9 | requires exists nn:Int :: own(x.g1, nn, 1.0) 10 | { 11 | unfold inv1(); 12 | ghost var gv0: Int := 0; 13 | 14 | // This field read is the concrete atomic step 15 | var f: Int := x.f1; 16 | 17 | // The following commands are all allowed before folding the invariant, 18 | // since they are all writes to ghost variables or ghost fields. 19 | x.g1 := 4; 20 | ghost var gv1: Int := 0; 21 | gv0 := 1; 22 | {! x.g1 := 4; gv1 := 2; !} 23 | 24 | fold inv1(); 25 | } -------------------------------------------------------------------------------- /test/ci/front-end/atomics/atomicity_check_ghost_fields_vars.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./atomicity_check_ghost_fields_vars.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/atomics.t: -------------------------------------------------------------------------------- 1 | Atomic Commands Test 2 | 3 | $ dune exec -- raven --shh ./test1.rav 4 | Verification successful. 5 | 6 | $ dune exec -- raven --shh ./test2.rav 7 | Verification successful. 8 | 9 | 10 | $ dune exec -- raven --shh ./test3.rav 11 | Verification successful. 12 | 13 | $ dune exec -- raven --shh ./test4.rav 14 | [Error] File "./test4.rav", line 14, columns 2-17: 15 | 14 | unfold p2(1+1); 16 | ^^^^^^^^^^^^^^^ 17 | Verification Error: Cannot open invariant p2. Invariant already opened or not in mask. 18 | [1] 19 | 20 | $ dune exec -- raven --shh ./fail/fail1.rav 21 | [Error] File "./fail/fail1.rav", line 23, columns 1-1: 22 | 23 | } 23 | ^ 24 | Verification Error: The atomic specification may not have been committed before reaching this return point. 25 | [1] 26 | 27 | $ dune exec -- raven --shh ./fail/fail2.rav 28 | [Error] File "./fail/fail2.rav", line 22, columns 2-14: 29 | 22 | return x1+2; 30 | ^^^^^^^^^^^^ 31 | Verification Error: The atomic specification may not have been committed before reaching this return point. 32 | [1] 33 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/fail/fail1.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Ref) { 2 | true 3 | } 4 | 5 | proc p(x: Ref) 6 | atomic requires p1(x) 7 | atomic ensures p1(x) 8 | { 9 | ghost var phi: AtomicToken
; 10 | phi := bindAU(); 11 | openAU(phi); 12 | var m: Int := 5; 13 | ghost var n: Int := 6; 14 | {! 15 | ghost var k: Bool; 16 | if (k) { 17 | abortAU(phi); 18 | } else { 19 | commitAU(phi); 20 | } 21 | !} 22 | // commitAU(phi); 23 | } -------------------------------------------------------------------------------- /test/ci/front-end/atomics/fail/fail2.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Int) { 2 | x % 2 == 0 3 | } 4 | 5 | proc p(implicit ghost x: Int) 6 | returns (ghost y: Int) 7 | atomic requires p1(x) 8 | atomic ensures p1(y) 9 | { 10 | ghost var phi: AtomicToken
:= bindAU(); 11 | 12 | ghost var x0: Int := openAU(phi); 13 | 14 | var m: Int := 5; 15 | abortAU(phi); 16 | 17 | ghost var x1: Int := openAU(phi); 18 | unfold p1(x1); 19 | fold p1(x1 + 4); 20 | commitAU(phi, x1 + 4); 21 | // y := x1 + 4; 22 | return x1+2; 23 | 24 | } -------------------------------------------------------------------------------- /test/ci/front-end/atomics/invariant_alloc.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | inv counterInv(x: Ref) { 4 | exists v: Int :: own(x.c, v, 1.0) 5 | } 6 | 7 | proc make() 8 | returns (x: Ref) 9 | ensures counterInv(x) 10 | { 11 | x := new(c: 0); 12 | fold counterInv(x); 13 | } 14 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/invariant_alloc.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./invariant_alloc.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/invariant_alloc_fail.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | inv counterInv(x: Ref) { 4 | exists v: Int :: own(x.c, v, 1.0) 5 | } 6 | 7 | proc make() 8 | returns (x: Ref) 9 | // ensures counterInv(x) 10 | { 11 | x := new(c: 0); 12 | fold counterInv(x); 13 | } 14 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/invariant_alloc_fail.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./invariant_alloc_fail.rav 2 | [Error] File "./invariant_alloc_fail.rav", line 12, columns 2-21: 3 | 12 | fold counterInv(x); 4 | ^^^^^^^^^^^^^^^^^^^ 5 | Error: Invariant not already opened; cannot be closed. Invariant not in mask; cannot be allocated.. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/front-end/atomics/test1.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Ref) { 2 | true 3 | } 4 | 5 | proc p(x: Ref) 6 | atomic requires p1(x) 7 | atomic ensures p1(x) 8 | { 9 | ghost var phi: AtomicToken
; 10 | phi := bindAU(); 11 | openAU(phi); 12 | commitAU(phi); 13 | } -------------------------------------------------------------------------------- /test/ci/front-end/atomics/test2.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Int) { 2 | x % 2 == 0 3 | } 4 | 5 | proc p(implicit ghost x: Int) 6 | atomic requires p1(x) 7 | atomic ensures p1(x+2) 8 | { 9 | ghost var phi: AtomicToken
:= bindAU(); 10 | 11 | ghost var x0: Int := openAU(phi); 12 | 13 | var m: Int := 5; 14 | abortAU(phi); 15 | 16 | ghost var x1: Int := openAU(phi); 17 | unfold p1(x1); 18 | fold p1(x1 + 2); 19 | commitAU(phi); 20 | } -------------------------------------------------------------------------------- /test/ci/front-end/atomics/test3.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Int) { 2 | x % 2 == 0 3 | } 4 | 5 | inv p2(x: Int) { 6 | x % 2 == 0 7 | } 8 | 9 | proc p(implicit ghost x: Int) 10 | returns (ghost y: Int) 11 | atomic requires p1(x) 12 | atomic requires p2(x) 13 | atomic ensures p1(y) 14 | { 15 | ghost var phi: AtomicToken
:= bindAU(); 16 | 17 | ghost var x0: Int := openAU(phi); 18 | 19 | var m: Int := 5; 20 | abortAU(phi); 21 | 22 | 23 | ghost var x1: Int := openAU(phi); 24 | unfold p1(x1); 25 | unfold p2(x1); 26 | fold p1(x1); 27 | commitAU(phi, x1); 28 | y := x1; 29 | fold p2(x1); 30 | // return x1+4; 31 | 32 | } -------------------------------------------------------------------------------- /test/ci/front-end/atomics/test4.rav: -------------------------------------------------------------------------------- 1 | pred p1(x: Int) { 2 | x % 2 == 0 3 | } 4 | 5 | inv p2(x: Int) { 6 | x % 2 == 0 7 | } 8 | 9 | proc p(implicit ghost x: Int) 10 | returns (y: Int) 11 | requires p2(2) 12 | { 13 | unfold p2(2); 14 | unfold p2(1+1); 15 | fold p2(2); 16 | fold p2(1+1); 17 | } -------------------------------------------------------------------------------- /test/ci/front-end/binders_typing.rav: -------------------------------------------------------------------------------- 1 | func t() returns (ret:Bool) { 2 | (forall x: Int :: true) && true 3 | } -------------------------------------------------------------------------------- /test/ci/front-end/binders_typing.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./binders_typing.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/bool_perm_ite.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | proc p(x: Ref) { 4 | inhale !true ? true : own(x.f, 1, 1.0); 5 | exhale true ? own(x.f, 1, 1.0) : true; 6 | } -------------------------------------------------------------------------------- /test/ci/front-end/bool_perm_ite.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./bool_perm_ite.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/bool_perm_typecheck.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | proc p() 4 | 5 | { 6 | var x: Ref; 7 | var b: Bool; 8 | inhale own(x.f, 1, 1.0) && b ? true : false; 9 | } -------------------------------------------------------------------------------- /test/ci/front-end/bool_perm_typecheck.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./bool_perm_typecheck.rav 2 | [Error] File "./bool_perm_typecheck.rav", line 8, columns 9-30: 3 | 8 | inhale own(x.f, 1, 1.0) && b ? true : false; 4 | ^^^^^^^^^^^^^^^^^^^^^ 5 | Type Error: Expected an expression of type 6 | Bool 7 | but found an expression of type 8 | Perm. 9 | [1] 10 | -------------------------------------------------------------------------------- /test/ci/front-end/cas_rewriter_test.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | func g(x: Ref) 4 | returns (y: Ref) 5 | { x } 6 | 7 | inv my_inv(x: Ref) { 8 | true 9 | } 10 | 11 | proc p(x: Ref) 12 | requires my_inv(x) 13 | requires own(x.f, 1, 1.0) 14 | { 15 | unfold my_inv(x); 16 | ghost var b : Bool := cas(x.f, 0, 5); 17 | // var b: Int := g(x).f; 18 | // var b1: Int := x.f; 19 | fold my_inv(x); 20 | assert (b == false); 21 | } 22 | -------------------------------------------------------------------------------- /test/ci/front-end/cas_rewriter_test.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./cas_rewriter_test.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/custom_fields_data_type.rav: -------------------------------------------------------------------------------- 1 | module IntSetRA = Library.SetRA[Library.IntType] 2 | 3 | type T = Int 4 | 5 | field c: T 6 | field d: IntSetRA 7 | 8 | type Something = data { case onething(a: Int); case nothing } 9 | 10 | field e: Something 11 | 12 | pred counter(x: Ref; v: Int) { 13 | own(x.c, 0, 1.0) && own(x.d, IntSetRA.set_constr({|v|})) && own(x.e, onething(v), 1.0) 14 | } 15 | 16 | proc incr(x: Ref) 17 | requires counter(x, 0) 18 | ensures counter(x, 0) 19 | { 20 | unfold counter(x, 0); 21 | fold counter(x, 0); 22 | var v: Something := onething(5); 23 | } -------------------------------------------------------------------------------- /test/ci/front-end/custom_fields_data_type.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./custom_fields_data_type.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/data_type.rav: -------------------------------------------------------------------------------- 1 | type T1 = data { 2 | case nil; 3 | case cons(elem: Int, tl: T1) 4 | } 5 | 6 | proc p1() { 7 | var x: T1; 8 | x := nil(); 9 | 10 | assert(x == nil()); 11 | } -------------------------------------------------------------------------------- /test/ci/front-end/data_type.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./data_type.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/data_type_inherit.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | type T = data { 3 | case x; 4 | case y 5 | } 6 | 7 | func is_x(t: T) returns (ret:Bool) { 8 | t == x() 9 | } 10 | 11 | } 12 | 13 | module N : M { 14 | 15 | } -------------------------------------------------------------------------------- /test/ci/front-end/data_type_inherit.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./data_type_inherit.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/datatype_test.rav: -------------------------------------------------------------------------------- 1 | module N1 : Library.Type { 2 | rep type T = Int 3 | } 4 | 5 | module N2 : Library.Type { 6 | rep type T = Int 7 | } 8 | 9 | module M { 10 | module M1 = Library.Frac[N1] 11 | module M2 = Library.Frac[N2] 12 | 13 | val x : Int = 3 14 | val y : M2.T = M2.frac_chunk(x, 0.75) 15 | 16 | proc p() { 17 | var y : M2.T := M2.frac_chunk(x, 0.75); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/ci/front-end/datatype_test.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./datatype_test.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/ci/front-end/exhale_existential_qual_pred_elim.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | pred p(x: Ref; v: Int) { 4 | own(x.f, v, 1.0) 5 | // true 6 | } 7 | 8 | 9 | proc p1() { 10 | var x: Ref; 11 | var v1: Int := 1; 12 | var v2: Int := 2; 13 | 14 | inhale p(x, v1); 15 | exhale exists v: Int :: p(x, v); 16 | } -------------------------------------------------------------------------------- /test/ci/front-end/exhale_existential_qual_pred_elim.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./exhale_existential_qual_pred_elim.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/fail/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/ci/front-end/fail/tuple.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | 3 | proc p() { 4 | var x: (Int, Bool) := (1, true); 5 | var y: Int := x#0; 6 | var z: Bool := x#1; 7 | var zz: Int := x#2; 8 | } 9 | 10 | 11 | } -------------------------------------------------------------------------------- /test/ci/front-end/fail/tuple.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./tuple.rav 2 | [Error] File "./tuple.rav", line 7, columns 20-22: 3 | 7 | var zz: Int := x#2; 4 | ^^ 5 | Type Error: Index out of bounds. 6 | [1] 7 | -------------------------------------------------------------------------------- /test/ci/front-end/fail/tuple_typing.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh tuple_typing1.rav 2 | [Error] File "tuple_typing1.rav", line 4, columns 7-16: 3 | 4 | x := (1, 2, 3); 4 | ^^^^^^^^^ 5 | Type Error: Expected tuple with 2 components. 6 | [1] 7 | 8 | $ dune exec -- raven --shh tuple_typing2.rav 9 | [Error] File "tuple_typing2.rav", line 4, columns 11-15: 10 | 4 | x := (1, true); 11 | ^^^^ 12 | Type Error: Expected an expression of type 13 | Int 14 | but found an expression of type 15 | Bool. 16 | [1] 17 | 18 | $ dune exec -- raven --shh tuple_typing3.rav 19 | [Error] File "tuple_typing3.rav", line 4, columns 18-20: 20 | 4 | var y: Bool := x#0; 21 | ^^ 22 | Type Error: Expected an expression of type 23 | Bool 24 | but found an expression of type 25 | Int. 26 | [1] 27 | -------------------------------------------------------------------------------- /test/ci/front-end/fail/tuple_typing1.rav: -------------------------------------------------------------------------------- 1 | proc p() { 2 | var x: (Int, Int); 3 | x := (1, 2); 4 | x := (1, 2, 3); 5 | } -------------------------------------------------------------------------------- /test/ci/front-end/fail/tuple_typing2.rav: -------------------------------------------------------------------------------- 1 | proc p() { 2 | var x: (Int, Int); 3 | x := (1, 2); 4 | x := (1, true); 5 | } -------------------------------------------------------------------------------- /test/ci/front-end/fail/tuple_typing3.rav: -------------------------------------------------------------------------------- 1 | proc p() { 2 | var x: (Int, Int); 3 | x := (1, 2); 4 | var y: Bool := x#0; 5 | } -------------------------------------------------------------------------------- /test/ci/front-end/field_type_test.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | module NatType : Library.Type { 3 | rep type T = Int 4 | } 5 | 6 | module N = Library.Frac[NatType] 7 | 8 | field f : N 9 | field g : Int 10 | } -------------------------------------------------------------------------------- /test/ci/front-end/field_type_test.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./field_type_test.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/field_typing.rav: -------------------------------------------------------------------------------- 1 | module M1 { 2 | field f: Bool 3 | } 4 | 5 | module M2 { 6 | pred foo(x: Ref) { 7 | own(x.M1.f, true, 1.0) 8 | } 9 | } -------------------------------------------------------------------------------- /test/ci/front-end/field_typing.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./field_typing.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/inlined_fold_witness.rav: -------------------------------------------------------------------------------- 1 | pred p(i1: Int, i2: Int, b: Bool) { 2 | true 3 | } 4 | 5 | pred q(i1: Int) { 6 | exists i2: Int, b: Bool :: p(i1, i2, b) 7 | } 8 | 9 | proc pr() { 10 | inhale p(5, 2, true); 11 | fold q(5)[i2 := 2, b := true]; 12 | } -------------------------------------------------------------------------------- /test/ci/front-end/inlined_fold_witness.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./inlined_fold_witness.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/inlined_unfold_bind.rav: -------------------------------------------------------------------------------- 1 | pred p(i1: Int, i2: Int, b: Bool) { 2 | true 3 | } 4 | 5 | pred q(i1: Int) { 6 | exists i2: Int, b: Bool :: p(i1, i2, b) 7 | } 8 | 9 | proc pr() { 10 | inhale q(5); 11 | 12 | ghost var i2: Int; ghost var b_sk: Bool; 13 | unfold q(5)[ 14 | i2 := i2, 15 | b_sk := b 16 | ]; 17 | } -------------------------------------------------------------------------------- /test/ci/front-end/inlined_unfold_bind.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./inlined_unfold_bind.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/inst_mod_frac_field.rav: -------------------------------------------------------------------------------- 1 | interface A[Tp: Library.Type] { 2 | field f: Tp.T 3 | } 4 | 5 | interface M { 6 | module RefType : Library.Type { 7 | rep type T = Ref 8 | } 9 | 10 | interface AN = A[RefType] 11 | 12 | proc p(x: Ref) { 13 | inhale own(x.AN.f, x, 1.0); 14 | } 15 | 16 | /* 17 | There used to be a bug in the `rewrite_own_expr_4_arg` rewriter which 18 | translates 4-arg own chunks into uniform 3-arg own chunks. 19 | 20 | The name for the Frac module generated to rewrite the inhale expression is: 21 | $Program.M.AN.Frac$Fld-Ref-.T 22 | 23 | The name that is actually generated during the `rewrite_frac_field_types` rewrite is: 24 | $Program.A.Frac$Fld-$Program_A_Tp_T-.T 25 | */ 26 | 27 | 28 | /* 29 | This bug was fixed in the following commit: 30 | b0f5e2d7a172fe321c677dcbad14eb340563097b 31 | 32 | Earlier, `rewrite_frac_field_types` was using field types to generate frac module name. Switched to using field_name. 33 | */ 34 | } -------------------------------------------------------------------------------- /test/ci/front-end/inst_mod_frac_field.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./inst_mod_frac_field.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/loop-rewriter_test.rav: -------------------------------------------------------------------------------- 1 | proc p1() { 2 | var x: Int := 4; 3 | var y: Int := 5; 4 | var z: Int := 1; 5 | 6 | while(x < 10) 7 | invariant (x <= y + z) 8 | { 9 | x := y + z; 10 | } 11 | } 12 | 13 | 14 | 15 | module M { 16 | var xx: Int = 5; 17 | 18 | proc p2() { 19 | var x: Int := 4; 20 | var y: Int := 5; 21 | var z: Int := 10; 22 | 23 | 24 | while(x < 10) 25 | invariant (x <= y + z) 26 | { 27 | x := y + z; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/ci/front-end/loop-rewriter_test.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./loop-rewriter_test.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/loop_inv_vars.rav: -------------------------------------------------------------------------------- 1 | proc foo(x: Int) 2 | { 3 | var i: Int := 0; 4 | 5 | while (i < 10) 6 | invariant 0 <= i <= 10 7 | invariant x == x 8 | { 9 | i := i + 1; 10 | } 11 | } -------------------------------------------------------------------------------- /test/ci/front-end/loop_inv_vars.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./loop_inv_vars.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/map_compr.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | val y: Bool = true 4 | 5 | proc p() { 6 | 7 | var m: Map[Int, Int] := {| y:Int :: (exists a: Int :: (y == 2*a)) ? y/2 : y |}; 8 | var x: Int := m[5]; 9 | assert x == 5; 10 | } 11 | -------------------------------------------------------------------------------- /test/ci/front-end/map_compr.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./map_compr.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/map_empty_set.rav: -------------------------------------------------------------------------------- 1 | proc p() { 2 | var x: Map[Int, Set[Int]] := {| k:Int :: {||} |}; 3 | 4 | var y: Set[Int] := {| k:Int :: k > 5 |}; 5 | } -------------------------------------------------------------------------------- /test/ci/front-end/map_empty_set.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./map_empty_set.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/merge_inherited_members.rav: -------------------------------------------------------------------------------- 1 | interface K { } 2 | 3 | module P[K: K] { } 4 | 5 | interface M { 6 | module K1: K 7 | module S = P[K1] 8 | } 9 | 10 | module N[K2: K] : M { 11 | module K1: K = K2 12 | } 13 | -------------------------------------------------------------------------------- /test/ci/front-end/merge_inherited_members.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./merge_inherited_members.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/own_expr_rewriter_test.rav: -------------------------------------------------------------------------------- 1 | interface MyType { 2 | rep type T; 3 | 4 | } 5 | 6 | module MyIntMod : Library.Type { 7 | rep type T = Int; 8 | 9 | } 10 | 11 | 12 | module M { 13 | 14 | 15 | field f: Int; 16 | 17 | proc p1(x: Ref, v: Int) 18 | requires own(x.f, v, 1.0) 19 | ensures own(x.f, v, 1.0) 20 | { 21 | 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /test/ci/front-end/own_expr_rewriter_test.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./own_expr_rewriter_test.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/parametric_frac.rav: -------------------------------------------------------------------------------- 1 | module M[N: Library.Type] { 2 | field f: N 3 | 4 | proc p1(x: Ref, v: N) 5 | returns (m: N, l: Int) 6 | requires own(x.f, v, 1.0) 7 | ensures own(x.f, v, 1.0) 8 | 9 | { 10 | var y: Int := 5; 11 | var z: Set[Int] := {| k:Int :: k % 2 == 0 |}; 12 | var a: Map[Int, Int] := {| k: Int :: k%2 |}; 13 | 14 | return v, 5; 15 | } 16 | } -------------------------------------------------------------------------------- /test/ci/front-end/parametric_frac.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./parametric_frac.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/predicates.rav: -------------------------------------------------------------------------------- 1 | field f: Int 2 | 3 | pred p(x: Ref; v: Int) { 4 | own(x.f, v, 1.0) 5 | } 6 | 7 | pred q() { 8 | true 9 | } 10 | 11 | proc p1() { 12 | var x: Ref; 13 | var v1: Int := 1; 14 | var v2: Int := 2; 15 | 16 | inhale p(x, v1); 17 | inhale p(x, v2); 18 | inhale q(); 19 | 20 | assert false; 21 | } -------------------------------------------------------------------------------- /test/ci/front-end/predicates.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./predicates.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/simple.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | proc p() { 3 | var x: Int; 4 | } 5 | } 6 | 7 | proc q(x: Int) 8 | requires x == 5 9 | ensures x == 5 10 | { 11 | x := 3; 12 | var y: Int; 13 | } -------------------------------------------------------------------------------- /test/ci/front-end/simple.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./simple.rav 2 | [Error] File "./simple.rav", line 13, columns 1-1: 3 | 13 | } 4 | ^ 5 | Verification Error: A postcondition may not hold at this return point. 6 | [Error] File "./simple.rav", line 9, columns 10-16: 7 | 9 | ensures x == 5 8 | ^^^^^^ 9 | Related Location: This assertion may not hold. 10 | [1] 11 | -------------------------------------------------------------------------------- /test/ci/front-end/tuple.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | 3 | proc p() { 4 | var x: (Int, Bool) := (1, true); 5 | var y: Int := x#0; 6 | var z: Bool := x#1; 7 | } 8 | } -------------------------------------------------------------------------------- /test/ci/front-end/tuple.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./tuple.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/type_alias_1.rav: -------------------------------------------------------------------------------- 1 | type T = Int 2 | 3 | proc p() { 4 | var x: T := 1; 5 | } -------------------------------------------------------------------------------- /test/ci/front-end/type_alias_1.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./type_alias_1.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/type_alias_2.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | type T = Int 3 | } 4 | 5 | module N { 6 | type T = Int 7 | } 8 | 9 | proc p() { 10 | var x: N.T; 11 | var y: M.T := x; 12 | } -------------------------------------------------------------------------------- /test/ci/front-end/type_alias_2.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./type_alias_2.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/ci/front-end/type_alias_3.rav: -------------------------------------------------------------------------------- 1 | module M { 2 | type T = Int 3 | 4 | field f: T 5 | 6 | proc p(x: T) { 7 | var y: Ref; 8 | y := new(f: 1); 9 | x := 1; 10 | } 11 | } -------------------------------------------------------------------------------- /test/ci/front-end/type_alias_3.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./type_alias_3.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/comparison/adt_buggy.rav: -------------------------------------------------------------------------------- 1 | interface List { 2 | rep type T 3 | func nil() returns (ret: T) 4 | func cons(head: Int, tail: T) returns (ret: T) 5 | 6 | func head_cons(xs: T) returns (ret: Int) 7 | func tail_cons(xs: T) returns (ret: T) 8 | 9 | func tp(xs: T) returns (ret: Int) 10 | func tp_nil() returns (ret: Int) 11 | func tp_cons() returns (ret: Int) 12 | 13 | auto axiom tp_unique() 14 | ensures tp_nil() != tp_cons() 15 | 16 | func is_nil(xs: T) returns (ret: Bool) 17 | func is_cons(xs: T) returns (ret: Bool) 18 | 19 | auto axiom destruct_over_construct_cons() 20 | ensures forall head: Int, tail: T :: 21 | head_cons(cons(head, tail)) == head && 22 | tail_cons(cons(head, tail)) == tail 23 | 24 | auto axiom construct_over_destruct_cons() 25 | ensures forall xs: T :: {head_cons(xs)} {tail_cons(xs)} is_cons(xs) ==> xs == cons(head_cons(xs), tail_cons(xs)) 26 | 27 | auto axiom type_of_nil() 28 | ensures tp(nil()) == tp_nil() 29 | 30 | auto axiom type_of_cons() 31 | ensures forall head: Int, tail: T :: tp(cons(head, tail)) == tp_cons() 32 | 33 | auto axiom type_existence() 34 | ensures forall xs: T :: 35 | tp(xs) == tp_nil() || tp(xs) == tp_cons() 36 | 37 | auto axiom type_is_nil() 38 | ensures forall xs: T :: 39 | (tp(xs) == tp_nil ==> is_nil(xs)) && 40 | (is_nil(xs) ==> tp(xs) == tp_nil) 41 | 42 | auto axiom type_isElem() 43 | ensures forall xs: T :: 44 | (tp(xs) == tp_cons() ==> is_cons(xs)) && 45 | (is_cons(xs) ==> tp(xs) == tp_cons()) 46 | } 47 | 48 | import List._ 49 | 50 | proc test_types(x: List) 51 | { 52 | assert is_nil(x) ==> !is_cons(x); 53 | assert !is_cons(x) ==> is_nil(x); 54 | } 55 | 56 | proc test_quantifiers() { 57 | assert forall head: Int, tail: List, xs: List :: 58 | is_cons(xs) ==> ( 59 | (head == head_cons(xs) && tail == tail_cons(xs) ==> 60 | cons(head, tail) == xs 61 | ) && 62 | 63 | (cons(head, tail) == xs ==> 64 | head == head_cons(xs) && tail == tail_cons(xs) 65 | ) 66 | ); 67 | } 68 | 69 | proc pattern_match_exhaustiveness(xs: List) { 70 | assert !is_nil(xs) 71 | && !(is_cons(xs) && is_nil(tail_cons(xs))) 72 | && !(is_cons(xs) && is_cons(tail_cons(xs))) 73 | ==> false; 74 | 75 | assert !is_nil(xs) 76 | && !(is_cons(xs) && is_nil(tail_cons(xs))) 77 | && !(is_cons(xs) && is_cons(tail_cons(xs)) 78 | && head_cons(xs) < head_cons(tail_cons(xs)) 79 | ) 80 | ==> false; 81 | } -------------------------------------------------------------------------------- /test/comparison/adt_correct.rav: -------------------------------------------------------------------------------- 1 | interface List { 2 | rep type T 3 | func nil() returns (ret: T) 4 | func cons(head: Int, tail: T) returns (ret: T) 5 | 6 | func head_cons(xs: T) returns (ret: Int) 7 | func tail_cons(xs: T) returns (ret: T) 8 | 9 | func tp(xs: T) returns (ret: Int) 10 | func tp_nil() returns (ret: Int) 11 | func tp_cons() returns (ret: Int) 12 | 13 | auto axiom tp_unique() 14 | ensures tp_nil() != tp_cons() 15 | 16 | func is_nil(xs: T) returns (ret: Bool) 17 | func is_cons(xs: T) returns (ret: Bool) 18 | 19 | auto axiom destruct_over_construct_cons() 20 | ensures forall head: Int, tail: T :: 21 | head_cons(cons(head, tail)) == head && 22 | tail_cons(cons(head, tail)) == tail 23 | 24 | auto axiom construct_over_destruct_cons() 25 | ensures forall xs: T :: {head_cons(xs)} {tail_cons(xs)} is_cons(xs) ==> xs == cons(head_cons(xs), tail_cons(xs)) 26 | 27 | auto axiom type_of_nil() 28 | ensures tp(nil()) == tp_nil() 29 | 30 | auto axiom type_of_cons() 31 | ensures forall head: Int, tail: T :: tp(cons(head, tail)) == tp_cons() 32 | 33 | auto axiom type_existence() 34 | ensures forall xs: T :: 35 | tp(xs) == tp_nil() || tp(xs) == tp_cons() 36 | 37 | auto axiom type_is_nil() 38 | ensures forall xs: T :: 39 | (tp(xs) == tp_nil ==> is_nil(xs)) && 40 | (is_nil(xs) ==> tp(xs) == tp_nil) 41 | 42 | auto axiom type_isElem() 43 | ensures forall xs: T :: 44 | (tp(xs) == tp_cons() ==> is_cons(xs)) && 45 | (is_cons(xs) ==> tp(xs) == tp_cons()) 46 | } 47 | 48 | import List._ 49 | 50 | proc test_types(x: List) 51 | { 52 | assert is_nil(x) ==> !is_cons(x); 53 | assert !is_cons(x) ==> is_nil(x); 54 | } 55 | 56 | proc test_quantifiers() { 57 | assert forall head: Int, tail: List, xs: List :: 58 | is_cons(xs) ==> ( 59 | (head == head_cons(xs) && tail == tail_cons(xs) ==> 60 | cons(head, tail) == xs 61 | ) && 62 | 63 | (cons(head, tail) == xs ==> 64 | head == head_cons(xs) && tail == tail_cons(xs) 65 | ) 66 | ); 67 | } 68 | 69 | proc pattern_match_exhaustiveness(xs: List) { 70 | assert !is_nil(xs) 71 | && !(is_cons(xs) && is_nil(tail_cons(xs))) 72 | && !(is_cons(xs) && is_cons(tail_cons(xs))) 73 | ==> false; 74 | 75 | // assert !is_nil(xs) 76 | // && !(is_cons(xs) && is_nil(tail_cons(xs))) 77 | // && !(is_cons(xs) && is_cons(tail_cons(xs)) 78 | // && head_cons(xs) < head_cons(tail_cons(xs)) 79 | // ) 80 | // ==> false; 81 | } -------------------------------------------------------------------------------- /test/comparison/arc.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./arc.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/comparison/arc_ra.rav: -------------------------------------------------------------------------------- 1 | module ArcRA : Library.ResourceAlgebra { 2 | rep type T = data { 3 | case noToken; 4 | case tokens(authCount: Int, authPerm: Real, fragCount: Int, fragPerm: Real); 5 | case identity; 6 | case top 7 | } 8 | 9 | val id: T = identity 10 | 11 | func comp(a: T, b: T) returns (ret: T) { 12 | a == id ? 13 | b : 14 | (b == id ? 15 | a : 16 | (valid(a) && valid(b) ? 17 | ( 18 | a == tokens(a.authCount, a.authPerm, a.fragCount, a.fragPerm) && 19 | b == tokens(b.authCount, b.authPerm, b.fragCount, b.fragPerm) && 20 | ((a.authCount == 0 && a.authPerm == 0.0) || (b.authCount == 0 && b.authPerm == 0.0)) && 21 | valid(tokens( 22 | a.authCount + b.authCount, 23 | a.authPerm + b.authPerm, 24 | a.fragCount + b.fragCount, 25 | a.fragPerm + b.fragPerm) 26 | ) ? 27 | tokens( 28 | a.authCount + b.authCount, 29 | a.authPerm + b.authPerm, 30 | a.fragCount + b.fragCount, 31 | a.fragPerm + b.fragPerm 32 | ) : 33 | (a == noToken && b == noToken ? 34 | noToken : 35 | top 36 | ) 37 | ) : 38 | top 39 | 40 | )) 41 | } 42 | 43 | func valid(a: T) returns (ret: Bool) { 44 | a == noToken || a == id || 45 | (a == tokens(a.authCount, a.authPerm, a.fragCount, a.fragPerm) && 46 | a.authCount >= 0 && 47 | a.authPerm >= 0.0 && a.authPerm <= 1.0 && 48 | a.fragCount >= 0 && 49 | a.fragPerm >= 0.0 && a.fragPerm <= 1.0 && 50 | ( 51 | (a.fragCount <= a.authCount && a.fragPerm <= a.authPerm) || 52 | (a.authCount == 0 && a.authPerm == 0.0) 53 | ) && 54 | ( 55 | (a.authCount > 0 && a.authPerm > 0.0) || 56 | (a.fragCount > 0 && a.fragPerm > 0.0) 57 | ) && 58 | (a.authCount > a.fragCount ==> a.authPerm > a.fragPerm) 59 | ) && 60 | (a.authCount == a.fragCount ==> a.authPerm == a.fragPerm) 61 | } 62 | 63 | func frame(a: T, b: T) returns (ret: T) { 64 | b == id ? 65 | a : 66 | (a == noToken && b == noToken ? 67 | noToken : 68 | (a == b ? 69 | id : 70 | (a == tokens(a.authCount, a.authPerm, a.fragCount, a.fragPerm) && 71 | b == tokens(b.authCount, b.authPerm, b.fragCount, b.fragPerm) && valid(a) && valid(b) && 72 | ((b.authCount == 0 && b.authPerm == 0.0) || (b.authCount == a.authCount && b.authPerm == a.authPerm)) && b.fragCount <= a.fragCount && b.fragPerm <= a.fragPerm ? 73 | tokens(a.authCount - b.authCount, a.authPerm - b.authPerm, a.fragCount - b.fragCount, a.fragPerm - b.fragPerm) : 74 | top 75 | ))) 76 | } 77 | 78 | func fpuAllowed(a: T, b: T) returns (ret: Bool) { 79 | a == b ? true : 80 | (valid(a) && valid(b) ? 81 | (a == noToken ? 82 | false : 83 | (a == tokens(a.authCount, a.authPerm, a.fragCount, a.fragPerm) && 84 | b == tokens(b.authCount, b.authPerm, b.fragCount, b.fragPerm) ? 85 | (a.authCount - a.fragCount == b.authCount - b.fragCount && 86 | a.authPerm - a.fragPerm == b.authPerm - b.fragPerm ) 87 | : 88 | (a == tokens(a.authCount, a.authPerm, a.fragCount, a.fragPerm) ? 89 | a.authCount == a.fragCount && a.authPerm == a.fragPerm : 90 | false) 91 | )) : 92 | false) 93 | } 94 | } -------------------------------------------------------------------------------- /test/comparison/arc_ra.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./arc_ra.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/comparison/bounded_counter.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | inv counterInv(x: Ref, max: Int) { 4 | exists v: Int :: own(x.c, v, 1.0) && 0 <= v <= max 5 | } 6 | 7 | proc incr(x: Ref, max: Int) 8 | returns (res: Int) 9 | requires counterInv(x, max) 10 | ensures 0 <= res <= max 11 | { 12 | var v: Int; 13 | 14 | unfold counterInv(x, max); 15 | v := x.c; 16 | fold counterInv(x, max); 17 | 18 | var new_v : Int := (v < max) ? v+1 : 0; 19 | var flag: Bool; 20 | 21 | unfold counterInv(x, max); 22 | flag := cas(x.c, v, new_v); 23 | fold counterInv(x, max); 24 | 25 | if (!flag) { 26 | res := incr(x, max); // retry 27 | } else { 28 | return v; 29 | } 30 | } 31 | 32 | proc read(x: Ref, max: Int) 33 | returns (v: Int) 34 | requires counterInv(x, max) 35 | { 36 | unfold counterInv(x, max); 37 | v := x.c; 38 | fold counterInv(x, max); 39 | 40 | return v; 41 | } 42 | 43 | proc create(max: Int) 44 | returns (x: Ref) 45 | requires 0 < max 46 | ensures counterInv(x, max) 47 | { 48 | x := new(c: 0); 49 | fold counterInv(x, max); 50 | } 51 | -------------------------------------------------------------------------------- /test/comparison/cas_counter.rav: -------------------------------------------------------------------------------- 1 | module CASCounter { 2 | import Library.Fraction 3 | 4 | // module instantiations 5 | module FracNat = Library.FracRA[Library.Nat] 6 | module CtrRA = Library.Auth[FracNat] 7 | 8 | // definitions 9 | field c: Int 10 | ghost field gc: CtrRA 11 | 12 | func frac_auth_auth(v: Int) returns (res: CtrRA) { 13 | CtrRA.auth(FracNat.frac_chunk(v, 1.0)) 14 | } 15 | 16 | func frac_auth_frag(q: Real, v: Int) returns (res: CtrRA) { 17 | CtrRA.frag(FracNat.frac_chunk(v, q)) 18 | } 19 | 20 | auto pred counter_contribution(l: Ref, q: Real, n: Int) { 21 | own(l.gc, frac_auth_frag(q, n)) 22 | } 23 | 24 | inv is_counter(l: Ref) { 25 | exists z: Int :: 26 | own(l.c, z) && (z >= 0) && own(l.gc, frac_auth_auth(z)) 27 | } 28 | 29 | // algorithms 30 | 31 | proc make_counter() 32 | returns (l: Ref) 33 | requires true 34 | ensures is_counter(l) && counter_contribution(l, 1.0, 0) 35 | { 36 | l := new(c: 0, gc: CtrRA.comp(frac_auth_auth(0), frac_auth_frag(1.0, 0))); 37 | fold is_counter(l); 38 | } 39 | 40 | proc read_full_spec(l: Ref, implicit ghost n: Int) 41 | returns (c: Int) 42 | requires is_counter(l) && counter_contribution(l, 1.0, n) 43 | ensures c == n && counter_contribution(l, 1.0, n) 44 | { 45 | unfold is_counter(l); 46 | c := l.c; 47 | fold is_counter(l); 48 | } 49 | 50 | proc read_partial_spec(l: Ref, implicit ghost q: Real, implicit ghost n: Int) 51 | returns (c: Int) 52 | requires is_counter(l) && counter_contribution(l, q, n) 53 | ensures n <= c && counter_contribution(l, q, n) 54 | { 55 | unfold is_counter(l); 56 | c := l.c; 57 | fold is_counter(l); 58 | } 59 | 60 | proc incr(l: Ref, implicit ghost q: Real, implicit ghost n: Int) 61 | requires is_counter(l) && counter_contribution(l, q, n) 62 | ensures counter_contribution(l, q, n+1) 63 | { 64 | unfold is_counter(l); 65 | var n1: Int := l.c; 66 | fold is_counter(l); 67 | 68 | unfold is_counter(l); 69 | var b: Bool := cas(l.c, n1, n1+1); 70 | 71 | if (b) { 72 | fpu(l.gc, 73 | CtrRA.comp(frac_auth_auth(n1), frac_auth_frag(q, n)), 74 | CtrRA.comp(frac_auth_auth(n1+1), frac_auth_frag(q, n+1)) 75 | ); 76 | 77 | fold is_counter(l); 78 | } else { 79 | fold is_counter(l); 80 | incr(l, q, n); 81 | } 82 | } 83 | 84 | 85 | } -------------------------------------------------------------------------------- /test/comparison/cas_counter_client.rav: -------------------------------------------------------------------------------- 1 | include "fork_join.rav" 2 | include "cas_counter.rav" 3 | 4 | module CASCounterClient { 5 | import CASCounter._ 6 | 7 | module ClientResource: ForkJoinResource { 8 | rep type T = (Ref, Int) 9 | 10 | module Result: Library.Type { 11 | rep type T = () 12 | } 13 | 14 | pred resource(r: T, v: Result) { 15 | counter_contribution(r#0, 0.5, r#1+1) 16 | } 17 | } 18 | 19 | module FJ = ForkJoin[ClientResource] 20 | 21 | // algorithms 22 | 23 | proc thread_incr(l: Ref, fj: Ref, n: Int) 24 | requires is_counter(l) && FJ.is_join(fj, (l, n)) 25 | requires counter_contribution(l, 0.5, n) 26 | ensures true 27 | { 28 | incr(l, 0.5, n); 29 | fold ClientResource.resource((l, n), ()); 30 | FJ.set(fj, (l, n), ()); 31 | } 32 | 33 | // adding exists fj: Ref, l: Ref :: FJ.is_join(fj, l) 34 | // to the postcondition because call to make_join 35 | // requires FJ.is_join() in the mask 36 | proc parallel_increment() 37 | returns (res: Int) 38 | requires true 39 | ensures exists fj1: Ref, l: Ref :: FJ.is_join(fj1, (l, 0)) && is_counter(l) 40 | ensures res == 2 41 | { 42 | var l: Ref := make_counter(); 43 | var fj1: Ref := FJ.make_join((l, 0)); 44 | spawn thread_incr(l, fj1, 0); 45 | var fj2: Ref := FJ.make_join((l, 0)); 46 | spawn thread_incr(l, fj2, 0); 47 | var n1 := FJ.wait(fj1, (l, 0)); 48 | var n2 := FJ.wait(fj2, (l, 0)); 49 | unfold ClientResource.resource((l,0), ()); 50 | unfold ClientResource.resource((l,0), ()); 51 | res := read_full_spec(l, 2); 52 | 53 | assert FJ.is_join(fj1, (l, 0)) && is_counter(l); 54 | } 55 | } -------------------------------------------------------------------------------- /test/comparison/dfrac_ra.rav: -------------------------------------------------------------------------------- 1 | module Dfrac[X: Library.Type] : Library.ResourceAlgebra { 2 | rep type T = data { 3 | case dfrac_null 4 | case dfrac_chunk(chunk_proj1: X, chunk_proj2: Real) 5 | case dfrac_disc(disc_proj1: X) 6 | case dfrac_both(both_proj1: X, both_proj2: Real) 7 | case dfrac_top 8 | } 9 | 10 | val id: T = dfrac_null 11 | 12 | func valid(n:T) 13 | returns (ret:Bool) 14 | { 15 | (n == dfrac_null) ? true : 16 | (n == dfrac_chunk(n.chunk_proj1, n.chunk_proj2) ? (n.chunk_proj2 > 0.0 && n.chunk_proj2 <= 1.0) : 17 | (n == dfrac_disc(n.disc_proj1) ? true : 18 | (n == dfrac_both(n.both_proj1, n.both_proj2) ? (n.both_proj2 > 0.0 && n.both_proj2 < 1.0) : 19 | (false)))) 20 | } 21 | 22 | func comp(a:T, b:T) returns (ret:T) { 23 | a == dfrac_null ? b : 24 | (b == dfrac_null ? a : 25 | (valid(a) && valid(b) ? 26 | (a == dfrac_chunk(a.chunk_proj1, a.chunk_proj2) && b == dfrac_chunk(b.chunk_proj1, b.chunk_proj2) && a.chunk_proj1 == b.chunk_proj1 && a.chunk_proj2 + b.chunk_proj2 <= 1.0 ? 27 | dfrac_chunk(a.chunk_proj1, a.chunk_proj2 + b.chunk_proj2) : 28 | (a == dfrac_chunk(a.chunk_proj1, a.chunk_proj2) && b == dfrac_disc(b.disc_proj1) && a.chunk_proj1 == b.disc_proj1 && a.chunk_proj2 < 1.0 ? 29 | dfrac_both(a.chunk_proj1, a.chunk_proj2) : 30 | (a == dfrac_chunk(a.chunk_proj1, a.chunk_proj2) && b == dfrac_both(b.both_proj1, b.both_proj2) && a.chunk_proj1 == b.both_proj1 && a.chunk_proj2 + b.both_proj2 < 1.0 ? 31 | dfrac_both(a.chunk_proj1, a.chunk_proj2 + b.both_proj2) : 32 | (a == dfrac_disc(a.disc_proj1) && b == dfrac_chunk(b.chunk_proj1, b.chunk_proj2) && a.disc_proj1 == b.chunk_proj1 && b.chunk_proj2 < 1.0 ? 33 | dfrac_both(a.disc_proj1, b.chunk_proj2) : 34 | (a == dfrac_disc(a.disc_proj1) && b == dfrac_disc(b.disc_proj1) && a.disc_proj1 == b.disc_proj1 ? 35 | dfrac_disc(a.disc_proj1) : 36 | (a == dfrac_disc(a.disc_proj1) && b == dfrac_both(b.both_proj1, b.both_proj2) && a.disc_proj1 == b.both_proj1 && b.both_proj2 < 1.0 ? 37 | dfrac_both(a.disc_proj1, b.both_proj2) : 38 | (a == dfrac_both(a.both_proj1, a.both_proj2) && b == dfrac_chunk(b.chunk_proj1, b.chunk_proj2) && a.both_proj1 == b.chunk_proj1 && a.both_proj2 + b.chunk_proj2 < 1.0 ? 39 | dfrac_both(a.both_proj1, a.both_proj2 + b.chunk_proj2) : 40 | (a == dfrac_both(a.both_proj1, a.both_proj2) && b == dfrac_disc(b.disc_proj1) && a.both_proj1 == b.disc_proj1 && a.both_proj2 < 1.0 ? 41 | dfrac_both(a.both_proj1, a.both_proj2) : 42 | (a == dfrac_both(a.both_proj1, a.both_proj2) && b == dfrac_both(b.both_proj1, b.both_proj2) && a.both_proj1 == b.both_proj1 && a.both_proj2 + b.both_proj2 < 1.0 ? 43 | dfrac_both(a.both_proj1, a.both_proj2 + b.both_proj2) : 44 | dfrac_top))))))))) : 45 | dfrac_top) 46 | ) 47 | } 48 | 49 | func frame(a:T, b:T) returns (ret:T) { 50 | b == dfrac_null ? a : 51 | (a == dfrac_chunk(a.chunk_proj1, a.chunk_proj2) && b == dfrac_chunk(b.chunk_proj1, b.chunk_proj2) && valid(a) && valid(b) && a.chunk_proj1 == b.chunk_proj1 && a.chunk_proj2 - b.chunk_proj2 >= 0.0 ? 52 | (a.chunk_proj2 == b.chunk_proj2 ? dfrac_null : dfrac_chunk(a.chunk_proj1, a.chunk_proj2 - b.chunk_proj2)) : 53 | (a == dfrac_disc(a.disc_proj1) && b == dfrac_disc(b.disc_proj1) && valid(a) && valid(b) && a.disc_proj1 == b.disc_proj1 ? 54 | dfrac_disc(a.disc_proj1) : 55 | (a == dfrac_both(a.both_proj1, a.both_proj2) && b == dfrac_chunk(b.chunk_proj1, b.chunk_proj2) && valid(a) && valid(b) && a.both_proj1 == b.chunk_proj1 && a.both_proj2 - b.chunk_proj2 >= 0.0 ? 56 | (a.both_proj2 == b.chunk_proj2 ? dfrac_disc(a.both_proj1) : dfrac_both(a.both_proj1, a.both_proj2 - b.chunk_proj2)) : 57 | (a == dfrac_both(a.both_proj1, a.both_proj2) && b == dfrac_disc(b.disc_proj1) && valid(a) && valid(b) && a.both_proj1 == b.disc_proj1 ? 58 | dfrac_both(a.both_proj1, a.both_proj2) : 59 | (a == dfrac_both(a.both_proj1, a.both_proj2) && b == dfrac_both(b.both_proj1, b.both_proj2) && valid(a) && valid(b) && a.both_proj1 == b.both_proj1 && a.both_proj2 - b.both_proj2 >= 0.0 ? 60 | (a.both_proj2 == b.both_proj2 ? dfrac_disc(a.both_proj1) : dfrac_both(a.both_proj1, a.both_proj2 - b.both_proj2)) : 61 | dfrac_top))))) 62 | } 63 | 64 | func fpuAllowed(a:T, b:T) returns (ret:Bool) { 65 | (a == dfrac_chunk(a.chunk_proj1, 1.0) && b == dfrac_chunk(b.chunk_proj1, 1.0) ? true : 66 | (a == dfrac_chunk(a.chunk_proj1, 1.0) && b == dfrac_disc(a.chunk_proj1) ? true : 67 | false)) 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /test/comparison/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/comparison/fork_join.rav: -------------------------------------------------------------------------------- 1 | interface ForkJoinResource : Library.Type { 2 | rep type T 3 | 4 | module Result: Library.Type 5 | 6 | // Resource returned by a forked thread 7 | pred resource(r: T, v: Result) 8 | } 9 | 10 | module ForkJoin[R: ForkJoinResource] { 11 | 12 | module Excl = Library.Excl[Library.UnitRA] 13 | module OptionResult = Library.Option[R.Result] 14 | 15 | import OptionResult._ 16 | 17 | field result: OptionResult 18 | ghost field excl: Excl 19 | 20 | inv is_join(l: Ref, r: R) { 21 | exists v: OptionResult, b: Bool :: 22 | own(l.result, v) 23 | && (v == some(v.value) ? 24 | (b ? own(l.excl, Excl.excl(())) : R.resource(r, v.value)) 25 | : true) 26 | } 27 | 28 | auto pred join_handle(l: Ref) { 29 | own(l.excl, Excl.excl(())) 30 | } 31 | 32 | // algorithms 33 | 34 | proc make_join(r: R) 35 | returns (l: Ref) 36 | requires true 37 | ensures is_join(l, r) && join_handle(l) 38 | { 39 | l := new(result: none, excl: Excl.excl(())); 40 | // passing b to suppress warning 41 | fold is_join(l, r)[b := true]; 42 | } 43 | 44 | proc set(l: Ref, r: R, v: R.Result) 45 | requires is_join(l, r) && R.resource(r, v) 46 | ensures true 47 | { 48 | unfold is_join(l, r); 49 | l.result := some(v); 50 | fold is_join(l, r)[b := false]; 51 | } 52 | 53 | proc wait(l: Ref, r: R) 54 | returns (v: R.Result) 55 | requires is_join(l, r) && join_handle(l) 56 | ensures R.resource(r, v) 57 | { 58 | ghost var b: Bool; 59 | unfold is_join(l, r)[b := b]; 60 | var w: R.Result := l.result; 61 | {! 62 | if (w == some(w.value)) { 63 | fold is_join(l, r)[b := true]; 64 | } else { 65 | fold is_join(l, r)[b := b]; 66 | } 67 | !} 68 | 69 | if (w == some(w.value)) { 70 | return w.value; 71 | } else { 72 | v := wait(l, r); 73 | return v; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/comparison/fork_join_client.rav: -------------------------------------------------------------------------------- 1 | include "fork_join.rav" 2 | 3 | module ForkJoinClient { 4 | 5 | field f: Int 6 | 7 | module ClientResource : ForkJoinResource { 8 | rep type T = Ref 9 | 10 | module Result: Library.Type { 11 | rep type T = () 12 | } 13 | 14 | pred resource(r: T, v: Result) { 15 | own(r.f, 1) 16 | } 17 | } 18 | 19 | module FJ = ForkJoin[ClientResource] 20 | 21 | // algorithms 22 | 23 | proc client_thread(l: Ref, fj: Ref, implicit ghost w: Int) 24 | requires FJ.is_join(fj, l) && own(l.f, w) 25 | ensures true 26 | { 27 | l.f := 1; 28 | fold ClientResource.resource(l, ()); 29 | FJ.set(fj, l, ()); 30 | } 31 | 32 | // adding exists fj: Ref, l: Ref :: FJ.is_join(fj, l) 33 | // to the postcondition because call to make_join 34 | // requires FJ.is_join() in the mask 35 | proc client() 36 | returns (res: Int) 37 | requires true 38 | ensures exists fj: Ref, l: Ref :: FJ.is_join(fj, l) 39 | ensures res == 1 40 | { 41 | var l: Ref; 42 | l := new(f: 0); 43 | var fj: Ref := FJ.make_join(l); 44 | spawn client_thread(l, fj); 45 | var n := FJ.wait(fj, l); 46 | unfold ClientResource.resource(l, ()); 47 | res := l.f; 48 | 49 | // assert to supply witness for the 50 | // existential in the post-condition 51 | assert FJ.is_join(fj, l); 52 | } 53 | } -------------------------------------------------------------------------------- /test/comparison/inc_dec.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | auto pred counter(x: Ref; v: Int) { 4 | own(x.c, v, 1.0) 5 | } 6 | 7 | proc incr(x: Ref, k: Int, implicit ghost v: Int) 8 | atomic requires counter(x, v) 9 | atomic ensures counter(x, v + k) 10 | { 11 | ghost var phi := bindAU(); 12 | 13 | ghost var v0: Int := openAU(phi); 14 | var v1: Int := x.c; 15 | abortAU(phi); 16 | var new_v1 : Int := v1 + k; 17 | 18 | ghost var v2: Int := openAU(phi); 19 | 20 | var res: Bool := cas(x.c, v1, new_v1); 21 | 22 | if (res) { 23 | commitAU(phi); 24 | } else { 25 | abortAU(phi); 26 | ghost var v3: Int := openAU(phi); 27 | incr(x, k); 28 | commitAU(phi); 29 | } 30 | } 31 | 32 | proc decr(x: Ref, k: Int, implicit ghost v: Int) 33 | atomic requires counter(x, v) 34 | atomic ensures counter(x, v - k) 35 | { 36 | ghost var phi := bindAU(); 37 | 38 | ghost var v0: Int := openAU(phi); 39 | var v1: Int := x.c; 40 | abortAU(phi); 41 | var new_v1 : Int := v1 - k; 42 | 43 | ghost var v2: Int := openAU(phi); 44 | 45 | var res: Bool := cas(x.c, v1, new_v1); 46 | 47 | if (res) { 48 | commitAU(phi); 49 | } else { 50 | abortAU(phi); 51 | ghost var v3: Int := openAU(phi); 52 | decr(x, k); 53 | commitAU(phi); 54 | } 55 | } 56 | 57 | proc read(x: Ref, implicit ghost v: Int) 58 | returns (v2: Int) 59 | atomic requires counter(x, v) 60 | atomic ensures counter(x, v) && v2 == v 61 | { 62 | ghost var phi := bindAU(); 63 | 64 | ghost var v0: Int := openAU(phi); 65 | var v1: Int := x.c; 66 | commitAU(phi, v1); 67 | 68 | return v1; 69 | } 70 | -------------------------------------------------------------------------------- /test/comparison/lock_invariant.rav: -------------------------------------------------------------------------------- 1 | interface LockResource : Library.Type { 2 | rep type T 3 | 4 | // Resource protected by a lock 5 | pred resource(r: T) 6 | 7 | // axiom exclusive(r: T) 8 | // requires resource(r) && resource(r) 9 | // ensures false 10 | } 11 | 12 | 13 | interface Lock[R: LockResource] { 14 | import R.resource 15 | 16 | module Agree = Library.Agree[R] 17 | 18 | ghost field agr: Agree 19 | 20 | 21 | // Lock representation invariant 22 | pred lock_rep(l: Ref; b: Bool) 23 | 24 | // Abstract predicate describing a lock 25 | inv lock_inv(l: Ref; r: R) { 26 | exists b: Bool :: 27 | lock_rep(l, b) 28 | && own(l.agr, Agree.agree(r)) 29 | && (b ? true : locked(l) && resource(r)) 30 | } 31 | 32 | pred locked(l: Ref) 33 | 34 | lemma lk_exclusive(l: Ref) 35 | requires locked(l) && locked(l) 36 | ensures false 37 | 38 | // lemma exclusive(l: Ref, r: R) 39 | // requires lock_inv(l, r, false) && locked(l) 40 | // ensures false 41 | // { 42 | // unfold is_lock(l, r, false); 43 | // lk_exclusive(); 44 | // } 45 | 46 | proc create(r: R) 47 | returns (l: Ref) 48 | requires resource(r) 49 | ensures lock_inv(l, r) 50 | 51 | proc acquire(l: Ref, implicit ghost r: R) 52 | atomic requires lock_inv(l, r) 53 | atomic ensures lock_inv(l, r) && locked(l) && resource(r) 54 | 55 | proc release(l: Ref, implicit ghost r: R) 56 | atomic requires lock_inv(l, r) && locked(l) && resource(r) 57 | atomic ensures lock_inv(l, r) 58 | } 59 | -------------------------------------------------------------------------------- /test/comparison/msc_queue.rav: -------------------------------------------------------------------------------- 1 | 2 | interface Queue { 3 | 4 | // definitions 5 | 6 | module Option_Int = Library.Option[Library.IntType] 7 | import Option_Int.some 8 | import Option_Int.none 9 | 10 | field head: Ref 11 | field tail: Ref 12 | field next: Ref 13 | field value: Option_Int 14 | 15 | // predicate p holds for all values stored in the queue 16 | pred p(v: Option_Int) 17 | 18 | lemma p_none() 19 | ensures p(none) 20 | 21 | lemma p_dup(v: Option_Int) 22 | requires p(v) 23 | ensures p(v) && p(v) 24 | 25 | auto pred node(n: Ref) { 26 | exists v: Option_Int, nx: Ref :: 27 | own(n.next, nx) && own(n.value, v) && p(v) && is_queue(nx) 28 | } 29 | 30 | inv is_queue(n: Ref) { 31 | n == null ? true : node(n) 32 | } 33 | 34 | inv queue(q: Ref) { 35 | exists hd: Ref, tl: Ref :: 36 | own(q.head, hd) && is_queue(hd) && hd != null 37 | && own(q.tail, tl) && is_queue(tl) && tl != null 38 | } 39 | 40 | // algorithms 41 | 42 | proc create() 43 | returns (q: Ref) 44 | ensures queue(q) 45 | { 46 | fold is_queue(null); 47 | var tl: Ref; 48 | tl := new(next: null, value: none); 49 | p_none(); 50 | fold is_queue(tl); 51 | var hd: Ref; 52 | hd := new(next: tl, value: none); 53 | p_none(); 54 | fold is_queue(hd); 55 | q := new(head: hd, tail: tl); 56 | fold queue(q); 57 | } 58 | 59 | proc dequeue(q: Ref) 60 | returns (v: Option_Int) 61 | requires queue(q) 62 | ensures queue(q) && p(v) 63 | { 64 | unfold queue(q); 65 | var hd: Ref := q.head; 66 | fold queue(q); 67 | 68 | if (hd == null) { 69 | p_none(); 70 | return none; 71 | } 72 | 73 | unfold is_queue(hd); 74 | var nx: Ref := hd.next; 75 | fold is_queue(hd); 76 | 77 | if (nx == null) { 78 | p_none(); 79 | return none; 80 | } else { 81 | unfold queue(q); 82 | var b: Bool := cas(q.head, hd, nx); 83 | fold queue(q); 84 | 85 | 86 | if (b) { 87 | unfold is_queue(hd); 88 | v := hd.value; 89 | p_dup(v); 90 | fold is_queue(hd); 91 | return v; 92 | } else { 93 | v := dequeue(q); 94 | return v; 95 | } 96 | } 97 | } 98 | 99 | proc set_tail(q:Ref, n: Ref) 100 | requires queue(q) && is_queue(n) && n != null 101 | { 102 | unfold queue(q); 103 | var tl: Ref := q.tail; 104 | fold queue(q); 105 | 106 | unfold is_queue(tl); 107 | var nx: Ref := tl.next; 108 | fold is_queue(tl); 109 | 110 | if (nx == null) { 111 | 112 | unfold is_queue(tl); 113 | var b: Bool := cas(tl.next, null, n); 114 | fold is_queue(tl); 115 | if (b) { 116 | unfold queue(q); 117 | var b: Bool := cas(q.tail, tl, n); 118 | fold queue(q); 119 | } else { 120 | set_tail(q, n); 121 | } 122 | } else { 123 | unfold queue(q); 124 | var b: Bool := cas(q.tail, tl, nx); 125 | fold queue(q); 126 | set_tail(q, n); 127 | } 128 | } 129 | 130 | proc enqueue(q: Ref, v: Int) 131 | requires queue(q) && p(some(v)) 132 | ensures queue(q) 133 | { 134 | var n: Ref; 135 | n := new(next: null, value: some(v)); 136 | 137 | fold is_queue(null); 138 | fold is_queue(n); 139 | 140 | set_tail(q, n); 141 | } 142 | 143 | 144 | } -------------------------------------------------------------------------------- /test/comparison/queue.rav: -------------------------------------------------------------------------------- 1 | 2 | interface Queue { 3 | 4 | // definitions 5 | 6 | module Option_Int = Library.Option[Library.IntType] 7 | import Option_Int._ 8 | 9 | field head: Ref 10 | field next: Ref 11 | field value: Option_Int 12 | 13 | // predicate p holds for all values stored in the queue 14 | pred p(v: Option_Int) 15 | 16 | lemma p_none() 17 | ensures p(none) 18 | 19 | lemma p_dup(v: Option_Int) 20 | requires p(v) 21 | ensures p(v) && p(v) 22 | 23 | pred node(n: Ref) { 24 | exists v: Option_Int, nx: Ref :: 25 | own(n.next, nx) && own(n.value, v) && p(v) && is_queue(nx) 26 | } 27 | 28 | inv is_queue(n: Ref) { 29 | n == null ? true : node(n) 30 | } 31 | 32 | inv queue(q: Ref) { 33 | exists n: Ref :: own(q.head, n) && is_queue(n) 34 | } 35 | 36 | // algorithms 37 | 38 | proc create() 39 | returns (q: Ref) 40 | ensures queue(q) 41 | { 42 | fold is_queue(null); 43 | q := new(head: null); 44 | fold queue(q); 45 | } 46 | 47 | proc dequeue(q: Ref) 48 | returns (v: Option_Int) 49 | requires queue(q) 50 | ensures queue(q) && p(v) 51 | { 52 | unfold queue(q); 53 | var hd: Ref := q.head; 54 | fold queue(q); 55 | 56 | if (hd == null) { 57 | p_none(); 58 | return none; 59 | } 60 | 61 | unfold is_queue(hd); 62 | unfold node(hd); 63 | var nx: Ref := hd.next; 64 | fold node(hd); 65 | fold is_queue(hd); 66 | 67 | if (nx == null) { 68 | p_none(); 69 | return none; 70 | } else { 71 | unfold queue(q); 72 | var b: Bool := cas(q.head, hd, nx); 73 | fold queue(q); 74 | 75 | 76 | if (b) { 77 | unfold is_queue(hd); 78 | unfold node(hd); 79 | v := hd.value; 80 | p_dup(v); 81 | fold node(hd); 82 | fold is_queue(hd); 83 | return v; 84 | } else { 85 | v := dequeue(q); 86 | return v; 87 | } 88 | } 89 | } 90 | 91 | proc get_tail(hd: Ref) 92 | returns (tl: Ref) 93 | requires is_queue(hd) && hd != null 94 | ensures is_queue(tl) && tl != null 95 | { 96 | unfold is_queue(hd); 97 | unfold node(hd); 98 | var nx: Ref := hd.next; 99 | fold node(hd); 100 | fold is_queue(hd); 101 | 102 | if (nx == null) { 103 | tl := hd; 104 | return tl; 105 | } else { 106 | tl := get_tail(nx); 107 | return tl; 108 | } 109 | } 110 | 111 | proc set_tail(hd: Ref, n: Ref) 112 | requires is_queue(hd) && hd != null 113 | requires is_queue(n) && n != null 114 | { 115 | var tl: Ref := get_tail(hd); 116 | 117 | unfold is_queue(tl); 118 | unfold node(tl); 119 | var b: Bool := cas(tl.next, null, n); 120 | 121 | fold node(tl); 122 | fold is_queue(tl); 123 | 124 | if (!b) { 125 | set_tail(hd, n); 126 | } 127 | } 128 | 129 | proc enqueue(q: Ref, v: Int) 130 | requires queue(q) && p(some(v)) 131 | ensures queue(q) 132 | { 133 | var n: Ref; 134 | n := new(next: null, value: some(v)); 135 | 136 | fold is_queue(null); 137 | fold node(n); 138 | fold is_queue(n); 139 | 140 | unfold queue(q); 141 | var hd: Ref := q.head; 142 | fold queue(q); 143 | 144 | if (hd == null) { 145 | unfold queue(q); 146 | q.head := n; 147 | fold queue(q); 148 | } else { 149 | set_tail(hd, n); 150 | } 151 | } 152 | 153 | } -------------------------------------------------------------------------------- /test/comparison/rwlock_duolock.rav: -------------------------------------------------------------------------------- 1 | include "lock_invariant.rav" 2 | include "tokens.rav" 3 | 4 | module RWLockDuoLock[SharedPred: ShareablePredicate] { 5 | field ctr: Int 6 | field lkA_fld: Ref 7 | field lkB_fld: Ref 8 | 9 | module Tk = Tokens[SharedPred] 10 | 11 | import Tk.SharedPred 12 | import Tk.noTokens 13 | import Tk.tokenCounter 14 | import Tk.token 15 | 16 | module LkAResource : LockResource { 17 | rep type T = Ref 18 | 19 | pred resource(r: T) { 20 | SharedPred.p_chunk(r, 1.0) 21 | } 22 | } 23 | 24 | module LkA = Lock[LkAResource] 25 | 26 | module LkBResource : LockResource { 27 | rep type T = (Ref, Ref) 28 | // l, lkA_ref 29 | 30 | pred resource(r: T) { 31 | exists z: Int :: 32 | own( (r#0).ctr, z) && ( 33 | 0 < z ? ( 34 | tokenCounter(r#0, z) && LkA.locked(r#1) 35 | ) : ( 36 | z == 0 ? noTokens(r#0, 1.0) : 37 | false 38 | ) 39 | ) 40 | } 41 | } 42 | 43 | module LkB = Lock[LkBResource] 44 | 45 | auto pred is_rwlock(l: Ref; lkA_ref: Ref, lkB_ref: Ref) { 46 | own(l.lkA_fld, lkA_ref) 47 | && own(l.lkB_fld, lkB_ref) 48 | && LkA.lock_inv(lkA_ref, l) 49 | && LkB.lock_inv(lkB_ref, (l, lkA_ref)) 50 | } 51 | 52 | proc create() 53 | returns (l: Ref) 54 | requires SharedPred.p() 55 | ensures is_rwlock(l) 56 | { 57 | l := new(ctr: 0, lkA_fld: null, lkB_fld: null, Tk.v: TokenRA.noToken(1.0)); 58 | SharedPred.allocate(l); 59 | fold LkAResource.resource(l); 60 | var lkA_ref := LkA.create(l); 61 | 62 | fold noTokens(l, 1.0); 63 | fold LkBResource.resource((l, lkA_ref)); 64 | 65 | var lkB_ref := LkB.create((l, lkA_ref)); 66 | 67 | l.lkA_fld := lkA_ref; 68 | l.lkB_fld := lkB_ref; 69 | } 70 | 71 | proc acquire_reader(l: Ref, implicit ghost lkA_ref': Ref, implicit ghost lkB_ref': Ref) 72 | returns (n: Int) 73 | requires is_rwlock(l, lkA_ref', lkB_ref') 74 | ensures token(l) 75 | { 76 | var lkA_ref: Ref := l.lkA_fld; 77 | var lkB_ref: Ref := l.lkB_fld; 78 | 79 | LkB.acquire(lkB_ref); 80 | 81 | 82 | unfold LkBResource.resource((l, lkA_ref)); 83 | var old_val := l.ctr; 84 | l.ctr := old_val + 1; 85 | 86 | if (old_val == 0) { 87 | LkA.acquire(lkA_ref); 88 | unfold LkAResource.resource(l); 89 | Tk.token_mutate_generate(l); 90 | } else { 91 | Tk.token_mutate_incr(l, old_val); 92 | } 93 | 94 | fold LkBResource.resource((l, lkA_ref)); 95 | LkB.release(lkB_ref); 96 | } 97 | 98 | proc release_reader(l: Ref, implicit ghost lkA_ref': Ref, implicit ghost lkB_ref': Ref) 99 | requires is_rwlock(l, lkA_ref', lkB_ref') && token(l) 100 | ensures true 101 | { 102 | var lkA_ref: Ref := l.lkA_fld; 103 | var lkB_ref: Ref := l.lkB_fld; 104 | 105 | LkB.acquire(lkB_ref); 106 | 107 | unfold LkBResource.resource((l, lkA_ref)); 108 | var old_val := l.ctr; 109 | l.ctr := old_val - 1; 110 | 111 | if (old_val == 1) { 112 | Tk.token_mutate_decr_last(l); 113 | fold LkAResource.resource(l); 114 | LkA.release(lkA_ref); 115 | } else if (old_val == 0) { 116 | Tk.token_noTokens_interact(l, 1.0); 117 | } else { 118 | Tk.token_mutate_decr(l, old_val); 119 | } 120 | 121 | fold LkBResource.resource((l, lkA_ref)); 122 | LkB.release(lkB_ref); 123 | } 124 | 125 | proc upgrade_reader(l: Ref, implicit ghost lkA_ref': Ref, implicit ghost lkB_ref': Ref) 126 | requires is_rwlock(l, lkA_ref', lkB_ref') && token(l) 127 | ensures SharedPred.p_chunk(l, 1.0) && LkA.locked(lkA_ref') 128 | { 129 | var lkA_ref: Ref := l.lkA_fld; 130 | var lkB_ref: Ref := l.lkB_fld; 131 | 132 | LkB.acquire(lkB_ref); 133 | 134 | unfold LkBResource.resource((l, lkA_ref)); 135 | var old_val := l.ctr; 136 | l.ctr := old_val - 1; 137 | 138 | {! 139 | if (old_val == 1) { 140 | Tk.token_mutate_decr_last(l); 141 | } else if (old_val == 0) { 142 | Tk.token_noTokens_interact(l, 1.0); 143 | } else { 144 | Tk.token_mutate_decr(l, old_val); 145 | } 146 | !} 147 | 148 | fold LkBResource.resource((l, lkA_ref)); 149 | LkB.release(lkB_ref); 150 | 151 | if (old_val == 1) { 152 | // do nothing 153 | } else { 154 | LkA.acquire(lkA_ref); 155 | unfold LkAResource.resource(l); 156 | } 157 | } 158 | 159 | proc acquire_writer(l: Ref, implicit ghost lkA_ref': Ref, implicit ghost lkB_ref': Ref) 160 | requires is_rwlock(l, lkA_ref', lkB_ref') 161 | ensures SharedPred.p_chunk(l, 1.0) && LkA.locked(lkA_ref') 162 | { 163 | var lkA_ref: Ref := l.lkA_fld; 164 | var lkB_ref: Ref := l.lkB_fld; 165 | 166 | LkA.acquire(lkA_ref); 167 | unfold LkAResource.resource(l); 168 | } 169 | 170 | proc release_writer(l: Ref, implicit ghost lkA_ref': Ref, implicit ghost lkB_ref': Ref) 171 | requires is_rwlock(l, lkA_ref', lkB_ref') && LkA.locked(lkA_ref') && SharedPred.p_chunk(l, 1.0) 172 | ensures true 173 | { 174 | var lkA_ref: Ref := l.lkA_fld; 175 | var lkB_ref: Ref := l.lkB_fld; 176 | 177 | fold LkAResource.resource(l); 178 | LkA.release(lkA_ref); 179 | } 180 | } -------------------------------------------------------------------------------- /test/comparison/rwlock_duolock.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./rwlock_duolock.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/comparison/rwlock_lockless_faa.rav: -------------------------------------------------------------------------------- 1 | include "tokens.rav" 2 | 3 | interface RWLockLocklessFAA[SharedPred: ShareablePredicate] { 4 | field ctr: Int 5 | 6 | module Tk = Tokens[SharedPred] 7 | 8 | import Tk.SharedPred 9 | import Tk.noTokens 10 | import Tk.tokenCounter 11 | import Tk.token 12 | 13 | inv is_rwlock(l: Ref) { 14 | exists z: Int :: 15 | own(l.ctr, z) 16 | && (z > 0 ? (tokenCounter(l, z)) : 17 | (z == 0 ? (noTokens(l, 1.0) && SharedPred.p_chunk(l, 1.0)) : 18 | (z == -1) && noTokens(l, 0.5))) 19 | } 20 | 21 | proc create() 22 | returns (l: Ref) 23 | requires SharedPred.p() 24 | ensures is_rwlock(l) 25 | { 26 | l := new(ctr: 0, Tk.v: TokenRA.noToken(1.0)); 27 | SharedPred.allocate(l); 28 | fold noTokens(l, 1.0); 29 | fold is_rwlock(l); 30 | } 31 | 32 | proc acquire_reader(l: Ref) 33 | requires is_rwlock(l) 34 | ensures token(l) 35 | { 36 | unfold is_rwlock(l); 37 | var z: Int := l.ctr; 38 | fold is_rwlock(l); 39 | 40 | 41 | if (z == -1) { 42 | acquire_reader(l); 43 | } else { 44 | unfold is_rwlock(l); 45 | var b: Bool := cas(l.ctr, z, z+1); 46 | 47 | {! 48 | if (b) { 49 | if (z == 0) { 50 | Tk.token_mutate_generate(l); 51 | } else { 52 | Tk.token_mutate_incr(l, z); 53 | } 54 | } 55 | !} 56 | fold is_rwlock(l); 57 | 58 | if (!b) { 59 | acquire_reader(l); 60 | } 61 | } 62 | } 63 | 64 | proc release_reader(l: Ref) 65 | requires is_rwlock(l) && token(l) 66 | ensures true 67 | { 68 | ghost var z: Int; 69 | 70 | unfold is_rwlock(l)[z := z]; 71 | var old_ctr := faa(l.ctr, -1); 72 | {! 73 | if (z > 1) { 74 | Tk.token_mutate_decr(l, z); 75 | } else if (z == 1) { 76 | Tk.token_mutate_decr_last(l); 77 | } else if (z == 0) { 78 | Tk.token_noTokens_interact(l, 1.0); 79 | } else { 80 | Tk.token_noTokens_interact(l, 0.5); 81 | } 82 | !} 83 | fold is_rwlock(l); 84 | } 85 | 86 | proc acquire_writer(l: Ref) 87 | requires is_rwlock(l) 88 | ensures SharedPred.p_chunk(l, 1.0) && noTokens(l, 0.5) 89 | { 90 | unfold is_rwlock(l); 91 | var b: Bool := cas(l.ctr, 0, -1); 92 | {! 93 | if (b) { 94 | Tk.noTokens_split(l, 1.0); 95 | } 96 | !} 97 | fold is_rwlock(l); 98 | 99 | if (!b) { 100 | acquire_writer(l); 101 | } 102 | } 103 | 104 | proc release_writer(l: Ref) 105 | requires is_rwlock(l) 106 | requires SharedPred.p_chunk(l, 1.0) && noTokens(l, 0.5) 107 | ensures true 108 | { 109 | ghost var z: Int; 110 | unfold is_rwlock(l)[z := z]; 111 | {! 112 | if (z > 0) { 113 | Tk.tokenCounter_noTokens_interact(l, z, 0.5); 114 | } else if (z == 0) { 115 | SharedPred.merge(l, 1.0, 1.0); 116 | SharedPred.invalid(l, 2.0); 117 | } 118 | !} 119 | assert z == -1; 120 | l.ctr := 0; 121 | Tk.noTokens_merge(l, 0.5, 0.5); 122 | fold is_rwlock(l); 123 | } 124 | } -------------------------------------------------------------------------------- /test/comparison/shareable_predicates.rav: -------------------------------------------------------------------------------- 1 | interface ShareablePredicate { 2 | pred p(); 3 | 4 | pred p_chunk(x: Ref, f: Real); 5 | 6 | proc allocate(x: Ref) 7 | requires p() 8 | ensures p_chunk(x, 1.0) 9 | 10 | lemma destroyShareable(x: Ref) 11 | requires p_chunk(x, 1.0) 12 | ensures p() 13 | 14 | proc deallocate(x: Ref) 15 | requires p() 16 | ensures true 17 | 18 | axiom split(x: Ref, f: Real) 19 | requires p_chunk(x, f) 20 | ensures p_chunk(x, f / 2.0) && p_chunk(x, f / 2.0) 21 | 22 | axiom merge(x: Ref, f1: Real, f2: Real) 23 | requires p_chunk(x, f1) && p_chunk(x, f2) 24 | // requires f1+f2 <= 1.0 25 | ensures p_chunk(x, f1+f2) 26 | 27 | axiom invalid(x: Ref, f: Real) 28 | requires p_chunk(x, f) 29 | requires f > 1.0 30 | ensures false 31 | } -------------------------------------------------------------------------------- /test/comparison/ticket_lock_client.rav: -------------------------------------------------------------------------------- 1 | include "lock_invariant.rav" 2 | 3 | module TicketLockClient { 4 | 5 | field f1: Int 6 | field f2: Int 7 | 8 | // Instantiating the lock module 9 | module LkResource : LockResource { 10 | rep type T = Ref 11 | 12 | pred resource(r: T) { 13 | exists z: Int :: own(r.f1, z) && own(r.f2, z) 14 | } 15 | } 16 | 17 | module Lk = Lock[LkResource] 18 | 19 | // algorithms 20 | 21 | proc foo(l: Ref, lk: Ref, z: Int) 22 | requires Lk.lock_inv(lk, l) 23 | ensures true 24 | { 25 | Lk.acquire(lk); 26 | unfold LkResource.resource(l); 27 | l.f1 := z; 28 | l.f2 := z; 29 | fold LkResource.resource(l); 30 | Lk.release(lk); 31 | } 32 | 33 | // adding exists l: Ref, lk: Ref :: LK.lock_inv(lk, l) 34 | // to the postcondition because call to foo() 35 | // requires LK.lock_inv() in the mask 36 | proc run_foo() 37 | requires true 38 | ensures exists l: Ref, lk: Ref :: Lk.lock_inv(lk, l) 39 | { 40 | var l := new(f1: 0, f2: 0); 41 | fold LkResource.resource(l); 42 | var lk := Lk.create(l); 43 | 44 | spawn foo(l, lk, 3); 45 | spawn foo(l, lk, 5); 46 | 47 | Lk.acquire(lk); 48 | unfold LkResource.resource(l); 49 | var v1 := l.f1; 50 | var v2 := l.f2; 51 | 52 | if (v1 != v2) { 53 | // this section is unreachable as the program verifies 54 | assert false; 55 | } 56 | 57 | assert Lk.lock_inv(lk, l); 58 | } 59 | } -------------------------------------------------------------------------------- /test/concurrent/counter/counter.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | inv counterInv(x: Ref) { 4 | exists v: Int :: own(x.c, v, 1.0) 5 | } 6 | 7 | proc incr(x: Ref) 8 | requires counterInv(x) 9 | ensures counterInv(x) 10 | { 11 | var v1: Int; 12 | 13 | unfold counterInv(x); 14 | v1 := x.c; 15 | fold counterInv(x); 16 | 17 | var new_v1 : Int := v1 + 1; 18 | var res: Bool; 19 | 20 | unfold counterInv(x); 21 | res := cas(x.c, v1, new_v1); 22 | fold counterInv(x); 23 | 24 | if (!res) { 25 | incr(x); // retry 26 | } 27 | } 28 | 29 | proc read(x: Ref) 30 | returns (v: Int) 31 | requires counterInv(x) 32 | ensures counterInv(x) 33 | { 34 | unfold counterInv(x); 35 | v := x.c; 36 | fold counterInv(x); 37 | 38 | return v; 39 | } 40 | 41 | proc make() 42 | returns (x: Ref) 43 | ensures counterInv(x) 44 | { 45 | x := new(c: 0); 46 | fold counterInv(x); 47 | } 48 | -------------------------------------------------------------------------------- /test/concurrent/counter/counter.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./counter.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/counter/counter_monotonic.rav: -------------------------------------------------------------------------------- 1 | import Library.Auth 2 | import Library.MaxNat 3 | 4 | field c: Int 5 | 6 | module AuthMaxNat = Auth[MaxNat] 7 | import AuthMaxNat._ 8 | 9 | ghost field h: AuthMaxNat 10 | 11 | inv counterInv(x: Ref) { 12 | exists v: Int :: own(x.h, auth_frag(v,v)) && own(x.c, v, 1.0) 13 | } 14 | 15 | proc incr(x: Ref) 16 | requires counterInv(x) 17 | ensures counterInv(x) 18 | { 19 | var v1: Int; 20 | 21 | unfold counterInv(x); 22 | v1 := x.c; 23 | fold counterInv(x); 24 | 25 | var new_v1 : Int := v1 + 1; 26 | var res: Bool; 27 | 28 | ghost var v2: Int; 29 | unfold counterInv(x); 30 | v2 :| own(x.c, v2, 1.0); 31 | assert v1 <= v2; 32 | res := cas(x.c, v1, new_v1); 33 | 34 | if (!res) { 35 | fold counterInv(x); 36 | incr(x); 37 | } else { 38 | // Frame preserving update of ghost resource x.h 39 | fpu(x.h, auth_frag(v1,v1), auth_frag(new_v1,new_v1)); 40 | fold counterInv(x); 41 | } 42 | } 43 | 44 | proc read(x: Ref) 45 | returns (v: Int) 46 | requires counterInv(x) 47 | ensures counterInv(x) 48 | { 49 | unfold counterInv(x); 50 | v := x.c; 51 | fold counterInv(x); 52 | 53 | return v; 54 | } 55 | 56 | proc make() 57 | returns (x: Ref) 58 | ensures counterInv(x) 59 | { 60 | x := new(c: 0, h: auth_frag(0,0)); 61 | fold counterInv(x); 62 | } 63 | -------------------------------------------------------------------------------- /test/concurrent/counter/counter_monotonic.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./counter_monotonic.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/counter/counter_no_inv.rav: -------------------------------------------------------------------------------- 1 | field c: Int 2 | 3 | pred counter(x: Ref; v: Int) { 4 | own(x.c, v, 1.0) 5 | } 6 | 7 | proc incr(x: Ref, implicit ghost v: Int) 8 | atomic requires counter(x, v) 9 | atomic ensures counter(x, v + 1) 10 | { 11 | ghost var phi := bindAU(); 12 | 13 | 14 | ghost var v0: Int := openAU(phi); 15 | unfold counter(x, v0); 16 | var v1: Int := x.c; 17 | fold counter(x, v0); 18 | abortAU(phi); 19 | var new_v1 : Int := v1 + 1; 20 | 21 | ghost var v2: Int := openAU(phi); 22 | unfold counter(x,v2); 23 | 24 | var res: Bool := cas(x.c, v1, new_v1); 25 | 26 | if (!res) { 27 | fold counter(x, v2); 28 | abortAU(phi); 29 | ghost var v3: Int := openAU(phi); 30 | incr(x); 31 | commitAU(phi); 32 | } else { 33 | fold counter(x, new_v1); 34 | commitAU(phi); 35 | } 36 | } 37 | 38 | proc read(x: Ref, implicit ghost v: Int) 39 | returns (v2: Int) 40 | atomic requires counter(x, v) 41 | atomic ensures counter(x, v) && v2 == v 42 | { 43 | ghost var phi := bindAU(); 44 | 45 | ghost var v0: Int := openAU(phi); 46 | unfold counter(x, v0); 47 | var v1: Int := x.c; 48 | fold counter(x, v0); 49 | commitAU(phi, v1); 50 | 51 | return v1; 52 | } 53 | -------------------------------------------------------------------------------- /test/concurrent/counter/counter_no_inv.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./counter_no_inv.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/counter/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/concurrent/lock/clh-lock.rav: -------------------------------------------------------------------------------- 1 | interface CLHLock { 2 | field locked: Bool; 3 | field loc: Ref; 4 | field predecessor: Ref; 5 | field tail: Ref 6 | 7 | ghost field agr: (); 8 | 9 | // Resource protected by the lock 10 | pred resource() 11 | 12 | inv queued_loc(l: Ref) { 13 | exists b_disj: Bool, b: Bool :: 14 | (b_disj ? own(l, agr, (), 1.0) : 15 | own(l, locked, b, 0.5) && 16 | (!b ==> resource() && own(l, agr, (), 0.5) && own(l, locked, b, 0.5))) 17 | } 18 | 19 | inv lock_inv(lk: Ref) { 20 | exists l: Ref :: 21 | own(lk, tail, l, 1.0) && 22 | own(l, agr, (), 0.5) && 23 | queued_loc(l) 24 | } 25 | 26 | auto pred acquired_node(node: Ref) { 27 | exists ln: Ref, pn: Ref :: 28 | own(node, loc, ln, 1.0) && 29 | queued_loc(ln) && own(ln, agr, (), 0.5) && 30 | own(ln, locked, true, 0.5) && 31 | own(node, predecessor, pn, 1.0) && 32 | own(pn, locked, false, 1.0) && 33 | queued_loc(pn) && 34 | resource() 35 | } 36 | 37 | auto pred free_node(node: Ref) { 38 | exists ln: Ref, pn: Ref :: 39 | own(node, loc, ln, 1.0) && 40 | own(ln, locked, false, 1.0) && 41 | own(node, predecessor, pn, 1.0) && 42 | queued_loc(ln) 43 | } 44 | 45 | proc create_node() 46 | returns (node: Ref) 47 | ensures free_node(node) 48 | { 49 | var newloc := new(locked: false, agr: ()); 50 | node := new(loc: newloc, predecessor: null); 51 | fold queued_loc(newloc)[b_disj := true]; 52 | } 53 | 54 | proc create_lock() 55 | returns (lk: Ref) 56 | requires resource() 57 | ensures lock_inv(lk) 58 | { 59 | var l := new(locked: false, agr: ()); 60 | lk := new(tail: l); 61 | fold queued_loc(l)[b_disj := false]; 62 | fold lock_inv(lk); 63 | } 64 | 65 | proc wait_on(lk: Ref, pn: Ref, ln: Ref, node: Ref) 66 | requires lock_inv(lk) && queued_loc(ln) && 67 | own(node, loc, ln, 1.0) && 68 | own(node, predecessor, pn, 1.0) && 69 | own(ln, agr, (), 0.5) && 70 | own(ln, locked, true, 0.5) && 71 | queued_loc(pn) && own(pn, agr, (), 0.5) 72 | ensures acquired_node(node) 73 | { 74 | ghost var branch: Bool; 75 | unfold queued_loc(pn)[branch := b_disj]; 76 | var b := pn.locked; 77 | 78 | fold queued_loc(pn)[b := b, b_disj := !b || branch]; 79 | 80 | if (b) { 81 | wait_on(lk, pn, ln, node); 82 | } 83 | } 84 | 85 | proc acquire(lk: Ref, node: Ref) 86 | requires lock_inv(lk) && free_node(node) 87 | ensures acquired_node(node) 88 | { 89 | var ln := node.loc; 90 | ln.locked := true; 91 | 92 | unfold lock_inv(lk); 93 | unfold queued_loc(ln); 94 | var pn := xchg(lk.tail, ln); 95 | fold queued_loc(ln)[b_disj := false]; 96 | fold lock_inv(lk); 97 | 98 | // Set new predecessor 99 | node.predecessor := pn; 100 | // Wait on the predecessor 101 | wait_on(lk, pn, ln, node); 102 | } 103 | 104 | proc release(lk: Ref, node: Ref) 105 | requires acquired_node(node) 106 | ensures free_node(node) 107 | { 108 | var ln := node.loc; 109 | unfold queued_loc(ln); 110 | ln.locked := false; 111 | ghost var l: Ref; 112 | fold queued_loc(ln)[b_disj := false]; 113 | var pn := node.predecessor; 114 | node.loc := pn; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /test/concurrent/lock/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/concurrent/lock/lock.rav: -------------------------------------------------------------------------------- 1 | interface LockResource : Library.Type { 2 | rep type T 3 | 4 | // Resource protected by a lock 5 | pred resource(r: T) 6 | 7 | axiom exclusive(r: T) 8 | requires resource(r) && resource(r) 9 | ensures false 10 | } 11 | 12 | 13 | interface Lock[R: LockResource] { 14 | import R.resource 15 | 16 | module Agree = Library.Agree[R] 17 | 18 | ghost field agr: Agree 19 | 20 | 21 | // Lock representation invariant 22 | pred lock_rep(l: Ref; b: Bool) 23 | 24 | // Abstract predicate describing a lock 25 | auto pred is_lock(l: Ref; r: R, b: Bool) { 26 | own(l.agr, Agree.agree(r)) 27 | && lock_rep(l, b) 28 | && (b ? true : resource(r)) 29 | } 30 | 31 | lemma exclusive(l: Ref, r: R) 32 | requires is_lock(l, r, false) && resource(r) 33 | ensures false 34 | { 35 | //unfold is_lock(l, r, false); 36 | R.exclusive(r); 37 | } 38 | 39 | proc create(r: R) 40 | returns (l: Ref) 41 | requires resource(r) 42 | ensures is_lock(l, r, false) 43 | 44 | proc acquire(l: Ref, implicit ghost r: R, implicit ghost b: Bool) 45 | atomic requires is_lock(l, r, b) 46 | atomic ensures is_lock(l, r, true) && b == false && resource(r) 47 | 48 | proc release(l: Ref, implicit ghost r: R) 49 | atomic requires is_lock(l, r, true) && resource(r) 50 | atomic ensures is_lock(l, r, false) 51 | } 52 | -------------------------------------------------------------------------------- /test/concurrent/lock/spin-lock.rav: -------------------------------------------------------------------------------- 1 | include "lock.rav" 2 | 3 | module SpinLock[R: LockResource] : Lock { 4 | field bit: Bool 5 | 6 | import R.resource 7 | 8 | auto pred lock_rep(l: Ref; b: Bool) { 9 | own(l.bit, b, 1.0) 10 | } 11 | 12 | proc create(r: R) 13 | returns (l: Ref) 14 | requires resource(r) 15 | ensures is_lock(l, r, false) 16 | { 17 | l := new (bit: false, agr: Agree.agree(r)); 18 | } 19 | 20 | proc acquire(l: Ref, implicit ghost r: R, implicit ghost b: Bool) 21 | atomic requires is_lock(l, r, b) 22 | atomic ensures is_lock(l, r, true) && b == false && resource(r) 23 | { 24 | ghost val phi := bindAU(); 25 | 26 | ghost var b1: Bool; 27 | r, b1 := openAU(phi); 28 | val res: Bool := cas(l.bit, false, true); 29 | 30 | if (res) { 31 | commitAU(phi); 32 | return; 33 | } else { 34 | abortAU(phi); 35 | } 36 | 37 | r, b1 := openAU(phi); 38 | acquire(l, r, b1); 39 | commitAU(phi); 40 | } 41 | 42 | proc release(l: Ref, implicit ghost r: R) 43 | atomic requires is_lock(l, r, true) && resource(r) 44 | atomic ensures is_lock(l, r, false) 45 | { 46 | ghost val phi := bindAU(); 47 | r := openAU(phi); 48 | l.bit := false; 49 | commitAU(phi); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/concurrent/lock/spin-lock.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./spin-lock.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/lock/spin-lock_compact.rav: -------------------------------------------------------------------------------- 1 | include "lock.rav" 2 | 3 | module SpinLock[R: LockResource] { 4 | field bit: Bool 5 | 6 | import R.resource 7 | 8 | module Agree = Library.Agree[R] 9 | ghost field agr: Agree 10 | 11 | auto pred is_lock(l: Ref; r: R, b: Bool) { 12 | own(l, agr, Agree.agree(r)) 13 | && own(l, bit, b, 1.0) 14 | && (b ? true : resource(r)) 15 | } 16 | 17 | proc create(r: R) 18 | returns (l: Ref) 19 | requires resource(r) 20 | ensures is_lock(l, r, false) 21 | { 22 | l := new (bit: false, agr: Agree.agree(r)); 23 | } 24 | 25 | proc acquire(l: Ref, implicit ghost r: R, implicit ghost b: Bool) 26 | atomic requires is_lock(l, r, b) 27 | atomic ensures is_lock(l, r, true) && b == false && resource(r) 28 | { 29 | ghost val phi := bindAU(); 30 | 31 | ghost var b1: Bool; 32 | r, b1 := openAU(phi); 33 | 34 | val res: Bool := cas(l.bit, false, true); 35 | 36 | if (res) { 37 | commitAU(phi); 38 | return; 39 | } else { 40 | abortAU(phi); 41 | } 42 | 43 | r, b1 := openAU(phi); 44 | acquire(l, r, b1); 45 | commitAU(phi); 46 | } 47 | 48 | proc release(l: Ref, implicit ghost r: R) 49 | atomic requires is_lock(l, r, true) && resource(r) 50 | atomic ensures is_lock(l, r, false) 51 | { 52 | ghost val phi := bindAU(); 53 | r := openAU(phi); 54 | l.bit := false; 55 | commitAU(phi); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/concurrent/lock/ticket-lock.rav: -------------------------------------------------------------------------------- 1 | //include "lock.rav" 2 | 3 | interface LockResource : Library.Type { 4 | rep type T 5 | 6 | // Resource protected by a lock 7 | pred resource(r: T) 8 | 9 | axiom exclusive(r: T) 10 | requires resource(r) && resource(r) 11 | ensures false 12 | } 13 | 14 | interface Lock { 15 | module R: LockResource 16 | 17 | inv lock_inv(l: Ref; r: R) 18 | 19 | proc create(r: R) returns (l: Ref) 20 | requires R.resource(r) 21 | ensures lock_inv(l, r) 22 | 23 | proc acquire(l: Ref, implicit ghost r: R) 24 | requires lock_inv(l, r) 25 | ensures R.resource(r) 26 | 27 | proc release(l: Ref, implicit ghost r: R) 28 | requires lock_inv(l, r) && R.resource(r) 29 | ensures true 30 | } 31 | 32 | module TicketLock[R: LockResource] : Lock { 33 | import R.resource 34 | 35 | field next: Int 36 | field curr: Int 37 | 38 | module IntSet = Library.DisjSet[Library.IntType] 39 | module AuthDisjInts = Library.Auth[IntSet] 40 | 41 | ghost field tickets: AuthDisjInts 42 | 43 | inv lock_inv(l: Ref; r: R) { 44 | exists n: Int, c: Int, b: Bool :: 45 | own(l.next, n, 1.0) && n >= 0 46 | && own(l.curr, c, 1.0) 47 | && (b ? 48 | own(l.tickets, AuthDisjInts.frag(IntSet.set({|c|}))) : 49 | resource(r) 50 | ) 51 | && own(l.tickets, 52 | AuthDisjInts.auth_frag( 53 | IntSet.set({| i: Int :: 0 <= i && i < n |}), 54 | IntSet.set({||}) 55 | ) 56 | ) 57 | } 58 | 59 | proc create(r: R) returns (l: Ref) 60 | requires resource(r) 61 | ensures lock_inv(l, r) 62 | { 63 | l := new ( 64 | next: 0, curr: -1, 65 | tickets: AuthDisjInts.auth_frag( 66 | IntSet.set({||}), IntSet.set({||}) 67 | ) 68 | ); 69 | fold lock_inv(l, r)[b := false]; 70 | } 71 | 72 | proc acquire(l: Ref, implicit ghost r: R) 73 | requires lock_inv(l, r) 74 | ensures resource(r) 75 | { 76 | ghost var lockAcq: Bool; 77 | unfold lock_inv(l, r)[lockAcq := b]; 78 | val nxt := faa(l.next, 1); 79 | fpu(l.tickets, 80 | AuthDisjInts.auth_frag( 81 | IntSet.set({|i: Int :: 0 <= i && i < nxt|}), 82 | IntSet.set({||}) 83 | ), 84 | AuthDisjInts.auth_frag( 85 | IntSet.set({|i: Int :: 0 <= i && i < nxt+1|}), 86 | IntSet.set({|nxt|}) 87 | ) 88 | ); 89 | fold lock_inv(l, r)[b := lockAcq]; 90 | 91 | var crr: Int := -1; 92 | while (nxt != crr) 93 | invariant lock_inv(l, r) && ( 94 | nxt == crr ? resource(r) : 95 | own(l.tickets, AuthDisjInts.frag(IntSet.set({|nxt|}))) 96 | ) 97 | { 98 | unfold lock_inv(l, r)[ lockAcq := b ]; 99 | crr := l.curr; 100 | fold lock_inv(l, r)[ b := nxt == crr || lockAcq]; 101 | } 102 | } 103 | 104 | proc release(l: Ref, implicit ghost r: R) 105 | requires lock_inv(l, r) && resource(r) 106 | ensures true 107 | { 108 | ghost var lockAcq: Bool; 109 | 110 | unfold lock_inv(l, r)[ lockAcq := b ]; 111 | {! if (!lockAcq) R.exclusive(r); !} 112 | 113 | val crr: Int := l.curr; 114 | fold lock_inv(l, r)[b := true]; 115 | 116 | val c1: Int := crr+1; 117 | unfold lock_inv(l, r); 118 | 119 | l.curr := c1; 120 | 121 | fold lock_inv(l, r)[b := false]; 122 | } 123 | } -------------------------------------------------------------------------------- /test/concurrent/lock/ticket-lock_atomics.rav: -------------------------------------------------------------------------------- 1 | include "lock.rav" 2 | 3 | module TicketLock[R: LockResource] { 4 | import R.resource 5 | 6 | field next: Int 7 | field curr: Int 8 | 9 | module IntSet = Library.DisjSet[Library.IntType] 10 | module AuthDisjInts = Library.Auth[IntSet] 11 | 12 | ghost field tickets: AuthDisjInts 13 | 14 | pred is_lock(l: Ref; r: R, b: Bool) { 15 | exists n: Int, c: Int :: 16 | own(l.next, n, 1.0) && n >= 0 17 | && own(l.curr, c, 1.0) 18 | && (b ? 19 | own(l.tickets, AuthDisjInts.frag(IntSet.set({|c|}))) : 20 | resource(r) 21 | ) 22 | && own(l.tickets, 23 | AuthDisjInts.auth_frag( 24 | IntSet.set({|i: Int :: 0 <= i && i < n|}), 25 | IntSet.set({||}) 26 | ) 27 | ) 28 | } 29 | 30 | proc create(r: R) returns (l: Ref) 31 | requires resource(r) 32 | ensures is_lock(l, r, false) 33 | { 34 | l := new ( 35 | next: 0, curr: -1, 36 | tickets: AuthDisjInts.auth_frag( 37 | IntSet.set({||}), IntSet.set({||}) 38 | ) 39 | ); 40 | 41 | fold is_lock(l, r, false); 42 | } 43 | 44 | proc wait_loop(l: Ref, x: Int, implicit ghost r: R, implicit ghost b: Bool) 45 | requires own(l.tickets, AuthDisjInts.frag(IntSet.set({|x|}))) 46 | atomic requires is_lock(l, r, b) 47 | atomic ensures is_lock(l, r, true) && b == false && resource(r) 48 | { 49 | ghost val phi := bindAU(); 50 | r, b := openAU(phi); 51 | unfold is_lock(l); 52 | val c: Int := l.curr; 53 | 54 | if (x == c) { 55 | fold is_lock(l, r, true); 56 | commitAU(phi); 57 | return; 58 | } else { 59 | fold is_lock(l, r, b); 60 | abortAU(phi); 61 | r, b := openAU(phi); 62 | wait_loop(l, x); 63 | commitAU(phi); 64 | } 65 | } 66 | 67 | proc acquire(l: Ref, implicit ghost r: R, implicit ghost b: Bool) 68 | atomic requires is_lock(l, r, b) 69 | atomic ensures is_lock(l, r, true) && b == false && resource(r) 70 | { 71 | ghost val phi := bindAU(); 72 | 73 | r, b := openAU(phi); 74 | unfold is_lock(l); 75 | val nxt: Int := l.next; 76 | fold is_lock(l, r, b); 77 | abortAU(phi); 78 | 79 | r, b := openAU(phi); 80 | unfold is_lock(l); 81 | val res: Bool := cas(l.next, nxt, nxt+1); 82 | 83 | if (res) { 84 | fpu(l, tickets, 85 | AuthDisjInts.auth_frag( 86 | IntSet.set({|i: Int :: 0 <= i && i < nxt|}), 87 | IntSet.set({||}) 88 | ), 89 | AuthDisjInts.auth_frag( 90 | IntSet.set({|i: Int :: 0 <= i && i < nxt+1|}), 91 | IntSet.set({|nxt|}) 92 | ) 93 | ); 94 | fold is_lock(l, r, b); 95 | abortAU(phi); 96 | r, b := openAU(phi); 97 | wait_loop(l, nxt); 98 | commitAU(phi); 99 | 100 | } else { 101 | fold is_lock(l, r, b); 102 | abortAU(phi); 103 | r, b := openAU(phi); 104 | acquire(l); 105 | commitAU(phi); 106 | } 107 | } 108 | 109 | 110 | proc release(l: Ref, implicit ghost r: R) 111 | atomic requires is_lock(l, r, true) && resource(r) 112 | atomic ensures is_lock(l, r, false) 113 | { 114 | ghost val phi := bindAU(); 115 | r := openAU(phi); 116 | unfold is_lock(l, r, true); 117 | val c: Int := l.curr; 118 | fold is_lock(l, r, true); 119 | abortAU(phi); 120 | 121 | val c1: Int := c + 1; 122 | r := openAU(phi); 123 | unfold is_lock(l, r, true); 124 | l.curr := c1; 125 | fold is_lock(l, r, false); 126 | commitAU(phi); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /test/concurrent/templates/ccm.rav: -------------------------------------------------------------------------------- 1 | import Library.Type 2 | 3 | interface CCM : Type { 4 | val id: T 5 | func comp(a:T, b:T) returns (ret:T) 6 | 7 | func frame(a:T, b:T) returns (ret:T) 8 | 9 | func valid(a:T) returns (ret: Bool) 10 | 11 | auto axiom idValid() 12 | ensures valid(id) 13 | 14 | auto axiom compAssoc() 15 | ensures forall a:T, b:T, c:T :: {comp(comp(a, b), c)} {comp(a, comp(b, c))} (comp(comp(a, b), c) == comp(a, comp(b, c))) 16 | 17 | auto axiom compCommute() 18 | ensures forall a:T, b:T :: {comp(a,b)} {comp(b,a)} comp(a, b) == comp(b, a) 19 | 20 | auto axiom compId() 21 | ensures forall a:T :: {comp(a, id)} {frame(a, id)} comp(a, id) == a 22 | 23 | auto axiom compValid() 24 | ensures forall a:T, b:T :: {comp(a,b)} valid(a) && valid(b) ==> valid(comp(a, b)) 25 | 26 | auto axiom frameCompInv() 27 | ensures forall a:T, b:T:: {comp(a,b)} frame(comp(a, b), b) == a 28 | 29 | lemma frameId() 30 | ensures forall a:T :: {frame(a,id)} frame(a, id) == a 31 | {} 32 | 33 | // Better name? selfFrame? frameRefl? 34 | lemma frameInv() 35 | ensures forall a:T :: {frame(a,a)} frame(a, a) == id 36 | { 37 | assert forall a:T :: {frame(a,a)} frame(a, a) == id with { 38 | assert frame(a, a) == frame(comp(a, id), a); 39 | } 40 | } 41 | 42 | auto axiom compFrameInv() 43 | ensures forall a:T, b:T :: {frame(a,b)} valid(frame(a, b)) ==> comp(frame(a, b), b) == a 44 | 45 | lemma frameFrame() 46 | ensures forall a:T, b:T :: {valid(frame(a, b))} valid(frame(a, b)) ==> frame(a, frame(a, b)) == b 47 | {} 48 | } -------------------------------------------------------------------------------- /test/concurrent/templates/ccm_instances.rav: -------------------------------------------------------------------------------- 1 | include "ccm.rav" 2 | 3 | import Library.Type 4 | // import Library.CancellativeResourceAlgebra 5 | 6 | module Multiset[K: Type]: CCM { 7 | rep type T = Map[K, Int] 8 | 9 | val id: T := {| k: K :: 0 |} 10 | 11 | func comp(a:T, b:T) returns (ret:T) 12 | { 13 | {| k: K :: a[k] + b[k] |} 14 | } 15 | 16 | func frame(a:T, b:T) returns (ret:T) 17 | { 18 | {| k: K :: a[k] - b[k] |} 19 | } 20 | 21 | func valid(a:T) returns (ret: Bool) 22 | { 23 | forall k: K :: {a[k]} a[k] >= 0 24 | } 25 | 26 | func fromSet(s: Set[K]) returns (ret:T) 27 | { 28 | {| k: K :: k in s ? 1 : 0 |} 29 | } 30 | 31 | func elem(m: T, k: K) returns (ret: Bool) 32 | { 33 | m[k] > 0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/concurrent/templates/ccm_instances.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./ccm_instances.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/templates/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/concurrent/templates/flows_ra.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./flows_ra.rav --smt-timeout 20000 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/templates/give-up.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./give-up.rav --smt-timeout 20000 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/templates/keyset_ra.rav: -------------------------------------------------------------------------------- 1 | module KeysetRA[K: Library.Type] : Library.CancellativeResourceAlgebra { 2 | rep type T = data { 3 | case prodKS(keyset: Set[K], contents: Set[K]) 4 | case topKS 5 | } 6 | 7 | val id: T = prodKS({||}, {||}); 8 | 9 | func valid(n:T) returns (ret:Bool) { 10 | n == prodKS(n.keyset, n.contents) && n.contents subseteq n.keyset 11 | } 12 | 13 | 14 | func ks_composable(a:T, b:T) returns (ret:Bool) { 15 | valid(a) && valid(b) && a.keyset ** b.keyset == {||} 16 | } 17 | 18 | func comp(a:T, b:T) returns (ret:T) { 19 | a == id ? 20 | b : 21 | (b == id ? 22 | a : 23 | (ks_composable(a, b) ? 24 | prodKS(a.keyset ++ b.keyset, a.contents ++ b.contents) : topKS) 25 | ) 26 | } 27 | 28 | func frame(a:T, b:T) returns (ret:T) { 29 | b == id ? a : 30 | (valid(a) && valid(b) && b.keyset subseteq a.keyset && b.contents subseteq a.contents ? 31 | prodKS(a.keyset -- b.keyset, a.contents -- b.contents) : topKS) 32 | } 33 | 34 | func fpuAllowed(a:T, b:T) returns (ret:Bool) { 35 | valid(a) && valid(b) && b.keyset subseteq a.keyset 36 | } 37 | } -------------------------------------------------------------------------------- /test/concurrent/templates/single-node.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./single-node.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/treiber_stack/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/concurrent/treiber_stack/treiber_stack_atomic.rav: -------------------------------------------------------------------------------- 1 | import Library.Type 2 | import Library.Option 3 | import Library.List 4 | 5 | module Stack[T: Type] { 6 | 7 | module TOption = Option[T] 8 | module TList = List[T] 9 | import TList._ 10 | import TOption._ 11 | 12 | field top: Ref 13 | field next: Ref 14 | field value: T 15 | 16 | 17 | pred list(x: Ref; xs: TList) { 18 | x == null ? 19 | xs == nil : 20 | (xs != nil && (exists tl0: Ref, q: Real :: q > 0.0 && (own(x.value, xs.head, q) && own(x.next, tl0, q) && list(tl0, xs.tail)))) 21 | } 22 | 23 | pred stack(s: Ref; xs: TList) { 24 | exists x: Ref :: own(s.top, x, 1.0) && list(x, xs) 25 | } 26 | 27 | proc push(s: Ref, x: T, implicit ghost xs: TList) 28 | atomic requires stack(s, xs) 29 | atomic ensures stack(s, cons(x, xs)) 30 | { 31 | ghost val phi := bindAU(); 32 | ghost val xs0: TList := openAU(phi); 33 | 34 | unfold stack(s); 35 | var topv := s.top; 36 | fold stack(s, xs0); 37 | 38 | abortAU(phi); 39 | 40 | var s0 : Ref; 41 | s0 := new(value: x, next: topv); 42 | 43 | ghost val xs1: TList := openAU(phi); 44 | 45 | ghost val top1: Ref; 46 | unfold stack(s)[top1 := x]; 47 | 48 | var res := cas(s.top, topv, s0); 49 | 50 | if (!res) { 51 | fold stack(s, xs1); 52 | abortAU(phi); 53 | ghost val xs2: TList := openAU(phi); 54 | push(s, x); 55 | commitAU(phi); 56 | } else { 57 | fold list(s0, cons(x, xs1))[q := 1.0]; 58 | fold stack(s, cons(x, xs1)); 59 | commitAU(phi); 60 | } 61 | } 62 | 63 | proc pop(s: Ref, implicit ghost xs: TList) 64 | returns (result: TOption) 65 | atomic requires stack(s, xs) 66 | atomic ensures 67 | xs == nil ? 68 | (stack(s, xs) && result == none) : 69 | (stack(s, xs.tail) && result == some(xs.head)) 70 | { 71 | ghost val phi := bindAU(); 72 | ghost val xs0: TList := openAU(phi); 73 | 74 | unfold stack(s); 75 | 76 | var topv := s.top; 77 | 78 | ghost val q: Real; ghost val tl0: Ref; 79 | 80 | if (topv == null) { 81 | unfold list(topv)[q := q]; 82 | fold list(topv, xs0)[q := q]; 83 | fold stack(s, xs0); 84 | commitAU(phi, none); 85 | } else { 86 | unfold list(topv)[tl0 := tl0, q := q]; 87 | fold list(topv, xs0)[q := q/2.0]; 88 | fold stack(s, xs0); 89 | abortAU(phi); 90 | } 91 | 92 | if (topv == null) { 93 | return none; 94 | } 95 | 96 | val top_next := topv.next; 97 | val top_value := topv.value; 98 | 99 | ghost val xs1: TList := openAU(phi); 100 | ghost val top1: Ref; 101 | unfold stack(s)[top1 := x]; 102 | 103 | var res := cas(s.top, topv, top_next); 104 | 105 | if (res) { 106 | unfold list(top1); 107 | fold stack(s, xs1.tail); 108 | commitAU(phi, some(top_value)); 109 | return some(top_value); 110 | } else { 111 | fold stack(s, xs1); 112 | abortAU(phi); 113 | ghost val xs2: TList := openAU(phi); 114 | val ret := pop(s); 115 | commitAU(phi, ret); 116 | 117 | return ret; 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /test/concurrent/treiber_stack/treiber_stack_atomic.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./treiber_stack_atomic.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/concurrent/treiber_stack/treiber_stack_rewritten.rav: -------------------------------------------------------------------------------- 1 | // Treiber Stack with the atomic commands manually rewritten. 2 | 3 | type IntOption = data { 4 | case none; 5 | case some(i: Int) 6 | } 7 | 8 | field head: Ref 9 | field next: Ref 10 | field value: Int 11 | 12 | type IntList = data { 13 | case nil; 14 | case cons(elem: Int, tl: IntList) 15 | } 16 | 17 | pred is_list(hd: Ref, xs: IntList) { 18 | hd == null ? 19 | xs == nil() : 20 | (xs != nil() && (exists tl0: Ref, q:Real :: q > 0.0 && (own(hd.value, xs.elem, q) && own(hd.next, tl0, q) && is_list(tl0, xs.tl)))) 21 | } 22 | 23 | pred is_stack(s: Ref, xs: IntList) { 24 | exists hd: Ref :: (is_list(hd, xs) && own(s.head, hd, 1.0)) 25 | } 26 | 27 | proc push(s: Ref, x: Int, implicit ghost xs: IntList) 28 | // atomic requires is_stack(s, xs) 29 | // atomic ensures is_stack(s, cons(x, xs)) 30 | { 31 | // var xs0: IntList := openAU(phi); 32 | var xs0: IntList; 33 | inhale is_stack(s, xs0); 34 | 35 | 36 | unfold is_stack(s, xs0); 37 | var hd: Ref := s.head; 38 | fold is_stack(s, xs0); 39 | 40 | // abortAU(phi); 41 | exhale is_stack(s, xs0); 42 | 43 | var s0 : Ref; 44 | s0 := new(value: x, next: hd); 45 | 46 | // var xs1: IntList := openAU(phi); 47 | var xs1: IntList; 48 | inhale is_stack(s, xs1); 49 | 50 | ghost var hd1: Ref; 51 | unfold is_stack(s, xs1); 52 | hd1 :| is_list(hd1, xs1) && own(s.head, hd1, 1.0); 53 | 54 | // var res := cas(s.head, hd, s0); 55 | var res: Bool; 56 | var curr_head: Ref := s.head; 57 | 58 | if (curr_head == hd) { 59 | s.(head) := s0; 60 | res := true; 61 | } else { 62 | res := false; 63 | } 64 | 65 | {! 66 | if (res) { 67 | assert 68 | (s0 == null ? 69 | cons(x, xs1) == nil() : 70 | (cons(x,xs1) != nil() && (1.0 > 0.0 && (own(s0.value, cons(x, xs1).elem, 1.0) && own(s0.next, hd1, 1.0) && is_list(hd1, cons(x, xs1).tl))))); 71 | 72 | fold is_list(s0, cons(x, xs1)); 73 | fold is_stack(s, cons(x, xs1)); 74 | // commitAU(phi); 75 | exhale is_stack(s, cons(x, xs1)); 76 | } else { 77 | fold is_stack(s, xs1); 78 | // abortAU(phi); 79 | exhale is_stack(s, xs1); 80 | } 81 | !} 82 | 83 | if (!res) push(s, x); 84 | 85 | // assert false; 86 | } 87 | 88 | proc pop(s: Ref, implicit ghost xs: IntList) 89 | returns (result: IntOption) 90 | // atomic requires is_stack(s, xs) 91 | // atomic ensures 92 | // xs == nil() ? 93 | // is_stack(s, xs) && result == none() : 94 | // is_stack(s, xs.tl) && result == some(xs.elem) 95 | { 96 | 97 | // var xs0: IntList := openAU(phi); 98 | var xs0: IntList; 99 | inhale is_stack(s, xs0); 100 | 101 | unfold is_stack(s, xs0); 102 | 103 | var hd: Ref := s.(head); 104 | 105 | {! 106 | // assert hd != null; 107 | if (hd == null) { 108 | // assert false; 109 | unfold is_list(hd, xs0); 110 | fold is_list(hd, xs0)[q := 0.0]; 111 | fold is_stack(s, xs0); 112 | // commitAU(phi, none()); 113 | var result0: IntOption := none(); 114 | exhale xs0 == nil() ? 115 | is_stack(s, xs0) && result0 == none() : 116 | is_stack(s, xs0.tl) && result0 == some(xs0.elem); 117 | } else { 118 | ghost var q:Real; 119 | ghost var tl0: Ref; 120 | unfold is_list(hd, xs0); 121 | 122 | tl0, q :| 123 | hd == null ? 124 | xs0 == nil() : 125 | (xs0 != nil() && (q > 0.0 && (own(hd.value, xs0.elem, q) && own(hd.next, tl0, q) && is_list(tl0, xs0.tl)))); 126 | 127 | assert hd == null ? 128 | xs0 == nil() : 129 | (xs0 != nil() && (q/2.0 > 0.0 && (own(hd.value, xs0.elem, q/2.0) && own(hd.next, tl0, q/2.0) && is_list(tl0, xs0.tl)))); 130 | 131 | fold is_list(hd, xs0); 132 | fold is_stack(s, xs0); 133 | // abortAU(phi); 134 | exhale is_stack(s, xs0); 135 | } 136 | !} 137 | 138 | if (hd == null) { 139 | return none(); 140 | } 141 | 142 | var hd_next: Ref := hd.next; 143 | 144 | // var xs1 := openAU(phi); 145 | var xs1: IntList; 146 | inhale is_stack(s, xs1); 147 | 148 | ghost var hd1: Ref; 149 | unfold is_stack(s, xs1); 150 | hd1 :| is_list(hd1, xs1) && own(s.head, hd1, 1.0); 151 | // var res := cas(s.head, hd, hd_next); 152 | var res: Bool; 153 | var curr_val: Ref := s.head; 154 | 155 | if (curr_val == hd) { 156 | s.head := hd_next; 157 | res := true; 158 | } else { 159 | res := false; 160 | } 161 | 162 | {! 163 | if (res) { 164 | unfold is_list(hd1, xs1); 165 | assert hd1 != null; 166 | assert xs1 != nil(); 167 | fold is_stack(s, xs1.tl); 168 | // commitAU(phi, some(hd.value)); 169 | var hd_val: Int := hd.value; 170 | var result1: IntOption := some(hd_val); 171 | exhale xs1 == nil() ? 172 | is_stack(s, xs1) && result1 == none() : 173 | is_stack(s, xs1.tl) && result1 == some(xs1.elem); 174 | } else { 175 | fold is_stack(s, xs1); 176 | // abortAU(phi); 177 | exhale is_stack(s, xs1); 178 | } 179 | 180 | !} 181 | 182 | // if (!res) {pop(s);} 183 | 184 | // else return some(hd.(value)); 185 | } 186 | -------------------------------------------------------------------------------- /test/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/iterated-star/array-max.rav: -------------------------------------------------------------------------------- 1 | /* Encoding of arrays */ 2 | 3 | interface IArray { 4 | rep type T 5 | 6 | func loc(a: T, i: Int) returns (r: Ref) 7 | func len(a: T) returns (l: Int) 8 | func first(r: Ref) returns (a: T) 9 | func second(r: Ref) returns (i: Int) 10 | 11 | auto lemma all_diff() 12 | ensures forall a:T, i: Int :: first(loc(a, i)) == a && second(loc(a, i)) == i 13 | 14 | auto lemma len_nonneg() 15 | ensures forall a:T :: len(a) >= 0 16 | } 17 | 18 | module ArrayMax[M: IArray] { 19 | field value: Int 20 | 21 | pred arr(a: M, m: Map[Int, Int]) { 22 | forall j: Int :: 0 <= j < M.len(a) ==> own(M.loc(a, j).value, m[j], 1.0) 23 | } 24 | 25 | pred is_max(i: Int, m: Map[Int, Int], u: Int) { 26 | forall j: Int :: 0 <= j && j < u ==> m[j] <= m[i] 27 | } 28 | 29 | proc max(a: M, implicit ghost m: Map[Int, Int]) 30 | returns (x: Int) 31 | requires arr(a, m) 32 | ensures arr(a, m) 33 | ensures M.len(a) == 0 ? x == -1 : (0 <= x && x < M.len(a)) 34 | ensures is_max(x, m, M.len(a)) 35 | { 36 | var z : Int; 37 | if (M.len(a) == 0) { 38 | x := -1; 39 | } else { 40 | var y: Int; 41 | x := 0; 42 | y := M.len(a) - 1; 43 | 44 | while (x != y) 45 | invariant arr(a, m) 46 | invariant 0 <= x && x <= y && y < M.len(a) 47 | invariant (forall i: Int :: 48 | (((0 <= i && i < x) || (y < i && i < M.len(a))) 49 | ==> m[i] < m[x]) || 50 | (((0 <= i && i < x) || (y < i && i < M.len(a))) 51 | ==> m[i] <= m[y]) 52 | ) 53 | { 54 | M.all_diff(); 55 | unfold arr(a,m); 56 | 57 | var tmp1 : Int := M.loc(a, x).value; 58 | var tmp2 : Int := M.loc(a, y).value; 59 | 60 | if (tmp1 <= tmp2) { 61 | x := x + 1; 62 | } else { 63 | y := y - 1; 64 | } 65 | fold arr(a,m); 66 | } 67 | } 68 | 69 | fold is_max(x, m, M.len(a)); 70 | } 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /test/iterated-star/array-max.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./array-max.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/iterated-star/binary-search.rav: -------------------------------------------------------------------------------- 1 | interface IArray { 2 | rep type T 3 | 4 | func loc(a: T, i: Int) returns (r: Ref) 5 | func len(a: T) returns (l: Int) 6 | func first(r: Ref) returns (a: T) 7 | func second(r: Ref) returns (i: Int) 8 | 9 | auto lemma all_diff() 10 | ensures forall a:T, i: Int :: first(loc(a, i)) == a && second(loc(a, i)) == i 11 | 12 | auto lemma len_nonneg() 13 | ensures forall a:T :: len(a) >= 0 14 | } 15 | 16 | module BinarySearch[M: IArray] { 17 | field value: Int 18 | 19 | pred arr(a: M, m: Map[Int, Int]) { 20 | forall j: Int :: 0 <= j <= M.len(a) ==> own(M.loc(a, j).value, m[j]) 21 | } 22 | 23 | proc binary_search(a: M, key: Int, implicit ghost m: Map[Int, Int]) returns (index: Int) 24 | requires arr(a, m) 25 | requires forall i: Int, j: Int :: (0 <= i && j < M.len(a) && i < j) ==> m[i] < m[j] 26 | ensures arr(a, m) 27 | ensures -1 <= index && index < M.len(a) 28 | ensures 0 <= index ==> m[index] == key 29 | ensures -1 == index ==> (forall i: Int :: 0 <= i && i < M.len(a) ==> m[i] != key) 30 | { 31 | var low: Int := 0; 32 | var high: Int := M.len(a); 33 | index := -1; 34 | 35 | while (low < high) 36 | invariant arr(a, m) 37 | invariant 0 <= low && low <= high && high <= M.len(a) 38 | invariant index == -1 ==> (forall i: Int :: (0 <= i && i < M.len(a) && !(low <= i && i < high)) ==> m[i] != key) 39 | invariant -1 <= index && index < M.len(a) 40 | invariant 0 <= index ==> m[index] == key 41 | invariant forall i: Int, j: Int :: (0 <= i && j < M.len(a) && i < j) ==> m[i] < m[j] 42 | { 43 | var mid: Int := (low + high) / 2; 44 | 45 | unfold arr(a, m); 46 | var mid_val := M.loc(a, mid).value; 47 | 48 | assert mid_val == m[mid]; 49 | 50 | if (mid_val < key) { 51 | low := mid + 1; 52 | } else { 53 | if (key < mid_val) { 54 | high := mid; 55 | } else { 56 | index := mid; 57 | high := mid; 58 | } 59 | } 60 | 61 | fold arr(a, m); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /test/iterated-star/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/iterated-star/dutch-flag.rav: -------------------------------------------------------------------------------- 1 | interface IArray { 2 | rep type T 3 | 4 | func loc(a: T, i: Int) returns (r: Ref) 5 | func len(a: T) returns (l: Int) 6 | func first(r: Ref) returns (a: T) 7 | func second(r: Ref) returns (i: Int) 8 | 9 | auto lemma all_diff() 10 | ensures forall a:T, i: Int :: first(loc(a, i)) == a && second(loc(a, i)) == i 11 | 12 | auto lemma len_nonneg() 13 | ensures forall a:T :: len(a) >= 0 14 | } 15 | 16 | module DutchFlag[Arr: IArray] { 17 | field value: Int; 18 | 19 | pred ordered(m: Map[Int, Int], len: Int) { 20 | forall i: Int, j: Int :: 0 <= i && i < j && j < len ==> m[i] <= m[j] 21 | } 22 | 23 | pred access(a: Arr, implicit ghost m: Map[Int, Int]) { 24 | forall i: Int :: 0 <= i && i < Arr.len(a) ==> own(Arr.loc(a, i).value, m[i], 1.0) 25 | } 26 | 27 | proc dutchFlag(a: Arr, implicit ghost m: Map[Int, Int]) 28 | returns (ghost m2: Map[Int, Int]) 29 | requires access(a,m) 30 | requires forall i: Int :: 0 <= i && i < Arr.len(a) ==> m[i] == 0 || m[i] == 1 || m[i] == 2 31 | ensures access(a,m2) && ordered(m2, Arr.len(a)) 32 | { 33 | var unsorted : Int := 0; 34 | var white : Int := 0; 35 | var blue : Int := Arr.len(a); 36 | m2 := m; 37 | 38 | while (unsorted < blue) 39 | invariant access(a, m2) 40 | invariant 0 <= white && white <= unsorted && unsorted <= blue && blue <= Arr.len(a) 41 | invariant forall i: Int :: 0 <= i && i < Arr.len(a) ==> m2[i] == 0 || m2[i] == 1 || m2[i] == 2 42 | invariant forall i : Int :: 0 <= i && i < white ==> m2[i] == 0 43 | invariant forall i : Int :: white <= i && i < unsorted ==> m2[i] == 1 44 | invariant forall i : Int :: blue <= i && i < Arr.len(a) ==> m2[i] == 2 45 | { 46 | unfold access(a, m2); 47 | var tmp : Int := Arr.loc(a,unsorted).value; 48 | 49 | if (tmp == 1) { 50 | unsorted := unsorted + 1; 51 | } else if (tmp == 0) { 52 | var tmp1 : Int := Arr.loc(a,white).value; 53 | Arr.loc(a,unsorted).value := tmp1; 54 | var tmp2 : Int := Arr.loc(a,white).value; 55 | m2 := m2[unsorted := tmp2]; 56 | 57 | Arr.loc(a,white).value := tmp; 58 | m2 := m2[white := tmp]; 59 | 60 | white := white + 1; 61 | unsorted := unsorted + 1; 62 | } else { 63 | var tmp1 : Int := Arr.loc(a,blue - 1).value; 64 | Arr.loc(a,unsorted).value := tmp1; 65 | 66 | var tmp2 : Int := Arr.loc(a,blue - 1).value; 67 | m2 := m2[unsorted := tmp2]; 68 | 69 | blue := blue - 1; 70 | Arr.loc(a,blue).value := tmp; 71 | m2 := m2[blue := tmp ]; 72 | } 73 | fold access(a, m2); 74 | } 75 | 76 | fold ordered(m2, Arr.len(a)); 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /test/iterated-star/dutch-flag.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./dutch-flag.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/iterated-star/graph_marking_buggy.rav: -------------------------------------------------------------------------------- 1 | field left: Ref 2 | field right: Ref 3 | field is_marked: Bool 4 | 5 | auto pred invar(nodes: Set[Ref], lMap: Map[Ref, Ref], rMap: Map[Ref, Ref], mMap: Map[Ref, Bool]) { 6 | !(null in nodes) 7 | && (forall n: Ref :: n in nodes ==> own(n.left, lMap[n])) 8 | && (forall n: Ref :: n in nodes ==> own(n.right, rMap[n])) 9 | && (forall n: Ref :: n in nodes ==> (own(n.is_marked, mMap[n]))) 10 | && (forall n: Ref :: 11 | n in nodes && lMap[n] != null ==> lMap[n] in nodes) 12 | && (forall n: Ref :: 13 | n in nodes && rMap[n] != null ==> rMap[n] in nodes) 14 | } 15 | 16 | proc trav_rec(nodes: Set[Ref], node: Ref, implicit ghost lMap: Map[Ref, Ref], implicit ghost rMap: Map[Ref, Ref], implicit ghost mMap: Map[Ref, Bool]) 17 | returns (ghost lMap2: Map[Ref, Ref], ghost rMap2: Map[Ref, Ref], ghost mMap2: Map[Ref, Bool]) 18 | requires node in nodes && invar(nodes, lMap, rMap, mMap) 19 | requires !mMap[node] 20 | 21 | ensures node in nodes && invar(nodes, lMap2, rMap2, mMap2) 22 | 23 | /* We do not unmark nodes. This allows us to prove that the current node will be marked. */ 24 | ensures forall n: Ref :: n in nodes ==> (mMap[n] ==> mMap2[n]) 25 | ensures mMap2[node] 26 | 27 | /* The nodes are not being modified. */ 28 | ensures forall n: Ref :: n in nodes ==> (lMap2[n] == lMap[n]) 29 | ensures forall n: Ref :: n in nodes ==> (rMap2[n] == rMap[n]) 30 | 31 | /* Propagation of the marker. */ 32 | ensures forall n: Ref :: 33 | n in nodes ==> (!mMap[n] && mMap2[n] ==> (lMap2[n] == null || mMap2[lMap2[n]])) 34 | ensures forall n: Ref :: 35 | n in nodes ==> (!mMap[n] && mMap2[n] ==> (rMap2[n] == null || mMap2[rMap2[n]])) 36 | { 37 | lMap2 := lMap; 38 | rMap2 := rMap; 39 | mMap2 := mMap; 40 | 41 | node.is_marked := true; 42 | mMap2 := mMap2[node := true]; 43 | var node_left := node.left; 44 | 45 | if (node_left != null) { 46 | var node_left_marked := node_left.is_marked; 47 | if (!node_left_marked) { 48 | assert node_left in nodes; 49 | lMap2, rMap2, mMap2 := trav_rec(nodes, node_left, lMap2, rMap2, mMap2); 50 | } 51 | } 52 | 53 | 54 | var node_right := node.right; 55 | if (node_right != null) { 56 | var node_right_marked := node_right.is_marked; 57 | if (!node_right_marked) { 58 | assert node_right in nodes; 59 | lMap2, rMap2, mMap2 := trav_rec(nodes, node_right, lMap2, rMap2, mMap2); 60 | } 61 | } 62 | } 63 | 64 | proc client_success() { 65 | var a: Ref; a := new(left: null, right: null, is_marked: false); 66 | var b: Ref; b := new(left: null, right: null, is_marked: false); 67 | 68 | a.left := b; a.right := null; 69 | b.left := null; b.right := a; 70 | 71 | var nodes: Set[Ref] := {| a, b |}; 72 | 73 | ghost var lMap: Map[Ref, Ref] := {| r: Ref :: r == a ? b : null |}; 74 | ghost var rMap: Map[Ref, Ref] := {| r: Ref :: r == b ? a : null |}; 75 | ghost var mMap: Map[Ref, Bool] := {| r: Ref :: false |}; 76 | 77 | assert forall n: Ref :: n in nodes ==> !mMap[n]; 78 | 79 | ghost var lMap2: Map[Ref, Ref]; 80 | ghost var rMap2: Map[Ref, Ref]; 81 | ghost var mMap2: Map[Ref, Bool]; 82 | 83 | lMap2, rMap2, mMap2 := trav_rec(nodes, a, lMap, rMap, mMap); 84 | 85 | assert forall n: Ref :: n in nodes ==> mMap2[n]; 86 | } 87 | 88 | proc client_failure() { 89 | var a: Ref; a := new(left: null, right: null, is_marked: false); 90 | var b: Ref; b := new(left: null, right: null, is_marked: false); 91 | 92 | a.left := a; a.right := a; 93 | b.left := a; b.right := a; 94 | 95 | var nodes: Set[Ref] := {| a, b |}; 96 | 97 | ghost var lMap: Map[Ref, Ref] := {| r: Ref :: r == a ? a : (r == b ? a : null) |}; 98 | ghost var rMap: Map[Ref, Ref] := {| r: Ref :: r == a ? a : (r == b ? a : null) |}; 99 | ghost var mMap: Map[Ref, Bool] := {| r: Ref :: false |}; 100 | 101 | assert forall n: Ref :: n in nodes ==> !mMap[n]; 102 | 103 | ghost var lMap2: Map[Ref, Ref]; 104 | ghost var rMap2: Map[Ref, Ref]; 105 | ghost var mMap2: Map[Ref, Bool]; 106 | 107 | lMap2, rMap2, mMap2 := trav_rec(nodes, a, lMap, rMap, mMap); 108 | 109 | /* The assertion is expected to fail because b is in nodes, but b is not reachable from a */ 110 | 111 | assert forall n: Ref :: n in nodes ==> mMap2[n]; 112 | } -------------------------------------------------------------------------------- /test/iterated-star/graph_marking_correct.rav: -------------------------------------------------------------------------------- 1 | field left: Ref 2 | field right: Ref 3 | field is_marked: Bool 4 | 5 | auto pred invar(nodes: Set[Ref], lMap: Map[Ref, Ref], rMap: Map[Ref, Ref], mMap: Map[Ref, Bool]) { 6 | !(null in nodes) 7 | && (forall n: Ref :: n in nodes ==> own(n.left, lMap[n])) 8 | && (forall n: Ref :: n in nodes ==> own(n.right, rMap[n])) 9 | && (forall n: Ref :: n in nodes ==> (own(n.is_marked, mMap[n]))) 10 | && (forall n: Ref :: 11 | n in nodes && lMap[n] != null ==> lMap[n] in nodes) 12 | && (forall n: Ref :: 13 | n in nodes && rMap[n] != null ==> rMap[n] in nodes) 14 | } 15 | 16 | proc trav_rec(nodes: Set[Ref], node: Ref, implicit ghost lMap: Map[Ref, Ref], implicit ghost rMap: Map[Ref, Ref], implicit ghost mMap: Map[Ref, Bool]) 17 | returns (ghost lMap2: Map[Ref, Ref], ghost rMap2: Map[Ref, Ref], ghost mMap2: Map[Ref, Bool]) 18 | requires node in nodes && invar(nodes, lMap, rMap, mMap) 19 | requires !mMap[node] 20 | 21 | ensures node in nodes && invar(nodes, lMap2, rMap2, mMap2) 22 | 23 | /* We do not unmark nodes. This allows us to prove that the current node will be marked. */ 24 | ensures forall n: Ref :: n in nodes ==> (mMap[n] ==> mMap2[n]) 25 | ensures mMap2[node] 26 | 27 | /* The nodes are not being modified. */ 28 | ensures forall n: Ref :: n in nodes ==> (lMap2[n] == lMap[n]) 29 | ensures forall n: Ref :: n in nodes ==> (rMap2[n] == rMap[n]) 30 | 31 | /* Propagation of the marker. */ 32 | ensures forall n: Ref :: 33 | n in nodes ==> (!mMap[n] && mMap2[n] ==> (lMap2[n] == null || mMap2[lMap2[n]])) 34 | ensures forall n: Ref :: 35 | n in nodes ==> (!mMap[n] && mMap2[n] ==> (rMap2[n] == null || mMap2[rMap2[n]])) 36 | { 37 | lMap2 := lMap; 38 | rMap2 := rMap; 39 | mMap2 := mMap; 40 | 41 | node.is_marked := true; 42 | mMap2 := mMap2[node := true]; 43 | var node_left := node.left; 44 | 45 | if (node_left != null) { 46 | var node_left_marked := node_left.is_marked; 47 | if (!node_left_marked) { 48 | assert node_left in nodes; 49 | lMap2, rMap2, mMap2 := trav_rec(nodes, node_left, lMap2, rMap2, mMap2); 50 | } 51 | } 52 | 53 | 54 | var node_right := node.right; 55 | if (node_right != null) { 56 | var node_right_marked := node_right.is_marked; 57 | if (!node_right_marked) { 58 | assert node_right in nodes; 59 | lMap2, rMap2, mMap2 := trav_rec(nodes, node_right, lMap2, rMap2, mMap2); 60 | } 61 | } 62 | } 63 | 64 | proc client_success() { 65 | var a: Ref; a := new(left: null, right: null, is_marked: false); 66 | var b: Ref; b := new(left: null, right: null, is_marked: false); 67 | 68 | a.left := b; a.right := null; 69 | b.left := null; b.right := a; 70 | 71 | var nodes: Set[Ref] := {| a, b |}; 72 | 73 | ghost var lMap: Map[Ref, Ref] := {| r: Ref :: r == a ? b : null |}; 74 | ghost var rMap: Map[Ref, Ref] := {| r: Ref :: r == b ? a : null |}; 75 | ghost var mMap: Map[Ref, Bool] := {| r: Ref :: false |}; 76 | 77 | assert forall n: Ref :: n in nodes ==> !mMap[n]; 78 | 79 | ghost var lMap2: Map[Ref, Ref]; 80 | ghost var rMap2: Map[Ref, Ref]; 81 | ghost var mMap2: Map[Ref, Bool]; 82 | 83 | lMap2, rMap2, mMap2 := trav_rec(nodes, a, lMap, rMap, mMap); 84 | 85 | assert forall n: Ref :: n in nodes ==> mMap2[n]; 86 | } 87 | 88 | proc client_failure() { 89 | var a: Ref; a := new(left: null, right: null, is_marked: false); 90 | var b: Ref; b := new(left: null, right: null, is_marked: false); 91 | 92 | a.left := a; a.right := a; 93 | b.left := a; b.right := a; 94 | 95 | var nodes: Set[Ref] := {| a, b |}; 96 | 97 | ghost var lMap: Map[Ref, Ref] := {| r: Ref :: r == a ? a : (r == b ? a : null) |}; 98 | ghost var rMap: Map[Ref, Ref] := {| r: Ref :: r == a ? a : (r == b ? a : null) |}; 99 | ghost var mMap: Map[Ref, Bool] := {| r: Ref :: false |}; 100 | 101 | assert forall n: Ref :: n in nodes ==> !mMap[n]; 102 | 103 | ghost var lMap2: Map[Ref, Ref]; 104 | ghost var rMap2: Map[Ref, Ref]; 105 | ghost var mMap2: Map[Ref, Bool]; 106 | 107 | lMap2, rMap2, mMap2 := trav_rec(nodes, a, lMap, rMap, mMap); 108 | 109 | /* The assertion is expected to fail because b is in nodes, but b is not reachable from a */ 110 | 111 | // assert forall n: Ref :: n in nodes ==> mMap2[n]; 112 | } -------------------------------------------------------------------------------- /test/rec-preds/dune: -------------------------------------------------------------------------------- 1 | (cram 2 | (deps 3 | %{project_root}/bin/raven.exe 4 | %{project_root}/lib/library/resource_algebra.rav 5 | (:rav 6 | (glob_files_rec *.rav)))) 7 | -------------------------------------------------------------------------------- /test/rec-preds/list.rav: -------------------------------------------------------------------------------- 1 | module List { 2 | 3 | field next: Ref 4 | 5 | pred lseg(x: Ref, y: Ref) { 6 | x == y ? true : 7 | (exists z: Ref :: own(x.next, z, 1.0) && lseg(z, y)) 8 | } 9 | 10 | lemma append_tail(x: Ref, y: Ref, z: Ref) 11 | requires lseg(x, y) && own(y.next, z, 1.0) 12 | ensures lseg(x, z) 13 | { 14 | unfold lseg(x, y); 15 | if (x == y) { 16 | fold lseg(z, z); 17 | fold lseg(y, z); 18 | } else { 19 | val xnext: Ref := x.next; 20 | append_tail(xnext, y, z); 21 | fold lseg(x, z); 22 | } 23 | } 24 | 25 | proc traverse(x: Ref) 26 | requires lseg(x, null) 27 | ensures lseg(x, null) 28 | { 29 | var curr: Ref := x; 30 | fold lseg(x, curr); 31 | while (curr != null) 32 | invariant lseg(x, curr) && lseg(curr, null) 33 | { 34 | unfold lseg(curr, null); 35 | ghost var old_curr: Ref := curr; 36 | curr := curr.next; 37 | append_tail(x, old_curr, curr); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/rec-preds/list.t: -------------------------------------------------------------------------------- 1 | $ dune exec -- raven --shh ./list.rav 2 | Verification successful. 3 | -------------------------------------------------------------------------------- /test/rec-preds/list_predicates_wip.rav: -------------------------------------------------------------------------------- 1 | // No null values 2 | // No support for implications outside of iterated star 3 | // Evaluate the new command 4 | 5 | field key: Int 6 | field next: Ref 7 | 8 | // try insertion with this 9 | pred list(start: Ref, end: Ref, nmap: Map[Ref, Ref]) { 10 | (start == end) ? true : 11 | (own(start.next, nmap[start], 1.0) && list(nmap[start], end, nmap)) 12 | } 13 | 14 | proc append(x: Ref, y: Ref, z: Ref, nmap: Map[Ref, Ref]) 15 | requires list(x, y, nmap) 16 | requires list(y, z, nmap) 17 | ensures list(x, z, nmap) 18 | { 19 | if (x != y) { 20 | unfold list(x,y, nmap); 21 | var x_next: Ref = x.next; 22 | append(x_next, y, z, nmap); 23 | assert list(x_next, z, nmap); 24 | fold list(x, z, nmap); 25 | // assert false; 26 | } 27 | // assert false; 28 | } 29 | 30 | proc deque(x: Ref, y: Ref, nmap: Map[Ref, Ref]) 31 | returns (xn: Ref) 32 | requires list(x, y, nmap) 33 | requires x != y 34 | ensures list(xn, y, nmap) 35 | { 36 | unfold list(x, y, nmap); 37 | xn := x.next; 38 | } 39 | 40 | proc insert(x: Ref, y: Ref, z: Ref, n: Ref, nmap: Map[Ref, Ref]) 41 | returns (nmap1: Map[Ref, Ref]) 42 | requires list(x, y, nmap) 43 | requires own(n.next, nmap[n], 1.0) 44 | requires n != y 45 | ensures list(n, y, nmap1) 46 | ensures nmap1[n] == x 47 | ensures forall a: Ref :: a != n ==> nmap1[a] == nmap[a] 48 | { 49 | n.next := x; 50 | nmap1 := nmap[n := x]; 51 | // nmap1[n] := x; 52 | 53 | assert 54 | (n == y) ? true : 55 | (own(n.next, nmap1[n], 1.0) && list(nmap1[n], y, nmap1)); 56 | fold list(n, y, nmap1); 57 | } 58 | 59 | // pred list_seg(start: Ref, end: Ref, i: Int, j: Int, l: Map[Int, Int], nmap: Map[Ref, Ref], kmap: Map[Ref, Int]) { 60 | // ((start == end) ? true : 61 | // (own(start.next, nmap[start], 1.0) && own(start.key, kmap[start], 1.0) 62 | // && l[i] == kmap[start] && list_seg(nmap[start], end, i+1, j, l, nmap, kmap))) 63 | // } 64 | 65 | // proc append2(x: Ref, y: Ref, z: Ref, l1: Int, l2: Int, l3: Int, ls: Map[Int, Int], nmap: Map[Ref, Ref], kmap: Map[Ref, Int]) 66 | // requires list_seg(x, y, l1, l2, ls, nmap, kmap) 67 | // requires list_seg(y, z, l2, l3, ls, nmap, kmap) 68 | // ensures list_seg(x, z, l1, l3, ls, nmap, kmap) 69 | // { 70 | // if (x != y) { 71 | // unfold list_seg(x, y, l1, l2, ls, nmap, kmap); 72 | // append2(x.next, y, z, l1+1, l2, l3, ls, nmap, kmap); 73 | 74 | // assert list_seg(x.next, z, l1+1, l3, ls, nmap, kmap); 75 | // fold list_seg(x, z, l1, l3, ls, nmap, kmap); 76 | // // assert false; 77 | // } 78 | 79 | // // assert false; 80 | 81 | // } 82 | 83 | // proc deque(x: Ref, y: Ref, i: Int, j: Int, l: Map[Int, Int], nmap: Map[Ref, Ref], kmap: Map[Ref, Int]) 84 | // returns (xn: Ref) 85 | // requires (x != y) 86 | // requires list_seg(x, y, i, j, l, nmap, kmap) 87 | // ensures list_seg(xn, y, i+1, j, l, nmap, kmap) 88 | // { 89 | // unfold list_seg(x, y, i, j, l, nmap, kmap); 90 | // xn := x.next; 91 | // // assert false; 92 | // } 93 | 94 | // proc insert(x: Ref, y: Ref, i: Int, j: Int, l: Map[Int, Int], nmap: Map[Ref, Ref], kmap: Map[Ref, Int], k : Int) 95 | // returns (l1: Map[Int, Int], idx: Int, nmap1: Map[Ref, Ref], kmap1: Map[Ref, Int]) 96 | // requires (x != y) 97 | // requires list_seg(x, y, i, j, l, nmap, kmap) 98 | // requires forall i1 : Int :: i <= i1 < j ==> l[i1] <= l[i1+1] 99 | // requires kmap[x] < k <= kmap[y] 100 | // ensures i < idx <= j 101 | // ensures list_seg(x, y, i, j+1, l1, nmap1, kmap1) 102 | // ensures l1[idx] == k 103 | // ensures forall i1 : Int :: i <= i1 < idx ==> l1[i1] == l[i] 104 | // ensures forall i1 : Int :: idx < i1 <= j+1 ==> l1[i1] == l[i-1] 105 | // { 106 | // var prev : Ref; 107 | // var curr : Ref; 108 | // var currkey : Int; 109 | 110 | // prev := x; 111 | // curr := x; 112 | // unfold list_seg(x, y, i, j, l, nmap, kmap); 113 | // currkey := curr.key; 114 | // idx := i; 115 | 116 | // fold list_seg(x, prev, i, idx, l, nmap, kmap); 117 | // fold list_seg(curr, y, idx, j, l, nmap, kmap); 118 | 119 | // while (currkey < k) 120 | // invariant list_seg(x, prev, i, idx, l, nmap, kmap) 121 | // invariant list_seg(curr, y, idx, j, l, nmap, kmap) 122 | // invariant curr != y 123 | // { 124 | // prev := curr; 125 | 126 | // unfold list_seg(curr, y, idx, j, l, nmap, kmap); 127 | 128 | // curr := curr.next; 129 | // currkey := curr.key; 130 | 131 | // idx := idx + 1; 132 | // } 133 | 134 | // var n: Ref; 135 | // n := new(key: k, next: curr); 136 | // prev.next := n; 137 | 138 | // } -------------------------------------------------------------------------------- /test/rec-preds/tree_delete.rav: -------------------------------------------------------------------------------- 1 | field v: Int 2 | field l: Ref 3 | field r: Ref 4 | 5 | pred tree(x: Ref) { 6 | x == null 7 | ? true 8 | : (exists vv: Int, vl: Ref, vr: Ref :: own(x.v, vv) 9 | && own(x.l, vl) && tree(vl) 10 | && own(x.r, vr) && tree(vr)) 11 | } 12 | 13 | pred tree_hole(x: Ref, y: Ref) { 14 | x == y 15 | ? true 16 | : (exists vv: Int, vl: Ref, vr: Ref :: own(x.v, vv) 17 | && own(x.l, vl) && tree_hole(vl, y) 18 | && own(x.r, vr) && tree(vr)) 19 | } 20 | 21 | lemma compose_tree(x: Ref, y: Ref) 22 | requires tree_hole(x, y) && tree(y) 23 | ensures tree(x) 24 | { 25 | unfold tree_hole(x, y); 26 | if (x != y) { 27 | var xl := x.l; 28 | compose_tree(xl, y); 29 | fold tree(x); 30 | } 31 | } 32 | 33 | lemma compose_hole(x: Ref, y: Ref, z: Ref) 34 | requires tree_hole(x, y) && tree_hole(y, z) 35 | ensures tree_hole(x, z) 36 | { 37 | unfold tree_hole(x, y); 38 | if (x != y) { 39 | var xl := x.l; 40 | compose_hole(xl, y, z); 41 | fold tree_hole(x, z); 42 | } 43 | } 44 | 45 | 46 | proc tree_delete_min(x: Ref) returns (z: Ref) 47 | requires x != null && tree(x) 48 | ensures tree(z) 49 | { 50 | var p: Ref := x; 51 | 52 | unfold tree(p); 53 | var pl := p.l; 54 | 55 | if (pl == null) { 56 | z := p.r; 57 | } else { 58 | fold tree_hole(x, p); 59 | var abort := false; 60 | while (!abort) 61 | invariant p != null && pl != null && own(p.l, pl) && tree(pl) 62 | invariant exists pr: Ref :: own(p.r, pr) && tree(pr) 63 | invariant exists pv: Int :: own(p.v, pv) 64 | invariant tree_hole(x, p) 65 | { 66 | unfold tree(pl); 67 | var pll := pl.l; 68 | 69 | if (pll != null) { 70 | var oldp := p; 71 | p := pl; 72 | pl := pll; 73 | fold tree_hole(p, p); 74 | fold tree_hole(oldp, p); 75 | compose_hole(x, oldp, p); 76 | } else { 77 | fold tree(pl); 78 | abort := true; 79 | } 80 | 81 | } 82 | 83 | unfold tree(pl); 84 | 85 | var plr := pl.r; 86 | p.l := plr; 87 | 88 | z := x; 89 | fold tree(p); 90 | compose_tree(x, p); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | 16 nov, 2024: 2 | - [x] fix ident sanitization bug identified by Lucas. 3 | - [x] move statistics counting to after type-checking for greater accuracy. 4 | 5 | 22 oct, 2024: 6 | - [x] fix bug with existenials occuring in other variables' skolem function 7 | + [x] rewrite the entire elim_a functionality. 8 | + [x] fix issue with order of adding vs typechecking of mutually dependent skolems 9 | - [x] add another assertion for ISC that quantifies over the actual value, not just location 10 | - [x] exhale order of clause witness computation bug 11 | 12 | - [x] formalize masks 13 | - [x] introduce fold existential witness notation 14 | 15 | - [x] move injectivity check outside. 16 | - reorder rewrite passes to do inj checks for preds before rewriting fold/unfold 17 | + maybe by adding new lemmas 18 | - sweep to add default triggers for every Quant 19 | + fix missing triggers in all `Expr.mk_binder` calls 20 | 21 | - [x] add forks 22 | - toy around with preds as macros 23 | 24 | 25 | 26 | Type-checking: 27 | - Ensure that return variables are not allowed in pre-conditions 28 | - Check that openAU, commitAU having right number of arguments 29 | - Check that assertion expressions having the right format -- conditionals in ternary expr being pure, etc 30 | - Ensure that return variables of functions are not used in the function body 31 | - Ensure that predicates don't have implicit ghost args 32 | - Ensure that left-hand side of bindAU is well-typed (number of vars matches number of implicit args; types match, etc.) 33 | 34 | - Implement mask computation to check interface <-> module compatibility 35 | - Improve expression matching algorithm 36 | - Revamp witness computation code 37 | 38 | - [x] Fix `return proc()` stmts 39 | - [x] Allow parsing of `map[m1][m2]` expressions 40 | (Thomas did implement a fix for this, but needs review) 41 | 42 | - Parse field reads/writes/cas/fpu separately 43 | - Allow types to be used as modules implementing Library.Type 44 | 45 | 46 | 47 | === 48 | 49 | - [x] Fix dependency analysis wrt auto lemmas 50 | - [x] Investigate spurious "unknown"s in the middle of log files -------------------------------------------------------------------------------- /tree_delete.rav: -------------------------------------------------------------------------------- 1 | field v: Int 2 | field l: Ref 3 | field r: Ref 4 | 5 | pred tree(x: Ref) { 6 | x == null 7 | ? true 8 | : (exists vv: Int, vl: Ref, vr: Ref :: own(x.v, vv) 9 | && own(x.l, vl) && tree(vl) 10 | && own(x.r, vr) && tree(vr)) 11 | } 12 | 13 | pred tree_hole(x: Ref, y: Ref) { 14 | x == y 15 | ? true 16 | : (exists vv: Int, vl: Ref, vr: Ref :: own(x.v, vv) 17 | && own(x.l, vl) && tree_hole(vl, y) 18 | && own(x.r, vr) && tree(vr)) 19 | } 20 | 21 | lemma compose_tree(x: Ref, y: Ref) 22 | requires tree_hole(x, y) && tree(y) 23 | ensures tree(x) 24 | { 25 | unfold tree_hole(x, y); 26 | if (x != y) { 27 | var xl := x.l; 28 | compose_tree(xl, y); 29 | fold tree(x); 30 | } 31 | } 32 | 33 | lemma compose_hole(x: Ref, y: Ref, z: Ref) 34 | requires tree_hole(x, y) && tree_hole(y, z) 35 | ensures tree_hole(x, z) 36 | { 37 | unfold tree_hole(x, y); 38 | if (x != y) { 39 | var xl := x.l; 40 | compose_hole(xl, y, z); 41 | fold tree_hole(x, z); 42 | } 43 | } 44 | 45 | 46 | proc tree_delete_min(x: Ref) returns (z: Ref) 47 | requires x != null && tree(x) 48 | ensures tree(z) 49 | { 50 | var p: Ref := x; 51 | 52 | unfold tree(p); 53 | var pl := p.l; 54 | 55 | if (pl == null) { 56 | z := p.r; 57 | } else { 58 | fold tree_hole(x, p); 59 | var abort := true; 60 | while (!abort) 61 | invariant p != null && pl != null && own(p.l, pl) && tree(pl) 62 | invariant exists pr: Ref :: own(p.r, pr) && tree(pr) 63 | invariant exists pv: Int :: own(p.v, pv) 64 | invariant tree_hole(x, p) 65 | { 66 | unfold tree(pl); 67 | var pll := pl.l; 68 | 69 | if (pll != null) { 70 | var oldp := p; 71 | p := pl; 72 | pl := pll; 73 | fold tree_hole(p, p); 74 | fold tree_hole(oldp, p); 75 | compose_hole(x, oldp, p); 76 | } else { 77 | fold tree(pl); 78 | abort := true; 79 | } 80 | 81 | } 82 | 83 | unfold tree(pl); 84 | 85 | var plr := pl.r; 86 | p.l := plr; 87 | 88 | z := x; 89 | fold tree(p); 90 | compose_tree(x, p); 91 | } 92 | } 93 | --------------------------------------------------------------------------------