From 60a669d1b545e1bda7bddabd5e8d5bfa08f0464b Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 14 Feb 2025 14:45:02 -0500 Subject: [PATCH 001/158] Nits in docs --- docs/README.md | 15 +++++++-------- docs/getting-started/tutorials/basic-usage.md | 8 ++------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7bf01865..5fe0c4f5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,13 +5,12 @@ Pierce, and Cole Schlesinger, with contributions from Elizbeth Austell._ ??? info "BibTeX" ``` - @misc{cn-tutorial, - author = {Christopher Pulte and Benjamin C. Pierce and Cole Schlesinger and Elizabeth Austell}, - title = {{CN tutorial}}, - howpublished = "\url{https://rems-project.github.io/cn-tutorial/}", - year = {2024}, - note = "[Online; accessed 26-October-2024]" - } + @misc{cn-tutorial, + author = {Christopher Pulte and Benjamin C. Pierce and Cole Schlesinger and Elizabeth Austell}, + title = {{CN Tutorial}}, + howpublished = "\url{https://rems-project.github.io/cn-tutorial/}", + year = {2025}, + } ``` CN is an extension of the C programming language for testing and verifying the @@ -67,7 +66,7 @@ appreciated! ## Origins and papers CN was first described in [CN: Verifying Systems C Code with Separation-Logic Refinement Types](https://dl.acm.org/doi/10.1145/3571194) by Christopher Pulte, Dhruv C. Makwana, Thomas Sewell, Kayvan Memarian, Peter Sewell, and Neel Krishnaswami, in POPL 2023. -The Fulminate system for runtime testing of CN specifications was first described in [Fulminate: Testing CN Separation-Logic Specifications in C](http://www.cl.cam.ac.uk/users/pes20/cn-testing-popl2025.pdf), by Rini Banerjee, Kayvan Memarian, Dhruv Makwana, Christopher Pulte, Neel Krishnaswami, and Peter Sewell, in POPL 2025. +The Fulminate system for runtime testing of CN specifications was first described in [Fulminate: Testing CN Separation-Logic Specifications in C](http://www.cl.cam.ac.uk/users/pes20/cn-testing-popl2025.pdf), by Rini Banerjee, Kayvan Memarian, Dhruv Makwana, Christopher Pulte, Neel Krishnaswami, and Peter Sewell, in POPL 2025. To accurately handle the complex semantics of C, CN builds on the [Cerberus semantics for C](https://github.com/rems-project/cerberus/). Some of the examples in this tutorial are adapted from Arthur Charguéraud’s excellent [Separation Logic Foundations](https://softwarefoundations.cis.upenn.edu) textbook, and one of the case studies is based on an diff --git a/docs/getting-started/tutorials/basic-usage.md b/docs/getting-started/tutorials/basic-usage.md index 0db7e305..a353306b 100644 --- a/docs/getting-started/tutorials/basic-usage.md +++ b/docs/getting-started/tutorials/basic-usage.md @@ -38,9 +38,7 @@ solutions/add_0.c In detail: -- Function specifications are given using special `/*@ ... @*/` comments, placed in-between the function argument list and the function body. - - +- Function specifications are given using special `/*@ ... @*/` comments, placed in-between the function argument list and the function body. - The keyword `requires` starts the precondition, a list of one or more CN conditions separated by semicolons. @@ -48,9 +46,7 @@ In detail: - `let Sum = (i64) x + (i64) y` is a let-binding, which defines `Sum` as the value `(i64) x + (i64) y` in the remainder of the function specification. -- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. - - +- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. - To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. From 3989db503d05ff3c024d45ed2f14c418a9e75e46 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 17 Feb 2025 12:07:10 -0500 Subject: [PATCH 002/158] Add testing READMEs from main repo Also moves verification tutorial to its own folder and makes a new one for testing --- docs/README.md | 2 +- docs/getting-started/installation.md | 4 +- docs/getting-started/tutorials/README.md | 22 +++++--- .../tutorials/testing/FULMINATE_README.md | 47 +++++++++++++++++ .../tutorials/testing/overview.md | 48 ++++++++++++++++++ .../allocating-and-deallocating-memory.md | 0 .../{ => verification}/arrays-and-loops.md | 0 .../{ => verification}/basic-usage.md | 0 .../{ => verification}/defining-predicates.md | 0 .../{ => verification}/external-lemmas.md | 0 .../{ => verification}/images/0.error.png | Bin .../tutorials/{ => verification}/lists.md | 0 .../ownership-of-compound-objects.md | 0 .../pointers-and-simple-ownership.md | 0 mkdocs.yml | 19 ++++--- 15 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 docs/getting-started/tutorials/testing/FULMINATE_README.md create mode 100644 docs/getting-started/tutorials/testing/overview.md rename docs/getting-started/tutorials/{ => verification}/allocating-and-deallocating-memory.md (100%) rename docs/getting-started/tutorials/{ => verification}/arrays-and-loops.md (100%) rename docs/getting-started/tutorials/{ => verification}/basic-usage.md (100%) rename docs/getting-started/tutorials/{ => verification}/defining-predicates.md (100%) rename docs/getting-started/tutorials/{ => verification}/external-lemmas.md (100%) rename docs/getting-started/tutorials/{ => verification}/images/0.error.png (100%) rename docs/getting-started/tutorials/{ => verification}/lists.md (100%) rename docs/getting-started/tutorials/{ => verification}/ownership-of-compound-objects.md (100%) rename docs/getting-started/tutorials/{ => verification}/pointers-and-simple-ownership.md (100%) diff --git a/docs/README.md b/docs/README.md index 5fe0c4f5..84186c6e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -44,7 +44,7 @@ appreciated! Check out the *Basic Usage* tutorial to write, test, and verify your first spec - [:octicons-arrow-right-24: Basic Usage](getting-started/tutorials/basic-usage.md) + [:octicons-arrow-right-24: Basic Usage](getting-started/tutorials/verification/basic-usage.md) - :material-format-font:{ .lg .middle } __Tutorials__ diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index d7eecbd8..330cbdf4 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -4,7 +4,9 @@ To fetch and install CN, visit the [Cerberus repository](https://github.com/rems Once the installation is completed, type `cn --help` in your terminal to ensure CN is installed and found by your system. This should print the list of available options CN can be executed with. -To apply CN to a C file, run `cn verify CFILE`. +To use CN to verify a C file, run `cn verify CFILE`. + +To use CN to test a C file, run `cn test CFILE`. Install the [language server](https://github.com/GaloisInc/VERSE-Toolchain/tree/main/cn-lsp/server) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 18f6f176..34ee50b0 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -17,14 +17,20 @@ from [here](link:exercises.zip). ## Tutorials -- [Basic usage](basic-usage.md) -- [Pointers and simple ownership](pointers-and-simple-ownership.md) -- [Ownership of compound objects](ownership-of-compound-objects.md) -- [Arrays and loops](arrays-and-loops.md) -- [Defining predicates](defining-predicates.md) -- [Allocating and deallocating memory](allocating-and-deallocating-memory.md) -- [Lists](lists.md) -- [Working with external lemmas](external-lemmas.md) +### Testing + +- [Overview](testing/overview.md) + +### Verification + +- [Basic usage](verification/basic-usage.md) +- [Pointers and simple ownership](verification/pointers-and-simple-ownership.md) +- [Ownership of compound objects](verification/ownership-of-compound-objects.md) +- [Arrays and loops](verification/arrays-and-loops.md) +- [Defining predicates](verification/defining-predicates.md) +- [Allocating and deallocating memory](verification/allocating-and-deallocating-memory.md) +- [Lists](verification/lists.md) +- [Working with external lemmas](verification/external-lemmas.md) ## Case studies diff --git a/docs/getting-started/tutorials/testing/FULMINATE_README.md b/docs/getting-started/tutorials/testing/FULMINATE_README.md new file mode 100644 index 00000000..39d3751f --- /dev/null +++ b/docs/getting-started/tutorials/testing/FULMINATE_README.md @@ -0,0 +1,47 @@ +# Fulminate + +Fulminate is a tool for translating CN specifications into C runtime assertions, which can then be checked using concrete test inputs. + +## Installation + +Fulminate is installed as part of the CN toolchain - see [README.md](../../installation.md) for instructions. + +## Running Fulminate + +### Generating executable specifications + +To produce a file instrumented with CN runtime assertions, run: + +```bash +cn instrument .c +``` + +This will produce three files: + +* `-exec.c`, the instrumented source +* `cn.h`, a header file containing various definitions and prototypes, including C struct definitions representing CN datatypes, structs and records, as well as function prototypes for the various translated top-level CN functions and predicates. +* `cn.c`, a file that includes `cn.h` and provides definitions for the aforementioned prototypes + + +These are all produced in the directory the command was run from. Alternatively, one can provide an output directory for these three files (after creating the directory) using the `--output-dir` argument: + + +```bash +cn instrument .c --output-dir +``` + +The translation tool injects the executable precondition right before the source function body, at the start of the given function; the executable postcondition into a label called `cn_epilogue`, which gets jumped to via a `goto` wherever there is a return statement in the source; and the executable assertions inplace, wherever they were defined in the source. + +### Compiling, linking and running executable CN specifications + +To compile and link the output files described in the above section, and also to run these examples on some manually-produced concrete inputs (i.e. via a handwritten `main` function), one can run the following commands: + +```bash +export CHECK_SCRIPT="$OPAM_SWITCH_PREFIX/lib/cn/runtime/libexec/cn-runtime-single-file.sh" +$CHECK_SCRIPT .c +``` + +This runs the `cn-runtime-single-file.sh` script from the CN runtime library on `.c`, which generates the executable specification files, compiles and links these, and then runs the produced binary. This script is configurable with the `-n` option for disabling dynamic ownership checking and/or the `-q` option for running the script in quiet mode. This script can be found in `runtime/libcn/libexec` if you are interested in seeing the compile and link commands. + +The compile command includes the `-g` flag for collecting debug information, which means gdb or lldb can be run on the produced binary for setting breakpoints, stepping in and out of functions in a given run, printing concrete variable values at specific points in the program run, etc. gdb can cause problems on Mac due to some certification-related issues, so for Mac users we recommend you use lldb. + diff --git a/docs/getting-started/tutorials/testing/overview.md b/docs/getting-started/tutorials/testing/overview.md new file mode 100644 index 00000000..ef2078ac --- /dev/null +++ b/docs/getting-started/tutorials/testing/overview.md @@ -0,0 +1,48 @@ +# CN Testing + +CN has testing capabilities available via the `cn test` subcommand. + +## Overview + +Currently, CN supports only per-function tests, but additional types of testing may become available in the future. + +Running `cn test ` generates C files with the testing infrastructure, the instrumented program under test, and a build script named `run_tests.sh`. +This script compiles the C files and runs the tests. + +By default, running `cn test` will automatically run `run_tests.sh`, which produces a test executable `tests.out`. +This can be disabled by using the `--no-run` flag. + +The default behavior of testing is to rely on Fulminate for checking, which does not detect undefined behavior. +If you would like to also check for undefined behavior, you can use a sanitizer via `--sanitize=undefined`. + +The output directory for these files can be set by using `--output-dir=`. +If the directory does not already exist, it is created. + +### Per-function tests + +When testing, there are currently two types of tests, constant tests and generator-based tests. +For *each function with a body*, CN will create either a constant test or generator-based test. + +If a function takes no arguments, does not use accesses on global variables, and is correct, it should always return the same value and free any memory it allocates. +In this case, a constant test is generated, which runs the function once and uses [Fulminate](FULMINATE_README.md) to check for post-condition violations. + +In all other cases, it creates generator-based tests, which are in the style of property-based testing. +A "generator" is created, which randomly generates function arguments, values for globals accessed and heap states, all of which adhere to the given function's pre-condition. +It calls the function with this input and uses [Fulminate](FULMINATE_README.md) similar to the constant tests. + +#### Understanding errors + +Currently, the tool does not print out counterexamples, but this is [planned](https://github.com/rems-project/cerberus/issues/841). +Until then, `tests.out` can be run with the `--trap` flag in a debugger. +Since seeds are printed each time the tool runs, `--seed ` can be used to reproduce the test case. +The debugger should automatically pause right before rerunning the failing test case. + +#### Writing custom tests + +There is currently no way to write custom property-based tests. +However, once lemmas can be tested, a lemma describing the desired property could be written to test it. + +In terms of unit tests, one can simply define a function that performs the desired operations. +This function will get detected by `cn test` and turned into a constant test. +Any assertions that one would make about the result would have to be captured by the post-condition. +In the future, existing infrastructure like `cn_assert` might be adapted for general use. diff --git a/docs/getting-started/tutorials/allocating-and-deallocating-memory.md b/docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md similarity index 100% rename from docs/getting-started/tutorials/allocating-and-deallocating-memory.md rename to docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md diff --git a/docs/getting-started/tutorials/arrays-and-loops.md b/docs/getting-started/tutorials/verification/arrays-and-loops.md similarity index 100% rename from docs/getting-started/tutorials/arrays-and-loops.md rename to docs/getting-started/tutorials/verification/arrays-and-loops.md diff --git a/docs/getting-started/tutorials/basic-usage.md b/docs/getting-started/tutorials/verification/basic-usage.md similarity index 100% rename from docs/getting-started/tutorials/basic-usage.md rename to docs/getting-started/tutorials/verification/basic-usage.md diff --git a/docs/getting-started/tutorials/defining-predicates.md b/docs/getting-started/tutorials/verification/defining-predicates.md similarity index 100% rename from docs/getting-started/tutorials/defining-predicates.md rename to docs/getting-started/tutorials/verification/defining-predicates.md diff --git a/docs/getting-started/tutorials/external-lemmas.md b/docs/getting-started/tutorials/verification/external-lemmas.md similarity index 100% rename from docs/getting-started/tutorials/external-lemmas.md rename to docs/getting-started/tutorials/verification/external-lemmas.md diff --git a/docs/getting-started/tutorials/images/0.error.png b/docs/getting-started/tutorials/verification/images/0.error.png similarity index 100% rename from docs/getting-started/tutorials/images/0.error.png rename to docs/getting-started/tutorials/verification/images/0.error.png diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/verification/lists.md similarity index 100% rename from docs/getting-started/tutorials/lists.md rename to docs/getting-started/tutorials/verification/lists.md diff --git a/docs/getting-started/tutorials/ownership-of-compound-objects.md b/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md similarity index 100% rename from docs/getting-started/tutorials/ownership-of-compound-objects.md rename to docs/getting-started/tutorials/verification/ownership-of-compound-objects.md diff --git a/docs/getting-started/tutorials/pointers-and-simple-ownership.md b/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md similarity index 100% rename from docs/getting-started/tutorials/pointers-and-simple-ownership.md rename to docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md diff --git a/mkdocs.yml b/mkdocs.yml index 08433ecd..38a72237 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -100,14 +100,17 @@ nav: - Installation: getting-started/installation.md - Tutorials: - getting-started/tutorials/README.md - - "Basic usage": getting-started/tutorials/basic-usage.md - - "Pointers and simple ownership": getting-started/tutorials/pointers-and-simple-ownership.md - - "Ownership of compound objects": getting-started/tutorials/ownership-of-compound-objects.md - - "Arrays and loops": getting-started/tutorials/arrays-and-loops.md - - "Defining predicates": getting-started/tutorials/defining-predicates.md - - "Allocating and deallocating memory": getting-started/tutorials/allocating-and-deallocating-memory.md - - "Lists": getting-started/tutorials/lists.md - - "Working with external lemmas": getting-started/tutorials/external-lemmas.md + - Testing: + - Overview: getting-started/tutorials/testing/overview.md + - Verification: + - "Basic usage": getting-started/tutorials/verification/basic-usage.md + - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md + - "Ownership of compound objects": getting-started/tutorials/verification/ownership-of-compound-objects.md + - "Arrays and loops": getting-started/tutorials/verification/arrays-and-loops.md + - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md + - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md + - "Lists": getting-started/tutorials/verification/lists.md + - "Working with external lemmas": getting-started/tutorials/verification/external-lemmas.md - "Case studies": - "Imperative queues": getting-started/case-studies/imperative-queues.md - "Doubly-linked lists": getting-started/case-studies/doubly-linked-lists.md From 57c1547027c4be405d0894be005434bab621b657 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Fri, 21 Feb 2025 15:32:40 -0500 Subject: [PATCH 003/158] Add Jessica's min3 example --- .../tutorials/testing/min-example.md | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 docs/getting-started/tutorials/testing/min-example.md diff --git a/docs/getting-started/tutorials/testing/min-example.md b/docs/getting-started/tutorials/testing/min-example.md new file mode 100644 index 00000000..086fa995 --- /dev/null +++ b/docs/getting-started/tutorials/testing/min-example.md @@ -0,0 +1,39 @@ +### Example + +C program (with a bug). + +```C +int min3(int x, int y, int z) +{ + if (x <= y && x <= z) { + return x; + } else if (y <= x && x <= z) { + return y; + } else { + return z; + } +} +``` + +Specify the expected behavior of this program. + +```C +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +``` + +Run `cn test` and get a counterexample. + +```C +x = 13 +y = 4 +z = 9 +``` + +Use counterexample to realize and fix the bug. + +```C +else if (y <= x && y <= z) // not x <= z +``` From 8927fbcd92b6bfaf24c5d674b444798bd1a78184 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Fri, 21 Feb 2025 15:57:53 -0500 Subject: [PATCH 004/158] Create min3.c --- src/testing-examples/min3.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/testing-examples/min3.c diff --git a/src/testing-examples/min3.c b/src/testing-examples/min3.c new file mode 100644 index 00000000..5cad3bd3 --- /dev/null +++ b/src/testing-examples/min3.c @@ -0,0 +1,16 @@ +int min3(int x, int y, int z) +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +{ + if (x <= y && x <= z) { + return x; + } + else if (y <= x && x <= z) { + return y; + } + else { + return z; + } +} From 29f281458366fcb424cf8a69794b03ba37d050a5 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Fri, 21 Feb 2025 16:00:21 -0500 Subject: [PATCH 005/158] Separate three `min` versions --- src/testing-examples/min3.fixed.c | 16 ++++++++++++++++ src/testing-examples/min3.orig.c | 12 ++++++++++++ src/testing-examples/{min3.c => min3.spec.c} | 0 3 files changed, 28 insertions(+) create mode 100644 src/testing-examples/min3.fixed.c create mode 100644 src/testing-examples/min3.orig.c rename src/testing-examples/{min3.c => min3.spec.c} (100%) diff --git a/src/testing-examples/min3.fixed.c b/src/testing-examples/min3.fixed.c new file mode 100644 index 00000000..99abb065 --- /dev/null +++ b/src/testing-examples/min3.fixed.c @@ -0,0 +1,16 @@ +int min3(int x, int y, int z) +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +{ + if (x <= y && x <= z) { + return x; + } + else if (y <= x && y <= z) { + return y; + } + else { + return z; + } +} diff --git a/src/testing-examples/min3.orig.c b/src/testing-examples/min3.orig.c new file mode 100644 index 00000000..912cf81e --- /dev/null +++ b/src/testing-examples/min3.orig.c @@ -0,0 +1,12 @@ +int min3(int x, int y, int z) +{ + if (x <= y && x <= z) { + return x; + } + else if (y <= x && x <= z) { + return y; + } + else { + return z; + } +} diff --git a/src/testing-examples/min3.c b/src/testing-examples/min3.spec.c similarity index 100% rename from src/testing-examples/min3.c rename to src/testing-examples/min3.spec.c From 078707e153673b726dc162b7c2602dff9cb0dc80 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 24 Feb 2025 15:16:50 -0500 Subject: [PATCH 006/158] Create an outline document for thinking about testing tutorial structure --- docs/getting-started/tutorials/README.md | 3 ++- .../testing/{FULMINATE_README.md => overview-fulminate.md} | 0 .../tutorials/testing/{overview.md => overview-pbt.md} | 6 +++--- mkdocs.yml | 4 +++- 4 files changed, 8 insertions(+), 5 deletions(-) rename docs/getting-started/tutorials/testing/{FULMINATE_README.md => overview-fulminate.md} (100%) rename docs/getting-started/tutorials/testing/{overview.md => overview-pbt.md} (91%) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 34ee50b0..483aad8e 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -19,7 +19,8 @@ from [here](link:exercises.zip). ### Testing -- [Overview](testing/overview.md) +- [Outline](testing/outline.md) +**More links needed here** ### Verification diff --git a/docs/getting-started/tutorials/testing/FULMINATE_README.md b/docs/getting-started/tutorials/testing/overview-fulminate.md similarity index 100% rename from docs/getting-started/tutorials/testing/FULMINATE_README.md rename to docs/getting-started/tutorials/testing/overview-fulminate.md diff --git a/docs/getting-started/tutorials/testing/overview.md b/docs/getting-started/tutorials/testing/overview-pbt.md similarity index 91% rename from docs/getting-started/tutorials/testing/overview.md rename to docs/getting-started/tutorials/testing/overview-pbt.md index ef2078ac..119893b0 100644 --- a/docs/getting-started/tutorials/testing/overview.md +++ b/docs/getting-started/tutorials/testing/overview-pbt.md @@ -1,4 +1,4 @@ -# CN Testing +# Property-Based Testing in CN CN has testing capabilities available via the `cn test` subcommand. @@ -24,11 +24,11 @@ When testing, there are currently two types of tests, constant tests and generat For *each function with a body*, CN will create either a constant test or generator-based test. If a function takes no arguments, does not use accesses on global variables, and is correct, it should always return the same value and free any memory it allocates. -In this case, a constant test is generated, which runs the function once and uses [Fulminate](FULMINATE_README.md) to check for post-condition violations. +In this case, a constant test is generated, which runs the function once and uses [Fulminate](overview-fulminate.md) to check for post-condition violations. In all other cases, it creates generator-based tests, which are in the style of property-based testing. A "generator" is created, which randomly generates function arguments, values for globals accessed and heap states, all of which adhere to the given function's pre-condition. -It calls the function with this input and uses [Fulminate](FULMINATE_README.md) similar to the constant tests. +It calls the function with this input and uses [Fulminate](overview-fulminate.md) similar to the constant tests. #### Understanding errors diff --git a/mkdocs.yml b/mkdocs.yml index 38a72237..011317a5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -101,7 +101,9 @@ nav: - Tutorials: - getting-started/tutorials/README.md - Testing: - - Overview: getting-started/tutorials/testing/overview.md + - "Outline": getting-started/tutorials/testing/outline.md + - "Unit testing overview": getting-started/tutorials/testing/overview-fulminate.md + - "PBT overview": getting-started/tutorials/testing/overview-pbt.md - Verification: - "Basic usage": getting-started/tutorials/verification/basic-usage.md - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md From c26e50a9ef664e0181c5ddbd1ecd1ea1402435f6 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 24 Feb 2025 21:23:18 -0500 Subject: [PATCH 007/158] Big rename --- src/{examples => exercises}/abs.c | 0 src/{examples => exercises}/abs_mem.c | 0 src/{examples => exercises}/abs_mem_struct.c | 0 src/{examples => exercises}/add_0.c | 0 src/{examples => exercises}/add_1.c | 0 src/{examples => exercises}/add_2.c | 0 src/{examples => exercises}/add_read.c | 0 src/{examples => exercises}/add_two_array.c | 0 src/{examples => exercises}/array_load.broken.c | 0 src/{examples => exercises}/array_load.c | 0 src/{examples => exercises}/array_load2.c | 0 src/{examples => exercises}/bcp_framerule.c | 0 src/{examples => exercises}/const_example.c | 0 src/{examples => exercises}/const_example_lessgood.c | 0 src/{examples => exercises}/dll/add.c | 0 src/{examples => exercises}/dll/add_orig.broken.c | 0 src/{examples => exercises}/dll/c_types.h | 0 src/{examples => exercises}/dll/cn_types.h | 0 src/{examples => exercises}/dll/dllist_and_int.h | 0 src/{examples => exercises}/dll/getters.h | 0 src/{examples => exercises}/dll/headers.h | 0 src/{examples => exercises}/dll/malloc_free.h | 0 src/{examples => exercises}/dll/predicates.h | 0 src/{examples => exercises}/dll/remove.c | 0 src/{examples => exercises}/dll/remove_orig.broken.c | 0 src/{examples => exercises}/dll/singleton.c | 0 src/{examples => exercises}/facto.h | 0 src/{examples => exercises}/free.h | 0 src/{examples => exercises}/init_array.c | 0 src/{examples => exercises}/init_array2.c | 0 src/{examples => exercises}/init_array_rev.c | 0 src/{examples => exercises}/init_point.c | 0 src/{examples => exercises}/list/append.c | 0 src/{examples => exercises}/list/append.h | 0 src/{examples => exercises}/list/append2.c | 0 src/{examples => exercises}/list/c_types.h | 0 src/{examples => exercises}/list/cn_types.h | 0 src/{examples => exercises}/list/constructors.h | 0 src/{examples => exercises}/list/copy.c | 0 src/{examples => exercises}/list/free.c | 0 src/{examples => exercises}/list/hdtl.h | 0 src/{examples => exercises}/list/headers.h | 0 src/{examples => exercises}/list/length.c | 0 src/{examples => exercises}/list/mergesort.c | 0 src/{examples => exercises}/list/rev.c | 0 src/{examples => exercises}/list/rev.h | 0 src/{examples => exercises}/list/rev_alt.c | 0 src/{examples => exercises}/list/rev_lemmas.h | 0 src/{examples => exercises}/list/snoc.h | 0 src/{examples => exercises}/malloc.h | 0 src/{examples => exercises}/malloc_alt.h | 0 src/{testing-examples/min3.orig.c => exercises/min3/min3-orig.c} | 0 .../min3.spec.c => exercises/min3/min3.test.broken.c} | 0 src/{testing-examples/min3.fixed.c => exercises/min3/min3.test.c} | 0 src/{examples => exercises}/queue/allocation.h | 0 src/{examples => exercises}/queue/c_types.h | 0 src/{examples => exercises}/queue/cn_types_1.h | 0 src/{examples => exercises}/queue/cn_types_2.h | 0 src/{examples => exercises}/queue/cn_types_3.h | 0 src/{examples => exercises}/queue/empty.c | 0 src/{examples => exercises}/queue/headers.h | 0 src/{examples => exercises}/queue/pop.c | 0 src/{examples => exercises}/queue/pop_lemma.h | 0 src/{examples => exercises}/queue/pop_orig.broken.c | 0 src/{examples => exercises}/queue/pop_unified.c | 0 src/{examples => exercises}/queue/push.c | 0 src/{examples => exercises}/queue/push_induction.c | 0 src/{examples => exercises}/queue/push_lemma.h | 0 src/{examples => exercises}/queue/push_orig.broken.c | 0 src/{examples => exercises}/read.broken.c | 0 src/{examples => exercises}/read.c | 0 src/{examples => exercises}/read2.c | 0 src/{examples => exercises}/ref.h | 0 src/{examples => exercises}/runway/funcs1.h | 0 src/{examples => exercises}/runway/funcs2.c | 0 src/{examples => exercises}/runway/state.h | 0 src/{examples => exercises}/runway/valid_state.h | 0 src/{examples => exercises}/slf0_basic_incr.c | 0 src/{examples => exercises}/slf0_basic_incr.signed.broken.c | 0 src/{examples => exercises}/slf0_basic_incr.signed.c | 0 src/{examples => exercises}/slf0_incr.broken.c | 0 src/{examples => exercises}/slf10_basic_ref.c | 0 src/{examples => exercises}/slf11_basic_ref_greater.c | 0 src/{examples => exercises}/slf12_basic_ref_greater_abstract.c | 0 src/{examples => exercises}/slf13_basic_ref_with_frame.c | 0 .../slf14_basic_succ_using_incr_attempt.broken.c | 0 .../slf15_basic_succ_using_incr_attempt_.c | 0 src/{examples => exercises}/slf16_basic_succ_using_incr.c | 0 src/{examples => exercises}/slf17_get_and_free.c | 0 src/{examples => exercises}/slf18_two_dice.c | 0 src/{examples => exercises}/slf1_basic_example_let.c | 0 src/{examples => exercises}/slf1_basic_example_let.signed.c | 0 src/{examples => exercises}/slf2_basic_quadruple.c | 0 src/{examples => exercises}/slf2_basic_quadruple.signed.c | 0 src/{examples => exercises}/slf3_basic_inplace_double.c | 0 src/{examples => exercises}/slf4_basic_incr_two.c | 0 src/{examples => exercises}/slf5_basic_aliased_call.broken.c | 0 src/{examples => exercises}/slf6_basic_incr_two_aliased_call.c | 0 src/{examples => exercises}/slf7_basic_incr_first.c | 0 src/{examples => exercises}/slf8_basic_transfer.c | 0 src/{examples => exercises}/slf9_basic_transfer_aliased.c | 0 src/{examples => exercises}/slf_incr2.c | 0 src/{examples => exercises}/slf_incr2_alias.c | 0 src/{examples => exercises}/slf_incr2_noalias.c | 0 src/{examples => exercises}/slf_length_acc.c | 0 src/{examples => exercises}/slf_quadruple_mem.c | 0 src/{examples => exercises}/slf_ref_greater.c | 0 src/{examples => exercises}/slf_sized_stack.c | 0 src/{examples => exercises}/swap.c | 0 src/{examples => exercises}/swap_array.c | 0 src/{examples => exercises}/transpose.broken.c | 0 src/{examples => exercises}/transpose.c | 0 src/{examples => exercises}/transpose2.c | 0 src/{examples => exercises}/zero.c | 0 src/{ => old}/asciidoc_to_md.md | 0 src/{ => old}/asciidoctor.css | 0 src/{ => old}/setup.m4 | 0 src/{ => old}/style.css | 0 src/{ => old}/tutorial.md | 0 119 files changed, 0 insertions(+), 0 deletions(-) rename src/{examples => exercises}/abs.c (100%) rename src/{examples => exercises}/abs_mem.c (100%) rename src/{examples => exercises}/abs_mem_struct.c (100%) rename src/{examples => exercises}/add_0.c (100%) rename src/{examples => exercises}/add_1.c (100%) rename src/{examples => exercises}/add_2.c (100%) rename src/{examples => exercises}/add_read.c (100%) rename src/{examples => exercises}/add_two_array.c (100%) rename src/{examples => exercises}/array_load.broken.c (100%) rename src/{examples => exercises}/array_load.c (100%) rename src/{examples => exercises}/array_load2.c (100%) rename src/{examples => exercises}/bcp_framerule.c (100%) rename src/{examples => exercises}/const_example.c (100%) rename src/{examples => exercises}/const_example_lessgood.c (100%) rename src/{examples => exercises}/dll/add.c (100%) rename src/{examples => exercises}/dll/add_orig.broken.c (100%) rename src/{examples => exercises}/dll/c_types.h (100%) rename src/{examples => exercises}/dll/cn_types.h (100%) rename src/{examples => exercises}/dll/dllist_and_int.h (100%) rename src/{examples => exercises}/dll/getters.h (100%) rename src/{examples => exercises}/dll/headers.h (100%) rename src/{examples => exercises}/dll/malloc_free.h (100%) rename src/{examples => exercises}/dll/predicates.h (100%) rename src/{examples => exercises}/dll/remove.c (100%) rename src/{examples => exercises}/dll/remove_orig.broken.c (100%) rename src/{examples => exercises}/dll/singleton.c (100%) rename src/{examples => exercises}/facto.h (100%) rename src/{examples => exercises}/free.h (100%) rename src/{examples => exercises}/init_array.c (100%) rename src/{examples => exercises}/init_array2.c (100%) rename src/{examples => exercises}/init_array_rev.c (100%) rename src/{examples => exercises}/init_point.c (100%) rename src/{examples => exercises}/list/append.c (100%) rename src/{examples => exercises}/list/append.h (100%) rename src/{examples => exercises}/list/append2.c (100%) rename src/{examples => exercises}/list/c_types.h (100%) rename src/{examples => exercises}/list/cn_types.h (100%) rename src/{examples => exercises}/list/constructors.h (100%) rename src/{examples => exercises}/list/copy.c (100%) rename src/{examples => exercises}/list/free.c (100%) rename src/{examples => exercises}/list/hdtl.h (100%) rename src/{examples => exercises}/list/headers.h (100%) rename src/{examples => exercises}/list/length.c (100%) rename src/{examples => exercises}/list/mergesort.c (100%) rename src/{examples => exercises}/list/rev.c (100%) rename src/{examples => exercises}/list/rev.h (100%) rename src/{examples => exercises}/list/rev_alt.c (100%) rename src/{examples => exercises}/list/rev_lemmas.h (100%) rename src/{examples => exercises}/list/snoc.h (100%) rename src/{examples => exercises}/malloc.h (100%) rename src/{examples => exercises}/malloc_alt.h (100%) rename src/{testing-examples/min3.orig.c => exercises/min3/min3-orig.c} (100%) rename src/{testing-examples/min3.spec.c => exercises/min3/min3.test.broken.c} (100%) rename src/{testing-examples/min3.fixed.c => exercises/min3/min3.test.c} (100%) rename src/{examples => exercises}/queue/allocation.h (100%) rename src/{examples => exercises}/queue/c_types.h (100%) rename src/{examples => exercises}/queue/cn_types_1.h (100%) rename src/{examples => exercises}/queue/cn_types_2.h (100%) rename src/{examples => exercises}/queue/cn_types_3.h (100%) rename src/{examples => exercises}/queue/empty.c (100%) rename src/{examples => exercises}/queue/headers.h (100%) rename src/{examples => exercises}/queue/pop.c (100%) rename src/{examples => exercises}/queue/pop_lemma.h (100%) rename src/{examples => exercises}/queue/pop_orig.broken.c (100%) rename src/{examples => exercises}/queue/pop_unified.c (100%) rename src/{examples => exercises}/queue/push.c (100%) rename src/{examples => exercises}/queue/push_induction.c (100%) rename src/{examples => exercises}/queue/push_lemma.h (100%) rename src/{examples => exercises}/queue/push_orig.broken.c (100%) rename src/{examples => exercises}/read.broken.c (100%) rename src/{examples => exercises}/read.c (100%) rename src/{examples => exercises}/read2.c (100%) rename src/{examples => exercises}/ref.h (100%) rename src/{examples => exercises}/runway/funcs1.h (100%) rename src/{examples => exercises}/runway/funcs2.c (100%) rename src/{examples => exercises}/runway/state.h (100%) rename src/{examples => exercises}/runway/valid_state.h (100%) rename src/{examples => exercises}/slf0_basic_incr.c (100%) rename src/{examples => exercises}/slf0_basic_incr.signed.broken.c (100%) rename src/{examples => exercises}/slf0_basic_incr.signed.c (100%) rename src/{examples => exercises}/slf0_incr.broken.c (100%) rename src/{examples => exercises}/slf10_basic_ref.c (100%) rename src/{examples => exercises}/slf11_basic_ref_greater.c (100%) rename src/{examples => exercises}/slf12_basic_ref_greater_abstract.c (100%) rename src/{examples => exercises}/slf13_basic_ref_with_frame.c (100%) rename src/{examples => exercises}/slf14_basic_succ_using_incr_attempt.broken.c (100%) rename src/{examples => exercises}/slf15_basic_succ_using_incr_attempt_.c (100%) rename src/{examples => exercises}/slf16_basic_succ_using_incr.c (100%) rename src/{examples => exercises}/slf17_get_and_free.c (100%) rename src/{examples => exercises}/slf18_two_dice.c (100%) rename src/{examples => exercises}/slf1_basic_example_let.c (100%) rename src/{examples => exercises}/slf1_basic_example_let.signed.c (100%) rename src/{examples => exercises}/slf2_basic_quadruple.c (100%) rename src/{examples => exercises}/slf2_basic_quadruple.signed.c (100%) rename src/{examples => exercises}/slf3_basic_inplace_double.c (100%) rename src/{examples => exercises}/slf4_basic_incr_two.c (100%) rename src/{examples => exercises}/slf5_basic_aliased_call.broken.c (100%) rename src/{examples => exercises}/slf6_basic_incr_two_aliased_call.c (100%) rename src/{examples => exercises}/slf7_basic_incr_first.c (100%) rename src/{examples => exercises}/slf8_basic_transfer.c (100%) rename src/{examples => exercises}/slf9_basic_transfer_aliased.c (100%) rename src/{examples => exercises}/slf_incr2.c (100%) rename src/{examples => exercises}/slf_incr2_alias.c (100%) rename src/{examples => exercises}/slf_incr2_noalias.c (100%) rename src/{examples => exercises}/slf_length_acc.c (100%) rename src/{examples => exercises}/slf_quadruple_mem.c (100%) rename src/{examples => exercises}/slf_ref_greater.c (100%) rename src/{examples => exercises}/slf_sized_stack.c (100%) rename src/{examples => exercises}/swap.c (100%) rename src/{examples => exercises}/swap_array.c (100%) rename src/{examples => exercises}/transpose.broken.c (100%) rename src/{examples => exercises}/transpose.c (100%) rename src/{examples => exercises}/transpose2.c (100%) rename src/{examples => exercises}/zero.c (100%) rename src/{ => old}/asciidoc_to_md.md (100%) rename src/{ => old}/asciidoctor.css (100%) rename src/{ => old}/setup.m4 (100%) rename src/{ => old}/style.css (100%) rename src/{ => old}/tutorial.md (100%) diff --git a/src/examples/abs.c b/src/exercises/abs.c similarity index 100% rename from src/examples/abs.c rename to src/exercises/abs.c diff --git a/src/examples/abs_mem.c b/src/exercises/abs_mem.c similarity index 100% rename from src/examples/abs_mem.c rename to src/exercises/abs_mem.c diff --git a/src/examples/abs_mem_struct.c b/src/exercises/abs_mem_struct.c similarity index 100% rename from src/examples/abs_mem_struct.c rename to src/exercises/abs_mem_struct.c diff --git a/src/examples/add_0.c b/src/exercises/add_0.c similarity index 100% rename from src/examples/add_0.c rename to src/exercises/add_0.c diff --git a/src/examples/add_1.c b/src/exercises/add_1.c similarity index 100% rename from src/examples/add_1.c rename to src/exercises/add_1.c diff --git a/src/examples/add_2.c b/src/exercises/add_2.c similarity index 100% rename from src/examples/add_2.c rename to src/exercises/add_2.c diff --git a/src/examples/add_read.c b/src/exercises/add_read.c similarity index 100% rename from src/examples/add_read.c rename to src/exercises/add_read.c diff --git a/src/examples/add_two_array.c b/src/exercises/add_two_array.c similarity index 100% rename from src/examples/add_two_array.c rename to src/exercises/add_two_array.c diff --git a/src/examples/array_load.broken.c b/src/exercises/array_load.broken.c similarity index 100% rename from src/examples/array_load.broken.c rename to src/exercises/array_load.broken.c diff --git a/src/examples/array_load.c b/src/exercises/array_load.c similarity index 100% rename from src/examples/array_load.c rename to src/exercises/array_load.c diff --git a/src/examples/array_load2.c b/src/exercises/array_load2.c similarity index 100% rename from src/examples/array_load2.c rename to src/exercises/array_load2.c diff --git a/src/examples/bcp_framerule.c b/src/exercises/bcp_framerule.c similarity index 100% rename from src/examples/bcp_framerule.c rename to src/exercises/bcp_framerule.c diff --git a/src/examples/const_example.c b/src/exercises/const_example.c similarity index 100% rename from src/examples/const_example.c rename to src/exercises/const_example.c diff --git a/src/examples/const_example_lessgood.c b/src/exercises/const_example_lessgood.c similarity index 100% rename from src/examples/const_example_lessgood.c rename to src/exercises/const_example_lessgood.c diff --git a/src/examples/dll/add.c b/src/exercises/dll/add.c similarity index 100% rename from src/examples/dll/add.c rename to src/exercises/dll/add.c diff --git a/src/examples/dll/add_orig.broken.c b/src/exercises/dll/add_orig.broken.c similarity index 100% rename from src/examples/dll/add_orig.broken.c rename to src/exercises/dll/add_orig.broken.c diff --git a/src/examples/dll/c_types.h b/src/exercises/dll/c_types.h similarity index 100% rename from src/examples/dll/c_types.h rename to src/exercises/dll/c_types.h diff --git a/src/examples/dll/cn_types.h b/src/exercises/dll/cn_types.h similarity index 100% rename from src/examples/dll/cn_types.h rename to src/exercises/dll/cn_types.h diff --git a/src/examples/dll/dllist_and_int.h b/src/exercises/dll/dllist_and_int.h similarity index 100% rename from src/examples/dll/dllist_and_int.h rename to src/exercises/dll/dllist_and_int.h diff --git a/src/examples/dll/getters.h b/src/exercises/dll/getters.h similarity index 100% rename from src/examples/dll/getters.h rename to src/exercises/dll/getters.h diff --git a/src/examples/dll/headers.h b/src/exercises/dll/headers.h similarity index 100% rename from src/examples/dll/headers.h rename to src/exercises/dll/headers.h diff --git a/src/examples/dll/malloc_free.h b/src/exercises/dll/malloc_free.h similarity index 100% rename from src/examples/dll/malloc_free.h rename to src/exercises/dll/malloc_free.h diff --git a/src/examples/dll/predicates.h b/src/exercises/dll/predicates.h similarity index 100% rename from src/examples/dll/predicates.h rename to src/exercises/dll/predicates.h diff --git a/src/examples/dll/remove.c b/src/exercises/dll/remove.c similarity index 100% rename from src/examples/dll/remove.c rename to src/exercises/dll/remove.c diff --git a/src/examples/dll/remove_orig.broken.c b/src/exercises/dll/remove_orig.broken.c similarity index 100% rename from src/examples/dll/remove_orig.broken.c rename to src/exercises/dll/remove_orig.broken.c diff --git a/src/examples/dll/singleton.c b/src/exercises/dll/singleton.c similarity index 100% rename from src/examples/dll/singleton.c rename to src/exercises/dll/singleton.c diff --git a/src/examples/facto.h b/src/exercises/facto.h similarity index 100% rename from src/examples/facto.h rename to src/exercises/facto.h diff --git a/src/examples/free.h b/src/exercises/free.h similarity index 100% rename from src/examples/free.h rename to src/exercises/free.h diff --git a/src/examples/init_array.c b/src/exercises/init_array.c similarity index 100% rename from src/examples/init_array.c rename to src/exercises/init_array.c diff --git a/src/examples/init_array2.c b/src/exercises/init_array2.c similarity index 100% rename from src/examples/init_array2.c rename to src/exercises/init_array2.c diff --git a/src/examples/init_array_rev.c b/src/exercises/init_array_rev.c similarity index 100% rename from src/examples/init_array_rev.c rename to src/exercises/init_array_rev.c diff --git a/src/examples/init_point.c b/src/exercises/init_point.c similarity index 100% rename from src/examples/init_point.c rename to src/exercises/init_point.c diff --git a/src/examples/list/append.c b/src/exercises/list/append.c similarity index 100% rename from src/examples/list/append.c rename to src/exercises/list/append.c diff --git a/src/examples/list/append.h b/src/exercises/list/append.h similarity index 100% rename from src/examples/list/append.h rename to src/exercises/list/append.h diff --git a/src/examples/list/append2.c b/src/exercises/list/append2.c similarity index 100% rename from src/examples/list/append2.c rename to src/exercises/list/append2.c diff --git a/src/examples/list/c_types.h b/src/exercises/list/c_types.h similarity index 100% rename from src/examples/list/c_types.h rename to src/exercises/list/c_types.h diff --git a/src/examples/list/cn_types.h b/src/exercises/list/cn_types.h similarity index 100% rename from src/examples/list/cn_types.h rename to src/exercises/list/cn_types.h diff --git a/src/examples/list/constructors.h b/src/exercises/list/constructors.h similarity index 100% rename from src/examples/list/constructors.h rename to src/exercises/list/constructors.h diff --git a/src/examples/list/copy.c b/src/exercises/list/copy.c similarity index 100% rename from src/examples/list/copy.c rename to src/exercises/list/copy.c diff --git a/src/examples/list/free.c b/src/exercises/list/free.c similarity index 100% rename from src/examples/list/free.c rename to src/exercises/list/free.c diff --git a/src/examples/list/hdtl.h b/src/exercises/list/hdtl.h similarity index 100% rename from src/examples/list/hdtl.h rename to src/exercises/list/hdtl.h diff --git a/src/examples/list/headers.h b/src/exercises/list/headers.h similarity index 100% rename from src/examples/list/headers.h rename to src/exercises/list/headers.h diff --git a/src/examples/list/length.c b/src/exercises/list/length.c similarity index 100% rename from src/examples/list/length.c rename to src/exercises/list/length.c diff --git a/src/examples/list/mergesort.c b/src/exercises/list/mergesort.c similarity index 100% rename from src/examples/list/mergesort.c rename to src/exercises/list/mergesort.c diff --git a/src/examples/list/rev.c b/src/exercises/list/rev.c similarity index 100% rename from src/examples/list/rev.c rename to src/exercises/list/rev.c diff --git a/src/examples/list/rev.h b/src/exercises/list/rev.h similarity index 100% rename from src/examples/list/rev.h rename to src/exercises/list/rev.h diff --git a/src/examples/list/rev_alt.c b/src/exercises/list/rev_alt.c similarity index 100% rename from src/examples/list/rev_alt.c rename to src/exercises/list/rev_alt.c diff --git a/src/examples/list/rev_lemmas.h b/src/exercises/list/rev_lemmas.h similarity index 100% rename from src/examples/list/rev_lemmas.h rename to src/exercises/list/rev_lemmas.h diff --git a/src/examples/list/snoc.h b/src/exercises/list/snoc.h similarity index 100% rename from src/examples/list/snoc.h rename to src/exercises/list/snoc.h diff --git a/src/examples/malloc.h b/src/exercises/malloc.h similarity index 100% rename from src/examples/malloc.h rename to src/exercises/malloc.h diff --git a/src/examples/malloc_alt.h b/src/exercises/malloc_alt.h similarity index 100% rename from src/examples/malloc_alt.h rename to src/exercises/malloc_alt.h diff --git a/src/testing-examples/min3.orig.c b/src/exercises/min3/min3-orig.c similarity index 100% rename from src/testing-examples/min3.orig.c rename to src/exercises/min3/min3-orig.c diff --git a/src/testing-examples/min3.spec.c b/src/exercises/min3/min3.test.broken.c similarity index 100% rename from src/testing-examples/min3.spec.c rename to src/exercises/min3/min3.test.broken.c diff --git a/src/testing-examples/min3.fixed.c b/src/exercises/min3/min3.test.c similarity index 100% rename from src/testing-examples/min3.fixed.c rename to src/exercises/min3/min3.test.c diff --git a/src/examples/queue/allocation.h b/src/exercises/queue/allocation.h similarity index 100% rename from src/examples/queue/allocation.h rename to src/exercises/queue/allocation.h diff --git a/src/examples/queue/c_types.h b/src/exercises/queue/c_types.h similarity index 100% rename from src/examples/queue/c_types.h rename to src/exercises/queue/c_types.h diff --git a/src/examples/queue/cn_types_1.h b/src/exercises/queue/cn_types_1.h similarity index 100% rename from src/examples/queue/cn_types_1.h rename to src/exercises/queue/cn_types_1.h diff --git a/src/examples/queue/cn_types_2.h b/src/exercises/queue/cn_types_2.h similarity index 100% rename from src/examples/queue/cn_types_2.h rename to src/exercises/queue/cn_types_2.h diff --git a/src/examples/queue/cn_types_3.h b/src/exercises/queue/cn_types_3.h similarity index 100% rename from src/examples/queue/cn_types_3.h rename to src/exercises/queue/cn_types_3.h diff --git a/src/examples/queue/empty.c b/src/exercises/queue/empty.c similarity index 100% rename from src/examples/queue/empty.c rename to src/exercises/queue/empty.c diff --git a/src/examples/queue/headers.h b/src/exercises/queue/headers.h similarity index 100% rename from src/examples/queue/headers.h rename to src/exercises/queue/headers.h diff --git a/src/examples/queue/pop.c b/src/exercises/queue/pop.c similarity index 100% rename from src/examples/queue/pop.c rename to src/exercises/queue/pop.c diff --git a/src/examples/queue/pop_lemma.h b/src/exercises/queue/pop_lemma.h similarity index 100% rename from src/examples/queue/pop_lemma.h rename to src/exercises/queue/pop_lemma.h diff --git a/src/examples/queue/pop_orig.broken.c b/src/exercises/queue/pop_orig.broken.c similarity index 100% rename from src/examples/queue/pop_orig.broken.c rename to src/exercises/queue/pop_orig.broken.c diff --git a/src/examples/queue/pop_unified.c b/src/exercises/queue/pop_unified.c similarity index 100% rename from src/examples/queue/pop_unified.c rename to src/exercises/queue/pop_unified.c diff --git a/src/examples/queue/push.c b/src/exercises/queue/push.c similarity index 100% rename from src/examples/queue/push.c rename to src/exercises/queue/push.c diff --git a/src/examples/queue/push_induction.c b/src/exercises/queue/push_induction.c similarity index 100% rename from src/examples/queue/push_induction.c rename to src/exercises/queue/push_induction.c diff --git a/src/examples/queue/push_lemma.h b/src/exercises/queue/push_lemma.h similarity index 100% rename from src/examples/queue/push_lemma.h rename to src/exercises/queue/push_lemma.h diff --git a/src/examples/queue/push_orig.broken.c b/src/exercises/queue/push_orig.broken.c similarity index 100% rename from src/examples/queue/push_orig.broken.c rename to src/exercises/queue/push_orig.broken.c diff --git a/src/examples/read.broken.c b/src/exercises/read.broken.c similarity index 100% rename from src/examples/read.broken.c rename to src/exercises/read.broken.c diff --git a/src/examples/read.c b/src/exercises/read.c similarity index 100% rename from src/examples/read.c rename to src/exercises/read.c diff --git a/src/examples/read2.c b/src/exercises/read2.c similarity index 100% rename from src/examples/read2.c rename to src/exercises/read2.c diff --git a/src/examples/ref.h b/src/exercises/ref.h similarity index 100% rename from src/examples/ref.h rename to src/exercises/ref.h diff --git a/src/examples/runway/funcs1.h b/src/exercises/runway/funcs1.h similarity index 100% rename from src/examples/runway/funcs1.h rename to src/exercises/runway/funcs1.h diff --git a/src/examples/runway/funcs2.c b/src/exercises/runway/funcs2.c similarity index 100% rename from src/examples/runway/funcs2.c rename to src/exercises/runway/funcs2.c diff --git a/src/examples/runway/state.h b/src/exercises/runway/state.h similarity index 100% rename from src/examples/runway/state.h rename to src/exercises/runway/state.h diff --git a/src/examples/runway/valid_state.h b/src/exercises/runway/valid_state.h similarity index 100% rename from src/examples/runway/valid_state.h rename to src/exercises/runway/valid_state.h diff --git a/src/examples/slf0_basic_incr.c b/src/exercises/slf0_basic_incr.c similarity index 100% rename from src/examples/slf0_basic_incr.c rename to src/exercises/slf0_basic_incr.c diff --git a/src/examples/slf0_basic_incr.signed.broken.c b/src/exercises/slf0_basic_incr.signed.broken.c similarity index 100% rename from src/examples/slf0_basic_incr.signed.broken.c rename to src/exercises/slf0_basic_incr.signed.broken.c diff --git a/src/examples/slf0_basic_incr.signed.c b/src/exercises/slf0_basic_incr.signed.c similarity index 100% rename from src/examples/slf0_basic_incr.signed.c rename to src/exercises/slf0_basic_incr.signed.c diff --git a/src/examples/slf0_incr.broken.c b/src/exercises/slf0_incr.broken.c similarity index 100% rename from src/examples/slf0_incr.broken.c rename to src/exercises/slf0_incr.broken.c diff --git a/src/examples/slf10_basic_ref.c b/src/exercises/slf10_basic_ref.c similarity index 100% rename from src/examples/slf10_basic_ref.c rename to src/exercises/slf10_basic_ref.c diff --git a/src/examples/slf11_basic_ref_greater.c b/src/exercises/slf11_basic_ref_greater.c similarity index 100% rename from src/examples/slf11_basic_ref_greater.c rename to src/exercises/slf11_basic_ref_greater.c diff --git a/src/examples/slf12_basic_ref_greater_abstract.c b/src/exercises/slf12_basic_ref_greater_abstract.c similarity index 100% rename from src/examples/slf12_basic_ref_greater_abstract.c rename to src/exercises/slf12_basic_ref_greater_abstract.c diff --git a/src/examples/slf13_basic_ref_with_frame.c b/src/exercises/slf13_basic_ref_with_frame.c similarity index 100% rename from src/examples/slf13_basic_ref_with_frame.c rename to src/exercises/slf13_basic_ref_with_frame.c diff --git a/src/examples/slf14_basic_succ_using_incr_attempt.broken.c b/src/exercises/slf14_basic_succ_using_incr_attempt.broken.c similarity index 100% rename from src/examples/slf14_basic_succ_using_incr_attempt.broken.c rename to src/exercises/slf14_basic_succ_using_incr_attempt.broken.c diff --git a/src/examples/slf15_basic_succ_using_incr_attempt_.c b/src/exercises/slf15_basic_succ_using_incr_attempt_.c similarity index 100% rename from src/examples/slf15_basic_succ_using_incr_attempt_.c rename to src/exercises/slf15_basic_succ_using_incr_attempt_.c diff --git a/src/examples/slf16_basic_succ_using_incr.c b/src/exercises/slf16_basic_succ_using_incr.c similarity index 100% rename from src/examples/slf16_basic_succ_using_incr.c rename to src/exercises/slf16_basic_succ_using_incr.c diff --git a/src/examples/slf17_get_and_free.c b/src/exercises/slf17_get_and_free.c similarity index 100% rename from src/examples/slf17_get_and_free.c rename to src/exercises/slf17_get_and_free.c diff --git a/src/examples/slf18_two_dice.c b/src/exercises/slf18_two_dice.c similarity index 100% rename from src/examples/slf18_two_dice.c rename to src/exercises/slf18_two_dice.c diff --git a/src/examples/slf1_basic_example_let.c b/src/exercises/slf1_basic_example_let.c similarity index 100% rename from src/examples/slf1_basic_example_let.c rename to src/exercises/slf1_basic_example_let.c diff --git a/src/examples/slf1_basic_example_let.signed.c b/src/exercises/slf1_basic_example_let.signed.c similarity index 100% rename from src/examples/slf1_basic_example_let.signed.c rename to src/exercises/slf1_basic_example_let.signed.c diff --git a/src/examples/slf2_basic_quadruple.c b/src/exercises/slf2_basic_quadruple.c similarity index 100% rename from src/examples/slf2_basic_quadruple.c rename to src/exercises/slf2_basic_quadruple.c diff --git a/src/examples/slf2_basic_quadruple.signed.c b/src/exercises/slf2_basic_quadruple.signed.c similarity index 100% rename from src/examples/slf2_basic_quadruple.signed.c rename to src/exercises/slf2_basic_quadruple.signed.c diff --git a/src/examples/slf3_basic_inplace_double.c b/src/exercises/slf3_basic_inplace_double.c similarity index 100% rename from src/examples/slf3_basic_inplace_double.c rename to src/exercises/slf3_basic_inplace_double.c diff --git a/src/examples/slf4_basic_incr_two.c b/src/exercises/slf4_basic_incr_two.c similarity index 100% rename from src/examples/slf4_basic_incr_two.c rename to src/exercises/slf4_basic_incr_two.c diff --git a/src/examples/slf5_basic_aliased_call.broken.c b/src/exercises/slf5_basic_aliased_call.broken.c similarity index 100% rename from src/examples/slf5_basic_aliased_call.broken.c rename to src/exercises/slf5_basic_aliased_call.broken.c diff --git a/src/examples/slf6_basic_incr_two_aliased_call.c b/src/exercises/slf6_basic_incr_two_aliased_call.c similarity index 100% rename from src/examples/slf6_basic_incr_two_aliased_call.c rename to src/exercises/slf6_basic_incr_two_aliased_call.c diff --git a/src/examples/slf7_basic_incr_first.c b/src/exercises/slf7_basic_incr_first.c similarity index 100% rename from src/examples/slf7_basic_incr_first.c rename to src/exercises/slf7_basic_incr_first.c diff --git a/src/examples/slf8_basic_transfer.c b/src/exercises/slf8_basic_transfer.c similarity index 100% rename from src/examples/slf8_basic_transfer.c rename to src/exercises/slf8_basic_transfer.c diff --git a/src/examples/slf9_basic_transfer_aliased.c b/src/exercises/slf9_basic_transfer_aliased.c similarity index 100% rename from src/examples/slf9_basic_transfer_aliased.c rename to src/exercises/slf9_basic_transfer_aliased.c diff --git a/src/examples/slf_incr2.c b/src/exercises/slf_incr2.c similarity index 100% rename from src/examples/slf_incr2.c rename to src/exercises/slf_incr2.c diff --git a/src/examples/slf_incr2_alias.c b/src/exercises/slf_incr2_alias.c similarity index 100% rename from src/examples/slf_incr2_alias.c rename to src/exercises/slf_incr2_alias.c diff --git a/src/examples/slf_incr2_noalias.c b/src/exercises/slf_incr2_noalias.c similarity index 100% rename from src/examples/slf_incr2_noalias.c rename to src/exercises/slf_incr2_noalias.c diff --git a/src/examples/slf_length_acc.c b/src/exercises/slf_length_acc.c similarity index 100% rename from src/examples/slf_length_acc.c rename to src/exercises/slf_length_acc.c diff --git a/src/examples/slf_quadruple_mem.c b/src/exercises/slf_quadruple_mem.c similarity index 100% rename from src/examples/slf_quadruple_mem.c rename to src/exercises/slf_quadruple_mem.c diff --git a/src/examples/slf_ref_greater.c b/src/exercises/slf_ref_greater.c similarity index 100% rename from src/examples/slf_ref_greater.c rename to src/exercises/slf_ref_greater.c diff --git a/src/examples/slf_sized_stack.c b/src/exercises/slf_sized_stack.c similarity index 100% rename from src/examples/slf_sized_stack.c rename to src/exercises/slf_sized_stack.c diff --git a/src/examples/swap.c b/src/exercises/swap.c similarity index 100% rename from src/examples/swap.c rename to src/exercises/swap.c diff --git a/src/examples/swap_array.c b/src/exercises/swap_array.c similarity index 100% rename from src/examples/swap_array.c rename to src/exercises/swap_array.c diff --git a/src/examples/transpose.broken.c b/src/exercises/transpose.broken.c similarity index 100% rename from src/examples/transpose.broken.c rename to src/exercises/transpose.broken.c diff --git a/src/examples/transpose.c b/src/exercises/transpose.c similarity index 100% rename from src/examples/transpose.c rename to src/exercises/transpose.c diff --git a/src/examples/transpose2.c b/src/exercises/transpose2.c similarity index 100% rename from src/examples/transpose2.c rename to src/exercises/transpose2.c diff --git a/src/examples/zero.c b/src/exercises/zero.c similarity index 100% rename from src/examples/zero.c rename to src/exercises/zero.c diff --git a/src/asciidoc_to_md.md b/src/old/asciidoc_to_md.md similarity index 100% rename from src/asciidoc_to_md.md rename to src/old/asciidoc_to_md.md diff --git a/src/asciidoctor.css b/src/old/asciidoctor.css similarity index 100% rename from src/asciidoctor.css rename to src/old/asciidoctor.css diff --git a/src/setup.m4 b/src/old/setup.m4 similarity index 100% rename from src/setup.m4 rename to src/old/setup.m4 diff --git a/src/style.css b/src/old/style.css similarity index 100% rename from src/style.css rename to src/old/style.css diff --git a/src/tutorial.md b/src/old/tutorial.md similarity index 100% rename from src/tutorial.md rename to src/old/tutorial.md From 4ea5dcda3068a7f9e95454f182b81deb150dc0ac Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 24 Feb 2025 21:23:34 -0500 Subject: [PATCH 008/158] Big rename, part 2 --- Makefile | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index e525def8..ac1a1d75 100644 --- a/Makefile +++ b/Makefile @@ -6,16 +6,18 @@ default: tutorial all: default clean: - rm -rf docs/exercises docs/solutions docs/exercises.zip build TAGS + rm -rf docs/exercises docs/solutions docs/exercises.zip \ + build TAGS _tests ############################################################################## # Exercises -SRC_EXAMPLES=$(shell find src/examples -type f) -SOLUTIONS=$(patsubst src/examples/%, docs/solutions/%, $(SRC_EXAMPLES)) -EXERCISES=$(patsubst src/examples/%, docs/exercises/%, $(SRC_EXAMPLES)) +SRC_EXERCISES=$(shell find src/exercises -type f) +SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(SRC_EXERCISES)) +EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(SRC_EXERCISES)) CN=cn verify +CNTEST=cn test exercises: docs-exercises-dirs $(EXERCISES) $(SOLUTIONS) @@ -23,18 +25,23 @@ docs-exercises-dirs: mkdir -p docs/exercises mkdir -p docs/solutions -docs/exercises/%: src/examples/% +docs/exercises/%: src/exercises/% @echo Rebuild $@ @-mkdir -p $(dir $@) @sed -E '\|^.*--BEGIN--.*$$|,\|^.*--END--.*$$|d' $< > $@ -docs/solutions/%: src/examples/% +docs/solutions/%: src/exercises/% @-mkdir -p $(dir $@) + @-mkdir -p _tests @if [ `which cn` ]; then \ if [[ "$<" = *".c"* ]]; then \ if [[ "$<" != *"broken"* ]]; then \ - echo $(CN) $< && $(CN) $<; \ - fi; \ + if [[ "$<" = *".test."*c ]]; then \ + echo $(CNTEST) $< && $(CNTEST) test $< --output _tests; \ + else \ + echo $(CN) $< && $(CN) $<; \ + fi; \ + fi; \ fi \ fi @echo Rebuild $@ @@ -43,8 +50,8 @@ docs/solutions/%: src/examples/% docs/exercises.zip: $(EXERCISES) cd docs; zip -r exercises.zip exercises > /dev/null -WORKING=$(wildcard src/examples/list_*.c) -WORKING_AUX=$(patsubst src/examples/%, docs/solutions/%, $(WORKING)) +WORKING=$(wildcard src/exercises/list_*.c) +WORKING_AUX=$(patsubst src/exercises/%, docs/solutions/%, $(WORKING)) temp: $(WORKING_AUX) docs-exercises-dirs ############################################################################## @@ -52,12 +59,12 @@ temp: $(WORKING_AUX) docs-exercises-dirs CN_PATH?=cn verify -check-archive: +check-archive: @echo Check archive examples @$(MAKEFILE_DIR)/src/example-archive/check-all.sh "$(CN_PATH)" check-tutorial: - @echo Check tutorial examples + @echo Check tutorial exercises @$(MAKEFILE_DIR)/check.sh "$(CN_PATH)" check: check-tutorial check-archive @@ -76,7 +83,7 @@ serve: exercises mkdocs.yml $(shell find docs -type f) TAGS: @echo Rebuilding TAGS - @etags src/tutorial.adoc $(SRC_EXAMPLES) + @etags src/tutorial.adoc $(SRC_EXERCISES) ############################################################################## # Personal and site-specific stuff From d8466b0de84c039eec5de8c0efaa551860fde820 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 24 Feb 2025 21:24:31 -0500 Subject: [PATCH 009/158] (A start on (a skeleton for)) the testing tutorial --- .gitignore | 2 + docs/getting-started/tutorials/README.md | 6 -- .../tutorials/testing/outline.md | 58 +++++++++++++++++++ src/exercises/min3/min3.instrument.broken.c | 20 +++++++ src/exercises/min3/min3.instrument.c | 20 +++++++ src/exercises/min3/min3.test.broken.c | 2 +- 6 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 docs/getting-started/tutorials/testing/outline.md create mode 100644 src/exercises/min3/min3.instrument.broken.c create mode 100644 src/exercises/min3/min3.instrument.c diff --git a/.gitignore b/.gitignore index 4d1be0ad..6b21bfd0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ check **.swp docs/exercises docs/solutions +/_opam/ +/_tests/ diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 483aad8e..da2ab496 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,12 +4,6 @@ These tutorials introduce CN through a series of examples, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. -!!! warning - - These tutorials focus on verifying CN specifications and do not cover - runtime testing. Runtime testing will be introduced in future - documentation. - ## Source files The source files for all the exercises and examples below can be downloaded diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md new file mode 100644 index 00000000..2f7084f3 --- /dev/null +++ b/docs/getting-started/tutorials/testing/outline.md @@ -0,0 +1,58 @@ +# Outline of the New Testing Tutorial + +## A proposed order of topics and examples... + +- High-level overview of CN + +- Hello world example of unit testing + +- instructions for running unit tests themselves + - an exercise to try it out on min3 + - an exercise to find a bug in a variant of min3 + - couple more (similar, optional) exercises + +- Hello world example of PBT (min3) + - original version: + ```c title="exercises/min3/min3.orig.c" + --8<-- + exercises/min3/min3-orig.c + --8<-- + ``` + - with a specification: + ```c title="exercises/min3/min3.test.c" + --8<-- + exercises/min3/min3.test.c + --8<-- + ``` + - with a spec and a mistake: + ```c title="exercises/min3/min3.brokentest.c" + --8<-- + exercises/min3/min3.brokentest.c + --8<-- + ``` + +- instructions for running PBT themselves + - an exercise to try it out on min3 + - an exercise to find a bug in a variant of min3 + - couple more (similar, optional) exercises -- e.g., sorting three + numbers + +- Maybe some more examples of very simple C programs (no pointers, no + UB, ...) + +## Further Topics: + +- How to write specs (a huge topic!) +- Testing programs with pointers (but not dynamic storage allocation) +- Testing array-manipulating code +- Testing heap-manipulating code (lists, etc.) +- Checking for UB +- Larger case studies + +## Questions and TODOs + +- Go through the verification tutorial and move some stuff here +- When do we introduce unit tests? Can we do it at the very beginning? + - I think yes, but the fulminate instructions are currently quite + hard to follow! +- The makefile should confirm that broken tests actually fail diff --git a/src/exercises/min3/min3.instrument.broken.c b/src/exercises/min3/min3.instrument.broken.c new file mode 100644 index 00000000..8a6e4b2a --- /dev/null +++ b/src/exercises/min3/min3.instrument.broken.c @@ -0,0 +1,20 @@ +int min3(int x, int y, int z) +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +{ + if (x <= y && x <= z) { + return x; + } + else if (y <= x && y <= z) { + return y; + } + else { + return z; + } +} + +int main() { + int r = min3(1,2,3); +} diff --git a/src/exercises/min3/min3.instrument.c b/src/exercises/min3/min3.instrument.c new file mode 100644 index 00000000..8a6e4b2a --- /dev/null +++ b/src/exercises/min3/min3.instrument.c @@ -0,0 +1,20 @@ +int min3(int x, int y, int z) +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +{ + if (x <= y && x <= z) { + return x; + } + else if (y <= x && y <= z) { + return y; + } + else { + return z; + } +} + +int main() { + int r = min3(1,2,3); +} diff --git a/src/exercises/min3/min3.test.broken.c b/src/exercises/min3/min3.test.broken.c index 5cad3bd3..42d6aec5 100644 --- a/src/exercises/min3/min3.test.broken.c +++ b/src/exercises/min3/min3.test.broken.c @@ -7,7 +7,7 @@ int min3(int x, int y, int z) if (x <= y && x <= z) { return x; } - else if (y <= x && x <= z) { + else if (y <= x && x <= z) { // Oops! return y; } else { From 913da72a48f8b028d446174fbfcf42788f80bf0e Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 27 Feb 2025 08:50:23 -0500 Subject: [PATCH 010/158] Partial outline for testing tutorial --- .../tutorials/testing/outline.md | 47 ++++++++++++++++++- .../tutorials/verification/basic-usage.md | 11 +++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md index 2f7084f3..58c85581 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/testing/outline.md @@ -39,14 +39,45 @@ - Maybe some more examples of very simple C programs (no pointers, no UB, ...) + - use unsigned arithmetic, to avoid UB! (This would be good in + the verification tutorial too!) + +- Testing programs with pointers (but not dynamic storage allocation) + + - read.c + - unannotated version fails tests + - need to explain how to figure out WHY testing fails! + - explain ownership (copy/move from verification tutorial) + - version with proper spec works better! + - (lots of useful text) + - read.broken.c demonstrates linearity of resource usage + - exercises: + - quadruple_mem + - abs_mem + - slf0_basic_incr_signed.c + shows the difference between Block and Owned + - exercises + - zero.c + - basic_inplace_double.c involves UB, so skip? + - maybe something about swapping pointers? + + - add_read (but changing it to swapping or something, to avoid UB + issues) + + - everything up through pointers to compound objects seems to work + well, except for some of the resource inference stuff ## Further Topics: - How to write specs (a huge topic!) -- Testing programs with pointers (but not dynamic storage allocation) +- Numeric types, conversions, overflow, etc. + - abs.c is a good exercise (probably we'd just move it entirely, + along with the paragraph above it) - Testing array-manipulating code - Testing heap-manipulating code (lists, etc.) - Checking for UB + - Note that the verification tutorial *begins* with an example that + testing doesn't handle at all! - Larger case studies ## Questions and TODOs @@ -55,4 +86,16 @@ - When do we introduce unit tests? Can we do it at the very beginning? - I think yes, but the fulminate instructions are currently quite hard to follow! -- The makefile should confirm that broken tests actually fail +- The makefile should confirm that broken tests actually +- VSCode / Copilot gives a lot of hints (some correct)!! +- The naming of exercises is hideous (esp. the slf ones) +- Starting with signed overflow, etc., is horrible +- I think the verification material can be organized so that it can be + read either interleaved with the testing tutorial or completely + after it. + +## CN / VSCode Nits +- It would be nice if (a) errors were indicated more boldly (e.g., a + red slug in the margin, not just red squiggles) and (b) successful + verification were visually indicated somehow (green light goes on, + or whatever). diff --git a/docs/getting-started/tutorials/verification/basic-usage.md b/docs/getting-started/tutorials/verification/basic-usage.md index a353306b..5835bb01 100644 --- a/docs/getting-started/tutorials/verification/basic-usage.md +++ b/docs/getting-started/tutorials/verification/basic-usage.md @@ -1,6 +1,6 @@ # Basic usage -The simple arithmetic function: `add` shown below takes two `int` arguments, `x` and `y`, and returns their sum. +The simple arithmetic function `add` shown below takes `int` arguments `x` and `y` and returns their sum. ```c title="exercises/add_0.c" --8<-- @@ -100,7 +100,6 @@ comprises two sections: -_CN error report_ ![*CN error report*](images/0.error.png) _Path to error._ The first section contains information about the @@ -195,11 +194,15 @@ exercises/slf1_basic_example_let.signed.c --8<-- ``` -We would like to verify this is safe, and that `doubled` returns twice the value of `n`. Running CN on `doubled` leads to a type error: the increment of `a` has undefined behaviour. +We would like to verify this is safe and that `doubled` returns twice the value of `n`. Running CN on `doubled` leads to a type error: the increment of `a` has undefined behaviour. As in the first example, we need to ensure that `n+1` does not overflow and `n-1` does not underflow. Similarly `a+b` has to be representable at `int` type. -include\*example(solutions/slf1_basic_example_let.signed.c) +```c title="solutions/slf1_basic_example_let.signed.c" +--8<-- +solutions/slf1_basic_example_let.signed.c +--8<-- +``` From a9e5f38915148c77014a2b214586a76e2e54216e Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 27 Feb 2025 21:09:06 -0500 Subject: [PATCH 011/158] More work on outline of new tutorial --- .../tutorials/testing/outline.md | 170 +++++++++++------- 1 file changed, 110 insertions(+), 60 deletions(-) diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md index 58c85581..bfcf9398 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/testing/outline.md @@ -1,17 +1,25 @@ -# Outline of the New Testing Tutorial - -## A proposed order of topics and examples... +# Introduction - High-level overview of CN -- Hello world example of unit testing +# Unit Testing + +(BCP: I'd like to introduce unit testing at the very start, but the +Fulminate instructions are currently quite hard to follow! (When) can +we improve that?) + +- Hello-world example of unit testing - instructions for running unit tests themselves - an exercise to try it out on min3 - an exercise to find a bug in a variant of min3 - couple more (similar, optional) exercises -- Hello world example of PBT (min3) +TODO: Complete instructions for running Fulminate on the min3 example. + +# PBT + +- Hello-world example of PBT (min3) - original version: ```c title="exercises/min3/min3.orig.c" --8<-- @@ -31,71 +39,113 @@ --8<-- ``` -- instructions for running PBT themselves +- instructions for running PBT - an exercise to try it out on min3 - an exercise to find a bug in a variant of min3 - couple more (similar, optional) exercises -- e.g., sorting three numbers -- Maybe some more examples of very simple C programs (no pointers, no - UB, ...) - - use unsigned arithmetic, to avoid UB! (This would be good in - the verification tutorial too!) - -- Testing programs with pointers (but not dynamic storage allocation) - - - read.c - - unannotated version fails tests - - need to explain how to figure out WHY testing fails! - - explain ownership (copy/move from verification tutorial) - - version with proper spec works better! - - (lots of useful text) - - read.broken.c demonstrates linearity of resource usage - - exercises: - - quadruple_mem - - abs_mem - - slf0_basic_incr_signed.c - shows the difference between Block and Owned - - exercises - - zero.c - - basic_inplace_double.c involves UB, so skip? - - maybe something about swapping pointers? - - - add_read (but changing it to swapping or something, to avoid UB - issues) - - - everything up through pointers to compound objects seems to work - well, except for some of the resource inference stuff - -## Further Topics: - -- How to write specs (a huge topic!) -- Numeric types, conversions, overflow, etc. +- Some more examples of very simple C programs + - use unsigned arithmetic in all the early sections to avoid UB! + - (convert all the existing examples and exercises to unsigned, + leaving signed arithmetic and UB to a later section by + themselves) + +[BCP: In the rest of the tutorial, maybe we could be agnostic +(somewhat agnostic, at least) about whether people are using unit +tests or PBT. I don't have a sense yet of whether that will really +work, but it would have the good effect of focusing everybody's +attention on specifications and how to think about them, rather than +the testing process itself.] + +# Programs with Pointers + +(but not yet dynamic storage allocation) + +- read.c + - unannotated version fails tests + - need to explain how to figure out WHY testing fails! + - explain ownership (copy/move from verification tutorial) + - version with proper spec works better! + - (lots of useful text) + - read.broken.c demonstrates linearity of resource usage +- exercises: + - quadruple_mem + - abs_mem +- slf0_basic_incr_signed.c + shows the difference between Block and Owned +- exercises + - zero.c + - basic_inplace_double.c involves UB, so skip? + - maybe something about swapping pointers? + +- add_read (but changing it to swapping or something, to avoid UB + issues) + +- everything up through pointers to compound objects seems to work + well, except for some of the resource inference stuff + +## Arrays + +## Dynamic Heap Structures + +## Numeric Types + +- Signed numeric types, sizes, conversions, overflow, etc. - abs.c is a good exercise (probably we'd just move it entirely, along with the paragraph above it) -- Testing array-manipulating code -- Testing heap-manipulating code (lists, etc.) -- Checking for UB - - Note that the verification tutorial *begins* with an example that - testing doesn't handle at all! -- Larger case studies - -## Questions and TODOs - -- Go through the verification tutorial and move some stuff here -- When do we introduce unit tests? Can we do it at the very beginning? - - I think yes, but the fulminate instructions are currently quite - hard to follow! -- The makefile should confirm that broken tests actually -- VSCode / Copilot gives a lot of hints (some correct)!! + - Checking for UB + - Note that the verification tutorial *begins* with an example that + testing doesn't handle at all! + +## Case studies + +Explicit chapters / case studies on each of the "high-value" PBT +situations that Harry identified in the Jane Street study + - simple memory safety specs + - other simple sanity-check properties + - round-trip properties + - model implementations + +The current case studies from the verification tutorial + - make a testing variant and an optional verification variant of + each of them + +____________________________________________________________________ + +# Questions and Discussion Points + - The naming of exercises is hideous (esp. the slf ones) -- Starting with signed overflow, etc., is horrible -- I think the verification material can be organized so that it can be - read either interleaved with the testing tutorial or completely - after it. -## CN / VSCode Nits +- I (bcp) am now leaning toward making the verification material + mostly be extra optional sections that users can read after each + major section of the testing tutorial -- i.e., it's not two separate + tutorials, but rather one tutorial with a bunch of sections that + people can skip if they only care about testing. This works because + the main focus of the testing parts is actually not testing, but + rather _specification_. (By contrast, the verification parts really + do have to talk quite a bit about the process of verification + itself, because verification is hard and there's a lot to say.) + +- We should think of / coin a word or phrase that means "unit testing, + but with a specification that tells you whether the system produced + the right answer, rather than an explicitly (programmer-)provided + expected output." E.g., maybe "unit testing with an oracle"? (OK, + but the person on the street will not know what we mean by oracle in + this context.) + +- The makefile should confirm that broken tests actually break + +____________________________________________________________________ + +# CN / VSCode Nits - It would be nice if (a) errors were indicated more boldly (e.g., a red slug in the margin, not just red squiggles) and (b) successful verification were visually indicated somehow (green light goes on, or whatever). +- VSCode with Copilot currently gives a *lot* of hints (some correct)!! +- One could imagine that users would sometimes want *both* unit tests + and PBT. E.g., if the PBT generator is having trouble hitting some + parts of the code, they could be covered by hand-written tests. Or + maybe people start by writing unit tests and later add PBT; it would + be silly to *not* run the unit tests they've written. From 72f3997b831094834a887d3c97b83b74d26882f8 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 28 Feb 2025 11:03:31 -0500 Subject: [PATCH 012/158] Updates to tutorial outline --- .../tutorials/testing/outline.md | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md index bfcf9398..73e44c39 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/testing/outline.md @@ -2,12 +2,23 @@ - High-level overview of CN +- Overview of this tutorial; road map; what you're going to learn; how + to approach the document, depending on your goals + - "I want to improve the coverage of my tests" + - "I want to learn how to verify C code" + - ... + # Unit Testing (BCP: I'd like to introduce unit testing at the very start, but the Fulminate instructions are currently quite hard to follow! (When) can we improve that?) +(We may actually want to go straight to PBT long term, because unit +testing will be integrated with build systems, unit testing +infrastructure, etc., so more complicated to set up. Hard to predict +exactly how this will look as we scale.) + - Hello-world example of unit testing - instructions for running unit tests themselves @@ -39,13 +50,13 @@ TODO: Complete instructions for running Fulminate on the min3 example. --8<-- ``` -- instructions for running PBT +- instructions for running PBT - an exercise to try it out on min3 - an exercise to find a bug in a variant of min3 - couple more (similar, optional) exercises -- e.g., sorting three - numbers + numbers -- Some more examples of very simple C programs +- Some more examples of very simple C programs - use unsigned arithmetic in all the early sections to avoid UB! - (convert all the existing examples and exercises to unsigned, leaving signed arithmetic and UB to a later section by @@ -58,12 +69,20 @@ work, but it would have the good effect of focusing everybody's attention on specifications and how to think about them, rather than the testing process itself.] +Throughout, we want several sorts of exercises: +- Here's the code; write a spec; now here's a broken version of the + code - does your spec catch it? +- Here's the code; write and validate a spec by breaking it yourself +- Here's a spec; write the program +- Here are requirements (with or without test cases); write the spec + and the code + # Programs with Pointers (but not yet dynamic storage allocation) - read.c - - unannotated version fails tests + - unannotated version fails tests - need to explain how to figure out WHY testing fails! - explain ownership (copy/move from verification tutorial) - version with proper spec works better! @@ -80,7 +99,7 @@ the testing process itself.] - maybe something about swapping pointers? - add_read (but changing it to swapping or something, to avoid UB - issues) + issues) - everything up through pointers to compound objects seems to work well, except for some of the resource inference stuff @@ -100,10 +119,14 @@ the testing process itself.] ## Case studies +Case studies drawn from the SUT(s), focused on specs + - e.g., system never enters bad state + - e.g., code mimics a state machine + Explicit chapters / case studies on each of the "high-value" PBT situations that Harry identified in the Jane Street study - simple memory safety specs - - other simple sanity-check properties + - other simple symbolic sanity-check properties - round-trip properties - model implementations @@ -113,7 +136,7 @@ The current case studies from the verification tutorial ____________________________________________________________________ -# Questions and Discussion Points +# Questions and Discussion Points - The naming of exercises is hideous (esp. the slf ones) From 3df2a643c139f5971363dd79c7c1f09a70b54d7b Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 3 Mar 2025 13:09:19 -0500 Subject: [PATCH 013/158] Reorg --- .../tutorials/testing/outline.md | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md index 73e44c39..e3302208 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/testing/outline.md @@ -1,4 +1,6 @@ -# Introduction +# CN Tutorial + +## Introduction - High-level overview of CN @@ -8,27 +10,7 @@ - "I want to learn how to verify C code" - ... -# Unit Testing - -(BCP: I'd like to introduce unit testing at the very start, but the -Fulminate instructions are currently quite hard to follow! (When) can -we improve that?) - -(We may actually want to go straight to PBT long term, because unit -testing will be integrated with build systems, unit testing -infrastructure, etc., so more complicated to set up. Hard to predict -exactly how this will look as we scale.) - -- Hello-world example of unit testing - -- instructions for running unit tests themselves - - an exercise to try it out on min3 - - an exercise to find a bug in a variant of min3 - - couple more (similar, optional) exercises - -TODO: Complete instructions for running Fulminate on the min3 example. - -# PBT +## PBT - Hello-world example of PBT (min3) - original version: @@ -77,7 +59,7 @@ Throughout, we want several sorts of exercises: - Here are requirements (with or without test cases); write the spec and the code -# Programs with Pointers +## Programs with Pointers (but not yet dynamic storage allocation) @@ -117,6 +99,26 @@ Throughout, we want several sorts of exercises: - Note that the verification tutorial *begins* with an example that testing doesn't handle at all! +# Unit Testing (optional) + +(BCP: I'd like to introduce unit testing at the very start, but the +Fulminate instructions are currently quite hard to follow! (When) can +we improve that?) + +(We may actually want to go straight to PBT long term, because unit +testing will be integrated with build systems, unit testing +infrastructure, etc., so more complicated to set up. Hard to predict +exactly how this will look as we scale.) + +- Hello-world example of unit testing + +- instructions for running unit tests themselves + - an exercise to try it out on min3 + - an exercise to find a bug in a variant of min3 + - couple more (similar, optional) exercises + +TODO: Complete instructions for running Fulminate on the min3 example. + ## Case studies Case studies drawn from the SUT(s), focused on specs @@ -162,11 +164,14 @@ ____________________________________________________________________ ____________________________________________________________________ # CN / VSCode Nits + - It would be nice if (a) errors were indicated more boldly (e.g., a red slug in the margin, not just red squiggles) and (b) successful verification were visually indicated somehow (green light goes on, or whatever). + - VSCode with Copilot currently gives a *lot* of hints (some correct)!! + - One could imagine that users would sometimes want *both* unit tests and PBT. E.g., if the PBT generator is having trouble hitting some parts of the code, they could be covered by hand-written tests. Or From 008781f8fe3297b0ec8360b9df869a3666e7b24d Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 3 Mar 2025 13:30:11 -0500 Subject: [PATCH 014/158] CP --- Makefile | 2 +- docs/getting-started/tutorials/README.md | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index ac1a1d75..1741d5d2 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ docs/solutions/%: src/exercises/% @-mkdir -p _tests @if [ `which cn` ]; then \ if [[ "$<" = *".c"* ]]; then \ - if [[ "$<" != *"broken"* ]]; then \ + if [[ "$<" != *"broken"* && "$<" != *".DS_Store"* ]]; then \ if [[ "$<" = *".test."*c ]]; then \ echo $(CNTEST) $< && $(CNTEST) test $< --output _tests; \ else \ diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index da2ab496..06c1cd9a 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -1,8 +1,22 @@ -# CN Tutorials +# CN Tutorial + +CN is an integrated specification, testing, and verification framework +for low-level software systems written in ISO C. + +This tutorial introduces CN through a series of examples and case +studies, starting with basic usage of CN on simple arithmetic +functions and slowly moving towards more elaborate separation logic +specifications of data structures. + + + +CN can be used in two distinct ways. The simpler usage is as a +framework for writing down formal specifications of C code, in the +form of logical pre- and post-conditions, and _testing_ that the code +agrees with the specification on specific examples. This usage mode +may be sufficient for many purposes. +- -These tutorials introduce CN through a series of examples, starting with basic -usage of CN on simple arithmetic functions and slowly moving towards more -elaborate separation logic specifications of data structures. ## Source files From 15919473c5ee8b09753bdfd86482bfbc02b12914 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 13:30:26 -0500 Subject: [PATCH 015/158] start editing min example --- .../tutorials/testing/min-example.md | 46 +++++-------------- mkdocs.yml | 1 + src/exercises/min3/min3-orig.c | 10 +--- src/exercises/min3/min3.test.c | 10 +--- 4 files changed, 14 insertions(+), 53 deletions(-) diff --git a/docs/getting-started/tutorials/testing/min-example.md b/docs/getting-started/tutorials/testing/min-example.md index 086fa995..1cbcd8ae 100644 --- a/docs/getting-started/tutorials/testing/min-example.md +++ b/docs/getting-started/tutorials/testing/min-example.md @@ -1,39 +1,15 @@ -### Example +Suppose we are writing a function `min3`, which takes three `int` arguments. -C program (with a bug). - -```C -int min3(int x, int y, int z) -{ - if (x <= y && x <= z) { - return x; - } else if (y <= x && x <= z) { - return y; - } else { - return z; - } -} -``` - -Specify the expected behavior of this program. - -```C -/*@ ensures return <= x - && return <= y - && return <= z; -@*/ +```c title="exercises/min3/min3-orig.c" +--8<-- +exercises/min3/min3-orig.c +--8<-- ``` -Run `cn test` and get a counterexample. +The desired behavior of `min3` is to return the smallest of the three numbers. That is, the return value shouuld be less than or equal to `x`, to `y`, and to `z`. More formally: -```C -x = 13 -y = 4 -z = 9 -``` - -Use counterexample to realize and fix the bug. - -```C -else if (y <= x && y <= z) // not x <= z -``` +```c title="exercises/min3/min3.test.c" +--8<-- +exercises/min3/min3-orig.c +--8<-- +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 011317a5..9b662a6d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,6 +102,7 @@ nav: - getting-started/tutorials/README.md - Testing: - "Outline": getting-started/tutorials/testing/outline.md + - "Minimal Start": getting-started/tutorials/testing/min-example.md - "Unit testing overview": getting-started/tutorials/testing/overview-fulminate.md - "PBT overview": getting-started/tutorials/testing/overview-pbt.md - Verification: diff --git a/src/exercises/min3/min3-orig.c b/src/exercises/min3/min3-orig.c index 912cf81e..c8ee3e01 100644 --- a/src/exercises/min3/min3-orig.c +++ b/src/exercises/min3/min3-orig.c @@ -1,12 +1,4 @@ int min3(int x, int y, int z) { - if (x <= y && x <= z) { - return x; - } - else if (y <= x && x <= z) { - return y; - } - else { - return z; - } + // not implemented... } diff --git a/src/exercises/min3/min3.test.c b/src/exercises/min3/min3.test.c index 99abb065..2166e1dd 100644 --- a/src/exercises/min3/min3.test.c +++ b/src/exercises/min3/min3.test.c @@ -4,13 +4,5 @@ int min3(int x, int y, int z) && return <= z; @*/ { - if (x <= y && x <= z) { - return x; - } - else if (y <= x && y <= z) { - return y; - } - else { - return z; - } + // not implemented... } From f2612af086504ce68fb9b5981d0d14a1a16ad22d Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 14:03:53 -0500 Subject: [PATCH 016/158] save progress on min example --- src/exercises/min3/{min3-orig.c => min3.orig.c} | 2 +- src/exercises/min3/min3.test.broken.c | 4 ++-- src/exercises/min3/min3.test.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/exercises/min3/{min3-orig.c => min3.orig.c} (56%) diff --git a/src/exercises/min3/min3-orig.c b/src/exercises/min3/min3.orig.c similarity index 56% rename from src/exercises/min3/min3-orig.c rename to src/exercises/min3/min3.orig.c index c8ee3e01..de3d5cd1 100644 --- a/src/exercises/min3/min3-orig.c +++ b/src/exercises/min3/min3.orig.c @@ -1,4 +1,4 @@ int min3(int x, int y, int z) { - // not implemented... + } diff --git a/src/exercises/min3/min3.test.broken.c b/src/exercises/min3/min3.test.broken.c index 42d6aec5..e64f5685 100644 --- a/src/exercises/min3/min3.test.broken.c +++ b/src/exercises/min3/min3.test.broken.c @@ -7,8 +7,8 @@ int min3(int x, int y, int z) if (x <= y && x <= z) { return x; } - else if (y <= x && x <= z) { // Oops! - return y; + else if (y <= x && y <= z) { + return x; } else { return z; diff --git a/src/exercises/min3/min3.test.c b/src/exercises/min3/min3.test.c index 2166e1dd..818a7b2f 100644 --- a/src/exercises/min3/min3.test.c +++ b/src/exercises/min3/min3.test.c @@ -4,5 +4,5 @@ int min3(int x, int y, int z) && return <= z; @*/ { - // not implemented... + } From 7c6d1bde2560266281d23428744e2bc0364aae78 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 14:04:12 -0500 Subject: [PATCH 017/158] make progress on min example --- docs/getting-started/tutorials/pbt.md | 37 +++++++++++++++++++ .../tutorials/testing/min-example.md | 15 -------- mkdocs.yml | 4 +- 3 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 docs/getting-started/tutorials/pbt.md delete mode 100644 docs/getting-started/tutorials/testing/min-example.md diff --git a/docs/getting-started/tutorials/pbt.md b/docs/getting-started/tutorials/pbt.md new file mode 100644 index 00000000..9d48afb0 --- /dev/null +++ b/docs/getting-started/tutorials/pbt.md @@ -0,0 +1,37 @@ +Suppose we are writing a function `min3`, which takes three `int` arguments. + +```c title="exercises/min3/min3.orig.c" +--8<-- +exercises/min3/min3.orig.c +--8<-- +``` + +The desired behavior of `min3` is to return the smallest of the three inputs. That is, the return value should be less than or equal to `x` and to `y` and to `z`. More formally: + +```c title="exercises/min3/min3.test.c" +--8<-- +exercises/min3/min3.test.c +--8<-- +``` + +In detail: + +- Function specifications are given using special `/*@ ... @*/` comments, placed in-between the function argument list and the function body. + +- The keyword `ensures` indicates the postcondition. + +- The keyword `return` refers to the return value. + +- CN provides a variety of arithmetic and logical operators, which we use here to require that the return value is less than or equal to each of the three inputs. + +- Each clause of the specification concludes with a semicolon. + +Next, suppose we have implemented `min3` as shown below. + +```c title="exercises/min3/min3.test.broken.c" +--8<-- +exercises/min3/min3.test.broken.c +--8<-- +``` + +How can we figure out if our implementation satisfies our specification? We can test it! Run the command `cn test ` to produce this output: diff --git a/docs/getting-started/tutorials/testing/min-example.md b/docs/getting-started/tutorials/testing/min-example.md deleted file mode 100644 index 1cbcd8ae..00000000 --- a/docs/getting-started/tutorials/testing/min-example.md +++ /dev/null @@ -1,15 +0,0 @@ -Suppose we are writing a function `min3`, which takes three `int` arguments. - -```c title="exercises/min3/min3-orig.c" ---8<-- -exercises/min3/min3-orig.c ---8<-- -``` - -The desired behavior of `min3` is to return the smallest of the three numbers. That is, the return value shouuld be less than or equal to `x`, to `y`, and to `z`. More formally: - -```c title="exercises/min3/min3.test.c" ---8<-- -exercises/min3/min3-orig.c ---8<-- -``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 9b662a6d..4072cf88 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,7 +102,7 @@ nav: - getting-started/tutorials/README.md - Testing: - "Outline": getting-started/tutorials/testing/outline.md - - "Minimal Start": getting-started/tutorials/testing/min-example.md + - "Property-Based Testing": getting-started/tutorials/pbt.md - "Unit testing overview": getting-started/tutorials/testing/overview-fulminate.md - "PBT overview": getting-started/tutorials/testing/overview-pbt.md - Verification: @@ -118,7 +118,7 @@ nav: - "Imperative queues": getting-started/case-studies/imperative-queues.md - "Doubly-linked lists": getting-started/case-studies/doubly-linked-lists.md - "Airport Simulation": getting-started/case-studies/the-runway.md - - "Style guide": + - "Style guide": - getting-started/style-guide/README.md - Specifications: - specifications/README.md From 40c21df6884ea48dac2ca518a8506636c173eccf Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 14:04:55 -0500 Subject: [PATCH 018/158] rename file --- docs/getting-started/tutorials/{pbt.md => first-taste.md} | 0 mkdocs.yml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/getting-started/tutorials/{pbt.md => first-taste.md} (100%) diff --git a/docs/getting-started/tutorials/pbt.md b/docs/getting-started/tutorials/first-taste.md similarity index 100% rename from docs/getting-started/tutorials/pbt.md rename to docs/getting-started/tutorials/first-taste.md diff --git a/mkdocs.yml b/mkdocs.yml index 4072cf88..5d7fbb8a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,7 +102,7 @@ nav: - getting-started/tutorials/README.md - Testing: - "Outline": getting-started/tutorials/testing/outline.md - - "Property-Based Testing": getting-started/tutorials/pbt.md + - "First Taste": getting-started/tutorials/pbt.md - "Unit testing overview": getting-started/tutorials/testing/overview-fulminate.md - "PBT overview": getting-started/tutorials/testing/overview-pbt.md - Verification: From 2e5b1da590758b632c336ea136b739401dcebe5e Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 14:09:02 -0500 Subject: [PATCH 019/158] fix filepath --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 5d7fbb8a..a9e40e29 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -102,7 +102,7 @@ nav: - getting-started/tutorials/README.md - Testing: - "Outline": getting-started/tutorials/testing/outline.md - - "First Taste": getting-started/tutorials/pbt.md + - "First Taste": getting-started/tutorials/first-taste.md - "Unit testing overview": getting-started/tutorials/testing/overview-fulminate.md - "PBT overview": getting-started/tutorials/testing/overview-pbt.md - Verification: From bf8caa613adc16121cd746469928910c51dd7fd8 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 15:09:30 -0500 Subject: [PATCH 020/158] finish draft of first chapter --- docs/getting-started/tutorials/first-taste.md | 91 ++++++++++++++++++- src/exercises/min3/min3.fixed.c | 16 ++++ src/exercises/min3/min3.test.broken.c | 2 +- 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/exercises/min3/min3.fixed.c diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 9d48afb0..26ca409a 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -34,4 +34,93 @@ exercises/min3/min3.test.broken.c --8<-- ``` -How can we figure out if our implementation satisfies our specification? We can test it! Run the command `cn test ` to produce this output: +How can we figure out if our implementation satisfies our specification? We can test it! Run the command `cn test ` to produce an output along these lines: + +``` +$ cn test min3.c + +Compiled 'min3_test.c'. +Compiled 'min3-exec.c'. +Compiled 'cn.c'. + +Linked C *.o files. + +Using seed: 50c34e798b33622c +Testing min3::min3: 2 runs +FAILED + +... + +original source location: +/*@ ensures return <= x + ^~~~~~~~~~~ min3.c:2:13-4:28 +CN assertion failed. + + +Testing Summary: +cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 +``` + +Hmm, it seems like there might be an issue with our implementation. We'll return to that in a second, but first, let's explain what happened when we ran `cn test`. + +`cn test` does _property-based testing_. You may instead be accustomed to input-output testing, where the user manually writes unit tests that assert what the output of a function should be on a given input. With property-based testing, things are much more automatic. Test inputs are _randomly generated_, and then assessed against the specification (i.e., the "property"). + +Here, `cn test` generates three integer inputs, runs `min3` on these inputs, and checks that the output satisfies the postcondition. It repeats this process until either some number (by default, 100) of tests succeed, or a failing test, called a _counterexample_, is encountered. + +We can do X to see our counterexample inputs: +``` +x = 13 +y = 4 +z = 9 +``` +(The counterexample you generated is most likely different, due to randomness, but the debugging logic will be the same.) + +Given these three inputs, we expect the function enter this branch: + +```c + else if (y <= x && y <= z) { + return x; + } +``` + +Oops! We made a mistake here. We should `return y`, not `x`, in this case. +Let's fix the bug: + +```c title="exercises/min3/min3.test.c" +--8<-- +exercises/min3/min3.test.c +--8<-- +``` + +Now, if we run `cn test` again, the output should end with this message that the tests passed: + +``` +Testing min3::min3: 100 runs +PASSED + +Testing Summary: +cases: 1, passed: 1, failed: 0, errored: 0, skipped: 0 +``` + +Hooray! + +??? note "(Optional) Verifying `min3`" + Property-based testing is great for increasing our confidence that the function satisfies its specification, but we might also want to _verify_ this formally. Run `cn verify ` on the buggy version to produce this output: + + ``` + [1/1]: min3 -- fail + min3.c:11:9: error: Unprovable constraint + return x; + ^~~~~~~~~ + Constraint from min3.c:2:13: + /*@ ensures return <= x + ^~~~~~~~~~~ + State file: file:///var/folders/_5/81fbkyvn3n5dsm34qw2zpr7w0000gn/T/state__min3.c__min3.html + ``` + + And on the fixed version to produce this output: + ``` + [1/1]: min3 -- pass + ``` + + Whereas `cn test` treats the function body as a black box, `cn verify` analyzes it directly, examining all possible paths through the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. \ No newline at end of file diff --git a/src/exercises/min3/min3.fixed.c b/src/exercises/min3/min3.fixed.c new file mode 100644 index 00000000..c3b3f10e --- /dev/null +++ b/src/exercises/min3/min3.fixed.c @@ -0,0 +1,16 @@ +int min3(int x, int y, int z) +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +{ + if (x <= y && x <= z) { + return x; + } + else if (y <= x && y <= z) { + return y; // fixed + } + else { + return z; + } +} diff --git a/src/exercises/min3/min3.test.broken.c b/src/exercises/min3/min3.test.broken.c index e64f5685..99abb065 100644 --- a/src/exercises/min3/min3.test.broken.c +++ b/src/exercises/min3/min3.test.broken.c @@ -8,7 +8,7 @@ int min3(int x, int y, int z) return x; } else if (y <= x && y <= z) { - return x; + return y; } else { return z; From c27ea8d0f6bb4dd0f0160426769243a129223cc2 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 3 Mar 2025 15:10:13 -0500 Subject: [PATCH 021/158] CP --- docs/getting-started/tutorials/README.md | 46 ++---- docs/getting-started/tutorials/arrays.md | 2 + docs/getting-started/tutorials/basics.md | 22 +++ docs/getting-started/tutorials/dynamic.md | 2 + docs/getting-started/tutorials/numeric.md | 8 + docs/getting-started/tutorials/pointers.md | 27 +++ docs/getting-started/tutorials/setup.md | 8 + .../tutorials/testing/outline.md | 155 +++++------------- .../getting-started/tutorials/unit-testing.md | 18 ++ docs/getting-started/tutorials/welcome.md | 35 ++++ 10 files changed, 176 insertions(+), 147 deletions(-) create mode 100644 docs/getting-started/tutorials/arrays.md create mode 100644 docs/getting-started/tutorials/basics.md create mode 100644 docs/getting-started/tutorials/dynamic.md create mode 100644 docs/getting-started/tutorials/numeric.md create mode 100644 docs/getting-started/tutorials/pointers.md create mode 100644 docs/getting-started/tutorials/setup.md create mode 100644 docs/getting-started/tutorials/unit-testing.md create mode 100644 docs/getting-started/tutorials/welcome.md diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 06c1cd9a..786291e4 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -1,36 +1,22 @@ # CN Tutorial -CN is an integrated specification, testing, and verification framework -for low-level software systems written in ISO C. +- [Welcome](welcome.md) +- [A first taste of CN](first-taste.md) +- [CN basics](basics.md) +- [Working with pointers](pointers.md) +- [Working with arrays](arrays.md) +- [Dynamic storage allocation](dynamic.md) +- [More on numeric types](numeric.md) -This tutorial introduces CN through a series of examples and case -studies, starting with basic usage of CN on simple arithmetic -functions and slowly moving towards more elaborate separation logic -specifications of data structures. - - - -CN can be used in two distinct ways. The simpler usage is as a -framework for writing down formal specifications of C code, in the -form of logical pre- and post-conditions, and _testing_ that the code -agrees with the specification on specific examples. This usage mode -may be sufficient for many purposes. -- - - -## Source files - -The source files for all the exercises and examples below can be downloaded -from [here](link:exercises.zip). - -## Tutorials +## Case studies -### Testing +- [Imperative queues](../case-studies/imperative-queues.md) +- [Doubly-linked lists](../case-studies/doubly-linked-lists.md) +- [Airport Simulation](../case-studies/the-runway.md) -- [Outline](testing/outline.md) -**More links needed here** +## OLD STUFF -### Verification +*Delete me...* - [Basic usage](verification/basic-usage.md) - [Pointers and simple ownership](verification/pointers-and-simple-ownership.md) @@ -41,8 +27,6 @@ from [here](link:exercises.zip). - [Lists](verification/lists.md) - [Working with external lemmas](verification/external-lemmas.md) -## Case studies -- [Imperative queues](../case-studies/imperative-queues.md) -- [Doubly-linked lists](../case-studies/doubly-linked-lists.md) -- [Airport Simulation](../case-studies/the-runway.md) + + diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md new file mode 100644 index 00000000..d52df74c --- /dev/null +++ b/docs/getting-started/tutorials/arrays.md @@ -0,0 +1,2 @@ +# Arrays + diff --git a/docs/getting-started/tutorials/basics.md b/docs/getting-started/tutorials/basics.md new file mode 100644 index 00000000..6f35cae2 --- /dev/null +++ b/docs/getting-started/tutorials/basics.md @@ -0,0 +1,22 @@ +# cn Basics + + - Some more examples of very simple C programs + - use unsigned arithmetic in all the early sections to avoid UB! + - (convert all the existing examples and exercises to unsigned, + leaving signed arithmetic and UB to a later section by + themselves) + + [BCP: In the rest of the tutorial, maybe we could be agnostic + (somewhat agnostic, at least) about whether people are using unit + tests or PBT. I don't have a sense yet of whether that will really + work, but it would have the good effect of focusing everybody's + attention on specifications and how to think about them, rather than + the testing process itself.] + + Throughout, we want several sorts of exercises: + - Here's the code; write a spec; now here's a broken version of the + code - does your spec catch it? + - Here's the code; write and validate a spec by breaking it yourself + - Here's a spec; write the program + - Here are requirements (with or without test cases); write the spec + and the code diff --git a/docs/getting-started/tutorials/dynamic.md b/docs/getting-started/tutorials/dynamic.md new file mode 100644 index 00000000..ea011382 --- /dev/null +++ b/docs/getting-started/tutorials/dynamic.md @@ -0,0 +1,2 @@ +# Dynamic Heap Structures + diff --git a/docs/getting-started/tutorials/numeric.md b/docs/getting-started/tutorials/numeric.md new file mode 100644 index 00000000..eff4041c --- /dev/null +++ b/docs/getting-started/tutorials/numeric.md @@ -0,0 +1,8 @@ +# More on Numeric Types + +- Signed numeric types, sizes, conversions, overflow, etc. + - abs.c is a good exercise (probably we'd just move it entirely, + along with the paragraph above it) + - Checking for UB + - Note that the verification tutorial *begins* with an example that + testing doesn't handle at all! diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md new file mode 100644 index 00000000..2a8e8c3f --- /dev/null +++ b/docs/getting-started/tutorials/pointers.md @@ -0,0 +1,27 @@ +# Programs with Pointers + +(but not yet dynamic storage allocation) + +- read.c + - unannotated version fails tests + - need to explain how to figure out WHY testing fails! + - explain ownership (copy/move from verification tutorial) + - version with proper spec works better! + - (lots of useful text) + - read.broken.c demonstrates linearity of resource usage +- exercises: + - quadruple_mem + - abs_mem +- slf0_basic_incr_signed.c + shows the difference between Block and Owned +- exercises + - zero.c + - basic_inplace_double.c involves UB, so skip? + - maybe something about swapping pointers? + +- add_read (but changing it to swapping or something, to avoid UB + issues) + +- everything up through pointers to compound objects seems to work + well, except for some of the resource inference stuff + diff --git a/docs/getting-started/tutorials/setup.md b/docs/getting-started/tutorials/setup.md new file mode 100644 index 00000000..3f61d8ad --- /dev/null +++ b/docs/getting-started/tutorials/setup.md @@ -0,0 +1,8 @@ +# Getting started + +## Install CN + +*Write me* + +## Download exercise sources + diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md index e3302208..5aefc6a2 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/testing/outline.md @@ -1,123 +1,34 @@ # CN Tutorial -## Introduction - -- High-level overview of CN - -- Overview of this tutorial; road map; what you're going to learn; how - to approach the document, depending on your goals - - "I want to improve the coverage of my tests" - - "I want to learn how to verify C code" - - ... +*Temporary -- stuff is moving to other files...* ## PBT -- Hello-world example of PBT (min3) - - original version: - ```c title="exercises/min3/min3.orig.c" - --8<-- - exercises/min3/min3-orig.c - --8<-- - ``` - - with a specification: - ```c title="exercises/min3/min3.test.c" - --8<-- - exercises/min3/min3.test.c - --8<-- - ``` - - with a spec and a mistake: - ```c title="exercises/min3/min3.brokentest.c" - --8<-- - exercises/min3/min3.brokentest.c - --8<-- - ``` - -- instructions for running PBT - - an exercise to try it out on min3 - - an exercise to find a bug in a variant of min3 - - couple more (similar, optional) exercises -- e.g., sorting three - numbers - -- Some more examples of very simple C programs - - use unsigned arithmetic in all the early sections to avoid UB! - - (convert all the existing examples and exercises to unsigned, - leaving signed arithmetic and UB to a later section by - themselves) - -[BCP: In the rest of the tutorial, maybe we could be agnostic -(somewhat agnostic, at least) about whether people are using unit -tests or PBT. I don't have a sense yet of whether that will really -work, but it would have the good effect of focusing everybody's -attention on specifications and how to think about them, rather than -the testing process itself.] - -Throughout, we want several sorts of exercises: -- Here's the code; write a spec; now here's a broken version of the - code - does your spec catch it? -- Here's the code; write and validate a spec by breaking it yourself -- Here's a spec; write the program -- Here are requirements (with or without test cases); write the spec - and the code - -## Programs with Pointers - -(but not yet dynamic storage allocation) - -- read.c - - unannotated version fails tests - - need to explain how to figure out WHY testing fails! - - explain ownership (copy/move from verification tutorial) - - version with proper spec works better! - - (lots of useful text) - - read.broken.c demonstrates linearity of resource usage -- exercises: - - quadruple_mem - - abs_mem -- slf0_basic_incr_signed.c - shows the difference between Block and Owned -- exercises - - zero.c - - basic_inplace_double.c involves UB, so skip? - - maybe something about swapping pointers? - -- add_read (but changing it to swapping or something, to avoid UB - issues) - -- everything up through pointers to compound objects seems to work - well, except for some of the resource inference stuff - -## Arrays - -## Dynamic Heap Structures - -## Numeric Types - -- Signed numeric types, sizes, conversions, overflow, etc. - - abs.c is a good exercise (probably we'd just move it entirely, - along with the paragraph above it) - - Checking for UB - - Note that the verification tutorial *begins* with an example that - testing doesn't handle at all! - -# Unit Testing (optional) - -(BCP: I'd like to introduce unit testing at the very start, but the -Fulminate instructions are currently quite hard to follow! (When) can -we improve that?) - -(We may actually want to go straight to PBT long term, because unit -testing will be integrated with build systems, unit testing -infrastructure, etc., so more complicated to set up. Hard to predict -exactly how this will look as we scale.) - -- Hello-world example of unit testing - -- instructions for running unit tests themselves - - an exercise to try it out on min3 - - an exercise to find a bug in a variant of min3 - - couple more (similar, optional) exercises - -TODO: Complete instructions for running Fulminate on the min3 example. + - Hello-world example of PBT (min3) + - original version: + ```c title="exercises/min3/min3.orig.c" + --8<-- + exercises/min3/min3-orig.c + --8<-- + ``` + - with a specification: + ```c title="exercises/min3/min3.test.c" + --8<-- + exercises/min3/min3.test.c + --8<-- + ``` + - with a spec and a mistake: + ```c title="exercises/min3/min3.brokentest.c" + --8<-- + exercises/min3/min3.brokentest.c + --8<-- + ``` + + - instructions for running PBT + - an exercise to try it out on min3 + - an exercise to find a bug in a variant of min3 + - couple more (similar, optional) exercises -- e.g., sorting three + numbers ## Case studies @@ -159,7 +70,18 @@ ____________________________________________________________________ but the person on the street will not know what we mean by oracle in this context.) -- The makefile should confirm that broken tests actually break +- The Makefile should confirm that broken tests actually break + +- The Makefile seems to build two copies of the examples (one in + /build, one in /docs). Is this optimal? + +- Throughout, we want several sorts of exercises: + - Here's the code; write a spec; now here's a broken version of the + code - does your spec catch it? + - Here's the code; write and validate a spec by breaking it yourself + - Here's a spec; write the program + - Here are requirements (with or without test cases); write the spec + and the code ____________________________________________________________________ @@ -177,3 +99,4 @@ ____________________________________________________________________ parts of the code, they could be covered by hand-written tests. Or maybe people start by writing unit tests and later add PBT; it would be silly to *not* run the unit tests they've written. + diff --git a/docs/getting-started/tutorials/unit-testing.md b/docs/getting-started/tutorials/unit-testing.md new file mode 100644 index 00000000..aa324fd3 --- /dev/null +++ b/docs/getting-started/tutorials/unit-testing.md @@ -0,0 +1,18 @@ +# Unit Testing (optional) + +(We currently go straight to PBT, because unit testing might be +integrated with build systems, unit testing infrastructure, etc., so +more complicated to set up. Hard to predict exactly how this will +look as we scale.) + +- Hello-world example of unit testing + +- instructions for running unit tests themselves + - an exercise to try it out on min3 + - an exercise to find a bug in a variant of min3 + - couple more (similar, optional) exercises + +TODO: Complete instructions for running Fulminate on the min3 example. + +## Old fulminate insructions + diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md new file mode 100644 index 00000000..cb9d292e --- /dev/null +++ b/docs/getting-started/tutorials/welcome.md @@ -0,0 +1,35 @@ +# Welcome + +CN is an integrated specification, testing, and verification framework +for low-level software systems written in ISO C. + +This tutorial introduces CN through a series of examples and case +studies, starting with basic usage of CN on simple arithmetic +functions and slowly moving towards more elaborate separation logic +specifications of data structures. + + + +CN can be used in two distinct ways: +- The simpler way is as a framework for writing down formal + specifications of C code, in the form of logical pre- and + post-conditions, and _testing_ that the code agrees with its + specification on specific examples. This is sufficient for many + purposes. +- The more sophisticated way is as a framework for _proving_ that C + programs agree with their specifications. This gives a higher level + of assurance, in return for a somewhat larger investment in learning + to use the verification-oriented aspects of CN. + +The main thread of this tutorial is aimed at readers who want to get +up to speed quickly with specifying and testing C programs using +CN. Verification topics are covered in optional sections throughout +the document. Most readers -- even readers whose primary interest is +verification -- should skip these sections on a first reading and, if +desired, come back to them on a second pass. + +Before getting started, make sure you have a running installation of +CN and a local copy of the source files for all the exercises and +examples; these can be downloaded from [here](link:exercises.zip). +*Move that to the first section where we ask +them to do something.* From 72aab6077b7759136dbd4d3c29f249e1fecf9909 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 15:18:12 -0500 Subject: [PATCH 022/158] fix file names --- Makefile | 2 +- docs/getting-started/tutorials/first-taste.md | 8 ++++---- src/exercises/min3/min3.instrument.broken.c | 20 ------------------- src/exercises/min3/min3.instrument.c | 20 ------------------- .../min3/{min3.orig.c => min3.partial.c} | 0 .../min3/{min3.test.c => min3.test.partial.c} | 2 +- 6 files changed, 6 insertions(+), 46 deletions(-) delete mode 100644 src/exercises/min3/min3.instrument.broken.c delete mode 100644 src/exercises/min3/min3.instrument.c rename src/exercises/min3/{min3.orig.c => min3.partial.c} (100%) rename src/exercises/min3/{min3.test.c => min3.test.partial.c} (75%) diff --git a/Makefile b/Makefile index 1741d5d2..d6f66c86 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ docs/solutions/%: src/exercises/% @-mkdir -p _tests @if [ `which cn` ]; then \ if [[ "$<" = *".c"* ]]; then \ - if [[ "$<" != *"broken"* && "$<" != *".DS_Store"* ]]; then \ + if [[ "$<" != *"broken"* && "$<" != *"partial"* && "$<" != *".DS_Store"* ]]; then \ if [[ "$<" = *".test."*c ]]; then \ echo $(CNTEST) $< && $(CNTEST) test $< --output _tests; \ else \ diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 26ca409a..ff732f43 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,16 +1,16 @@ Suppose we are writing a function `min3`, which takes three `int` arguments. -```c title="exercises/min3/min3.orig.c" +```c title="exercises/min3/min3.partial.c" --8<-- -exercises/min3/min3.orig.c +exercises/min3/min3.partial.c --8<-- ``` The desired behavior of `min3` is to return the smallest of the three inputs. That is, the return value should be less than or equal to `x` and to `y` and to `z`. More formally: -```c title="exercises/min3/min3.test.c" +```c title="exercises/min3/min3.test.partial.c" --8<-- -exercises/min3/min3.test.c +exercises/min3/min3.test.partial.c --8<-- ``` diff --git a/src/exercises/min3/min3.instrument.broken.c b/src/exercises/min3/min3.instrument.broken.c deleted file mode 100644 index 8a6e4b2a..00000000 --- a/src/exercises/min3/min3.instrument.broken.c +++ /dev/null @@ -1,20 +0,0 @@ -int min3(int x, int y, int z) -/*@ ensures return <= x - && return <= y - && return <= z; -@*/ -{ - if (x <= y && x <= z) { - return x; - } - else if (y <= x && y <= z) { - return y; - } - else { - return z; - } -} - -int main() { - int r = min3(1,2,3); -} diff --git a/src/exercises/min3/min3.instrument.c b/src/exercises/min3/min3.instrument.c deleted file mode 100644 index 8a6e4b2a..00000000 --- a/src/exercises/min3/min3.instrument.c +++ /dev/null @@ -1,20 +0,0 @@ -int min3(int x, int y, int z) -/*@ ensures return <= x - && return <= y - && return <= z; -@*/ -{ - if (x <= y && x <= z) { - return x; - } - else if (y <= x && y <= z) { - return y; - } - else { - return z; - } -} - -int main() { - int r = min3(1,2,3); -} diff --git a/src/exercises/min3/min3.orig.c b/src/exercises/min3/min3.partial.c similarity index 100% rename from src/exercises/min3/min3.orig.c rename to src/exercises/min3/min3.partial.c diff --git a/src/exercises/min3/min3.test.c b/src/exercises/min3/min3.test.partial.c similarity index 75% rename from src/exercises/min3/min3.test.c rename to src/exercises/min3/min3.test.partial.c index 818a7b2f..b70975ce 100644 --- a/src/exercises/min3/min3.test.c +++ b/src/exercises/min3/min3.test.partial.c @@ -4,5 +4,5 @@ int min3(int x, int y, int z) && return <= z; @*/ { - + return 0; // not implemented yet } From e241c7980d1009220fc34e33ced0459a44d732d8 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 15:18:52 -0500 Subject: [PATCH 023/158] oops --- src/exercises/min3/min3.test.partial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exercises/min3/min3.test.partial.c b/src/exercises/min3/min3.test.partial.c index b70975ce..818a7b2f 100644 --- a/src/exercises/min3/min3.test.partial.c +++ b/src/exercises/min3/min3.test.partial.c @@ -4,5 +4,5 @@ int min3(int x, int y, int z) && return <= z; @*/ { - return 0; // not implemented yet + } From f0850fb7fcec90cde12ee70fdae0f550119dcc17 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 15:20:39 -0500 Subject: [PATCH 024/158] oops again --- docs/getting-started/tutorials/first-taste.md | 4 ++-- src/exercises/min3/min3.test.broken.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index ff732f43..9ca04d21 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -86,9 +86,9 @@ Given these three inputs, we expect the function enter this branch: Oops! We made a mistake here. We should `return y`, not `x`, in this case. Let's fix the bug: -```c title="exercises/min3/min3.test.c" +```c title="exercises/min3/min3.fixed.c" --8<-- -exercises/min3/min3.test.c +exercises/min3/min3.fixed.c --8<-- ``` diff --git a/src/exercises/min3/min3.test.broken.c b/src/exercises/min3/min3.test.broken.c index 99abb065..e64f5685 100644 --- a/src/exercises/min3/min3.test.broken.c +++ b/src/exercises/min3/min3.test.broken.c @@ -8,7 +8,7 @@ int min3(int x, int y, int z) return x; } else if (y <= x && y <= z) { - return y; + return x; } else { return z; From 9f1ca4ec4584933a33b4deb035b3ae9349ba3b32 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 3 Mar 2025 15:21:30 -0500 Subject: [PATCH 025/158] Tidy --- src/exercises/min3/cn.c | 16 ++++ src/exercises/min3/cn.h | 39 ++++++++++ .../min3/min3.instrument.broken-exec.c | 78 +++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/exercises/min3/cn.c create mode 100644 src/exercises/min3/cn.h create mode 100644 src/exercises/min3/min3.instrument.broken-exec.c diff --git a/src/exercises/min3/cn.c b/src/exercises/min3/cn.c new file mode 100644 index 00000000..32b31795 --- /dev/null +++ b/src/exercises/min3/cn.c @@ -0,0 +1,16 @@ +#include "cn.h" + + +/* GENERATED STRUCT FUNCTIONS */ + + + +/* OWNERSHIP FUNCTIONS */ + + + + + +/* CN PREDICATES */ + + diff --git a/src/exercises/min3/cn.h b/src/exercises/min3/cn.h new file mode 100644 index 00000000..2918b9c0 --- /dev/null +++ b/src/exercises/min3/cn.h @@ -0,0 +1,39 @@ +#ifndef CN_HEADER +#define CN_HEADER +#include + + + + + + +/* ORIGINAL C STRUCTS */ + + + +/* CN VERSIONS OF C STRUCTS */ + + + + + + +/* OWNERSHIP FUNCTIONS */ + + + + + +/* GENERATED STRUCT FUNCTIONS */ + + + + + +/* CN FUNCTIONS */ + + + + + +#endif \ No newline at end of file diff --git a/src/exercises/min3/min3.instrument.broken-exec.c b/src/exercises/min3/min3.instrument.broken-exec.c new file mode 100644 index 00000000..fbdd2bfb --- /dev/null +++ b/src/exercises/min3/min3.instrument.broken-exec.c @@ -0,0 +1,78 @@ +#include "cn.h" +#include +#include +#include +#include + +int min3(int x, int y, int z) +/*@ ensures return <= x + && return <= y + && return <= z; +@*/ +{ + /* EXECUTABLE CN PRECONDITION */ + signed int __cn_ret; + ghost_stack_depth_incr(); + cn_bits_i32* x_cn = convert_to_cn_bits_i32(x); + cn_bits_i32* y_cn = convert_to_cn_bits_i32(y); + cn_bits_i32* z_cn = convert_to_cn_bits_i32(z); + + /* C OWNERSHIP */ + + c_add_to_ghost_state((uintptr_t) &x, sizeof(signed int), get_cn_stack_depth()); + c_add_to_ghost_state((uintptr_t) &y, sizeof(signed int), get_cn_stack_depth()); + c_add_to_ghost_state((uintptr_t) &z, sizeof(signed int), get_cn_stack_depth()); + + if (CN_LOAD(x) <= CN_LOAD(y) && CN_LOAD(x) <= CN_LOAD(z)) { + { __cn_ret = CN_LOAD(x); goto __cn_epilogue; } + } + else if (CN_LOAD(y) <= CN_LOAD(x) && CN_LOAD(y) <= CN_LOAD(z)) { + { __cn_ret = CN_LOAD(y); goto __cn_epilogue; } + } + else { + { __cn_ret = CN_LOAD(z); goto __cn_epilogue; } + } + +/* EXECUTABLE CN POSTCONDITION */ +__cn_epilogue: + + + /* C OWNERSHIP */ + + + c_remove_from_ghost_state((uintptr_t) &x, sizeof(signed int)); + + c_remove_from_ghost_state((uintptr_t) &y, sizeof(signed int)); + + c_remove_from_ghost_state((uintptr_t) &z, sizeof(signed int)); + +{ + cn_bits_i32* return_cn = convert_to_cn_bits_i32(__cn_ret); + update_cn_error_message_info("/*@ ensures return <= x\n ^~~~~~~~~~~ min3.instrument.broken.c:2:13-4:28"); + cn_assert(cn_bool_and(cn_bool_and(cn_bits_i32_le(return_cn, x_cn), cn_bits_i32_le(return_cn, y_cn)), cn_bits_i32_le(return_cn, z_cn))); + cn_pop_msg_info(); + ghost_stack_depth_decr(); +} + +return __cn_ret; + +} + +int main() { + /* EXECUTABLE CN PRECONDITION */ + signed int __cn_ret = 0; + initialise_ownership_ghost_state(); + initialise_ghost_stack_depth(); + + int r = min3(1,2,3); +c_add_to_ghost_state((uintptr_t) &r, sizeof(signed int), get_cn_stack_depth()); + + +c_remove_from_ghost_state((uintptr_t) &r, sizeof(signed int)); + +/* EXECUTABLE CN POSTCONDITION */ +__cn_epilogue: + +return __cn_ret; + +} From 70c6075d90b410739b92a140aca3587ab0f32471 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 3 Mar 2025 16:00:13 -0500 Subject: [PATCH 026/158] signed to unsigned --- docs/getting-started/tutorials/cn-basics.md | 8 ++++++++ docs/getting-started/tutorials/first-taste.md | 2 +- mkdocs.yml | 6 ++---- src/exercises/min3/min3.fixed.c | 2 +- src/exercises/min3/min3.partial.c | 2 +- src/exercises/min3/min3.test.broken.c | 2 +- src/exercises/min3/min3.test.partial.c | 2 +- 7 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 docs/getting-started/tutorials/cn-basics.md diff --git a/docs/getting-started/tutorials/cn-basics.md b/docs/getting-started/tutorials/cn-basics.md new file mode 100644 index 00000000..d20e1107 --- /dev/null +++ b/docs/getting-started/tutorials/cn-basics.md @@ -0,0 +1,8 @@ +In this chapter, we will practice writing and testing specifications for simple arithmetic functions. + +[exercise: `add`] +[maybe: exercise: `abs`] + +[example to introduce `requires`: `div`] + +[exercise: `floorsqrt`] \ No newline at end of file diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 9ca04d21..f0baeabf 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -75,7 +75,7 @@ z = 9 ``` (The counterexample you generated is most likely different, due to randomness, but the debugging logic will be the same.) -Given these three inputs, we expect the function enter this branch: +Given these three inputs, we expect the function to enter this branch: ```c else if (y <= x && y <= z) { diff --git a/mkdocs.yml b/mkdocs.yml index a9e40e29..dfcbe8af 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -101,10 +101,8 @@ nav: - Tutorials: - getting-started/tutorials/README.md - Testing: - - "Outline": getting-started/tutorials/testing/outline.md - - "First Taste": getting-started/tutorials/first-taste.md - - "Unit testing overview": getting-started/tutorials/testing/overview-fulminate.md - - "PBT overview": getting-started/tutorials/testing/overview-pbt.md + - "A first taste of CN": getting-started/tutorials/first-taste.md + - "CN basics": getting-started/tutorials/cn-basics.md - Verification: - "Basic usage": getting-started/tutorials/verification/basic-usage.md - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md diff --git a/src/exercises/min3/min3.fixed.c b/src/exercises/min3/min3.fixed.c index c3b3f10e..c6dd2a7f 100644 --- a/src/exercises/min3/min3.fixed.c +++ b/src/exercises/min3/min3.fixed.c @@ -1,4 +1,4 @@ -int min3(int x, int y, int z) +unsigned int min3(unsigned int x, unsigned int y, unsigned int z) /*@ ensures return <= x && return <= y && return <= z; diff --git a/src/exercises/min3/min3.partial.c b/src/exercises/min3/min3.partial.c index de3d5cd1..561c77fd 100644 --- a/src/exercises/min3/min3.partial.c +++ b/src/exercises/min3/min3.partial.c @@ -1,4 +1,4 @@ -int min3(int x, int y, int z) +unsigned int min3(unsigned int x, unsigned int y, unsigned int z) { } diff --git a/src/exercises/min3/min3.test.broken.c b/src/exercises/min3/min3.test.broken.c index e64f5685..582d87d5 100644 --- a/src/exercises/min3/min3.test.broken.c +++ b/src/exercises/min3/min3.test.broken.c @@ -1,4 +1,4 @@ -int min3(int x, int y, int z) +unsigned int min3(unsigned int x, unsigned int y, unsigned int z) /*@ ensures return <= x && return <= y && return <= z; diff --git a/src/exercises/min3/min3.test.partial.c b/src/exercises/min3/min3.test.partial.c index 818a7b2f..6ce215e2 100644 --- a/src/exercises/min3/min3.test.partial.c +++ b/src/exercises/min3/min3.test.partial.c @@ -1,4 +1,4 @@ -int min3(int x, int y, int z) +unsigned int min3(unsigned int x, unsigned int y, unsigned int z) /*@ ensures return <= x && return <= y && return <= z; From 612a49c608e4daaa477e6d97fc22b7465c7f42d8 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 4 Mar 2025 14:05:17 -0500 Subject: [PATCH 027/158] Checkpoint tutorial --- .../{verification => }/images/0.error.png | Bin .../tutorials/verification/basic-usage.md | 236 ------------------ 2 files changed, 236 deletions(-) rename docs/getting-started/tutorials/{verification => }/images/0.error.png (100%) delete mode 100644 docs/getting-started/tutorials/verification/basic-usage.md diff --git a/docs/getting-started/tutorials/verification/images/0.error.png b/docs/getting-started/tutorials/images/0.error.png similarity index 100% rename from docs/getting-started/tutorials/verification/images/0.error.png rename to docs/getting-started/tutorials/images/0.error.png diff --git a/docs/getting-started/tutorials/verification/basic-usage.md b/docs/getting-started/tutorials/verification/basic-usage.md deleted file mode 100644 index 5835bb01..00000000 --- a/docs/getting-started/tutorials/verification/basic-usage.md +++ /dev/null @@ -1,236 +0,0 @@ -# Basic usage - -The simple arithmetic function `add` shown below takes `int` arguments `x` and `y` and returns their sum. - -```c title="exercises/add_0.c" ---8<-- -exercises/add_0.c ---8<-- -``` - -Running CN on the example produces an error message: - -``` -cn verify exercises/add_0.c -[1/1]: add -exercises/add_0.c:3:10: error: Undefined behaviour -return x+y; -~^~ -an exceptional condition occurs during the evaluation of an expression (§6.5#5) -Consider the state in /var/folders/\_v/ndl32rvc8ph0000gn/T/state_393431.html -``` - -CN rejects the program because it has _undefined behaviour_ according to the C standard, meaning it is not safe to execute. CN points to the relevant source location, the addition `x+y`, and paragraph §6.5#5 of the standard, which specifies the undefined behaviour. It also includes a link to an HTML file with more details on the error to help in diagnosing the problem. - -Inspecting this HTML report (as we do in a moment) gives us possible example values for `x` and `y` that cause the undefined behaviour and hint at the problem: for very large values for `x` and `y`, such as `1073741825` and `1073741824`, the sum of `x` and `y` can exceed the representable range of a C `int` value: `1073741825 + 1073741824 = 2^31+1`, so their sum is larger than the maximal `int` value, `2^31-1`. - -Here `x` and `y` are _signed integers_, and in C, signed integer _overflow_ is undefined behaviour (UB). Hence, `add` is only safe to execute for smaller values. Similarly, _large negative_ values of `x` and `y` can cause signed integer _underflow_, also UB in C. We therefore need to rule out too-large values for `x` and `y`, both positive and negative, which we do by writing a CN function specification. - -### First function specification - -Shown below is our first function specification, for `add`, with a precondition that constrains `x` and `y` such that the sum of `x` and `y` lies between `-2147483648` and `2147483647`, so within the representable range of a C `int` value. - -```c title="solutions/add_0.c" ---8<-- -solutions/add_0.c ---8<-- -``` - -In detail: - -- Function specifications are given using special `/*@ ... @*/` comments, placed in-between the function argument list and the function body. - -- The keyword `requires` starts the precondition, a list of one or more CN conditions separated by semicolons. - -- In function specifications, the names of the function arguments, here `x` and `y`, refer to their _initial values_. (Function arguments are mutable in C.) - -- `let Sum = (i64) x + (i64) y` is a let-binding, which defines `Sum` as the value `(i64) x + (i64) y` in the remainder of the function specification. - -- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. - -- To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. - -- Finally, we require this sum to be between the minimal and maximal `int` values. Integer constants, such as `-2147483648i64`, must specifiy their CN type (`i64`). - - - -Running CN on the annotated program passes without errors. This means that, with our specified precondition, `add` is safe to execute. - -We may, however, wish to be more precise. So far, the specification gives no information to callers of `add` about its output. To describe its return value we add a postcondition to the specification using the `ensures` keyword. - -```c title="solutions/add_1.c" ---8<-- -solutions/add_1.c ---8<-- -``` - -Here we use the keyword `return`, which is only available in function -postconditions, to refer to the return value, and we equate it to `Sum` -as defined in the precondition, cast back to `i32` type: that is, `add` -returns the sum of `x` and `y`. - -Running CN confirms that this postcondition also holds. - -One final refinement of this example. CN defines constant functions `MINi32`, `MAXi64`, etc. so that specifications do not need to be littered with unreadable numeric constants. - -```c title="solutions/add_2.c" ---8<-- -solutions/add_2.c ---8<-- -``` - -Two things to note: (1) These are constant _functions_, so they -require a following `()`. And (2) The type of `MINi32()` is `i32`, so -if we want to use it as a 64-bit constant we need to add the explicit -coercion `(i64)`. - -### Error reports - -In the original example, CN reported a type error due to C undefined -behaviour. While that example was perhaps simple enough to guess the -problem and solution, this can become quite challenging as program and -specification complexity increases. Diagnosing errors is -therefore an important part of using CN. CN tries to help with this by -producing detailed error information, in the form of an HTML error -report. - -Let’s return to the type error from earlier -- `add` without -precondition -- and take a closer look at this report. It -comprises two sections: - - - -![*CN error report*](images/0.error.png) - -_Path to error._ The first section contains information about the -control-flow path leading to the error. - -When checking a C function, CN examines each possible control-flow -path individually. If it detects UB or a violation of user-defined -specifications, CN reports the problematic control-flow path as a -nested structure of statements: the path is split into sections that -group together statements between high-level control-flow positions -(e.g. function entry, the start of a loop, the invocation of a -`continue`, `break`, or `return` statement, etc.); within each -section, statements are listed by source code location; finally, per -statement, CN lists the typechecked sub-expressions, and the memory -accesses and function calls within these. - -In our example, there is only one possible control-flow path: entering -the function body (section "`function body`") and executing the block -from lines 2 to 4, followed by the return statement at line 3. The -entry for the latter contains the sequence of sub-expressions in the -return statement, including reads of the variables `x` and `y`. - -In C, local variables in a function, including its arguments, are -mutable, their addresses can be taken and passed as values. CN -therefore represents local variables as memory allocations that are -manipulated using memory reads and writes. Here, type checking the -return statement includes checking memory reads for `x` and `y`, -at their locations `&ARG0` and `&ARG1`. The path report lists -these reads and their return values: the read at `&ARG0` returns -`x` (that is, the value of `x` originally passed to `add`); the -read at `&ARG1` returns `y`. Alongside this symbolic information, -CN displays concrete values: - -- `1073741825i32 /* 0x40000001 */` for x (the first value is the decimal representation, the second, in `/*...*/` comments, the hex equivalent) and - -- `1073741824i32 /* 0x40000000 */` for `y`. - -For now, ignore the pointer values `{@0; 4}` for `x` and `{@0; 0}` for `y`. - - - - -These concrete values are part of a _counterexample_: a concrete -valuation of variables and pointers in the program that that leads to -the error. (The exact values may vary on your machine, depending on -the SMT solver -- i.e., the particular version of Z3, CVC5, or -whatever installed on your system.) - -_Proof context._ The second section, below the error trace, lists the proof context CN has reached along this control-flow path. - -"`Available resources`" lists the owned resources, as discussed in later sections. - -"`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. - - - - -Finally, "`Constraints`" records all logical facts CN has learned along the path. This includes user-specified assumptions from preconditions or loop invariants, value ranges inferred from the C-types of variables, and facts learned during the type checking of the statements. Here -- when checking `add` without precondition -- the only constraints are those inferred from C-types in the code: - -- For instance, `good(x)` says that the initial value of - `x` is a "`good`" `signed int` value (i.e. in range). Here - `signed int` is the same type as `int`, CN just makes the sign - explicit. - - - For an integer type `T`, the type `good` requires the value to - be in range of type `T`; for pointer types `T`, it also requires - the pointer to be aligned. For structs and arrays, this extends in the - obvious way to struct members or array cells. - - -- `repr` requires representability (not alignment) at type `T`, so `repr(&ARGO)`, for instance, records that the pointer to `x` is representable at C-type `signed int*`; - -- `aligned(&ARGO, 4u64)`, moreover, states that it is 4-byte aligned. - - - - - - -### Another arithmetic example - -Let’s apply what we know so far to another simple arithmetic example. - -The function `doubled`, shown below, takes an int `n`, defines `a` as `n` incremented, `b` as `n` decremented, and returns the sum of the two. - - - -```c title="exercises/slf1_basic_example_let.signed.c" ---8<-- -exercises/slf1_basic_example_let.signed.c ---8<-- -``` - -We would like to verify this is safe and that `doubled` returns twice the value of `n`. Running CN on `doubled` leads to a type error: the increment of `a` has undefined behaviour. - -As in the first example, we need to ensure that `n+1` does not overflow and `n-1` does not underflow. Similarly `a+b` has to be representable at `int` type. - -```c title="solutions/slf1_basic_example_let.signed.c" ---8<-- -solutions/slf1_basic_example_let.signed.c ---8<-- -``` - - - - -We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. - - - - - -To capture the functional behaviour, the postcondition specifies that `return` is twice the value of `n`. - -### Exercises - -_Quadruple._ Specify the precondition needed to ensure safety of the C function `quadruple`, and a postcondition that describes its return value. - -```c title="exercises/slf2_basic_quadruple.signed.c" ---8<-- -exercises/slf2_basic_quadruple.signed.c ---8<-- -``` - -_Abs._ Give a specification to the C function `abs`, which computes the absolute value of a given `int` value. To describe the return value, use CN’s ternary "`_ ? _ : _`" operator. Given a boolean `b`, and expressions `e1` and `e2` of the same basetype, `b ? e1 : e2` returns `e1` if `b` holds and `e2` otherwise. -Note that most binary operators in CN have higher precedence than the ternary operator, so depending on your solution you may need to place the ternary expression in parentheses. - -```c title="exercises/abs.c" ---8<-- -exercises/abs.c ---8<-- -``` - From d89646363e1d280bfc7f14ee3f24d9827a43054d Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 4 Mar 2025 14:06:03 -0500 Subject: [PATCH 028/158] CP --- docs/getting-started/tutorials/README.md | 2 +- .../tutorials/basics-with.verification.md | 2 + docs/getting-started/tutorials/numeric.md | 250 +++++++++++++++++- .../tutorials/testing/outline.md | 4 + 4 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 docs/getting-started/tutorials/basics-with.verification.md diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 786291e4..97407162 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -3,6 +3,7 @@ - [Welcome](welcome.md) - [A first taste of CN](first-taste.md) - [CN basics](basics.md) +- [CN basics (with verification)](basics-with-verification.md) - [Working with pointers](pointers.md) - [Working with arrays](arrays.md) - [Dynamic storage allocation](dynamic.md) @@ -18,7 +19,6 @@ *Delete me...* -- [Basic usage](verification/basic-usage.md) - [Pointers and simple ownership](verification/pointers-and-simple-ownership.md) - [Ownership of compound objects](verification/ownership-of-compound-objects.md) - [Arrays and loops](verification/arrays-and-loops.md) diff --git a/docs/getting-started/tutorials/basics-with.verification.md b/docs/getting-started/tutorials/basics-with.verification.md new file mode 100644 index 00000000..49cebaca --- /dev/null +++ b/docs/getting-started/tutorials/basics-with.verification.md @@ -0,0 +1,2 @@ +# CN Basics (with Verification) + diff --git a/docs/getting-started/tutorials/numeric.md b/docs/getting-started/tutorials/numeric.md index eff4041c..b3eed4f7 100644 --- a/docs/getting-started/tutorials/numeric.md +++ b/docs/getting-started/tutorials/numeric.md @@ -1,8 +1,242 @@ -# More on Numeric Types - -- Signed numeric types, sizes, conversions, overflow, etc. - - abs.c is a good exercise (probably we'd just move it entirely, - along with the paragraph above it) - - Checking for UB - - Note that the verification tutorial *begins* with an example that - testing doesn't handle at all! +# More on Numeric Types (Verification) + + TODO + - We need to talk in another (non-optional) section about signed types in the + context of specification and testing. + - Talk here about CN's signed numeric types, sizes, conversions, + overflow, etc. + +So far, we have worked entirely with unsigned 32-bit integers. These +are simpler to deal with than C's signed integers, which introduce the +possibility of _undefined behavior_. + +## Signed Arithmetic and Undefined Behavior + +The simple arithmetic function `add` shown below takes `int` arguments `x` and `y` and returns their sum. + +```c title="exercises/add_0.c" +--8<-- +exercises/add_0.c +--8<-- +``` + +Running `cn verify` on the example produces an error message: + +``` +cn verify exercises/add_0.c +[1/1]: add +exercises/add_0.c:3:10: error: Undefined behaviour +return x+y; +~^~ +an exceptional condition occurs during the evaluation of an expression (§6.5#5) +Consider the state in /var/folders/\_v/ndl32rvc8ph0000gn/T/state_393431.html +``` + +CN rejects the program because it has _undefined behaviour_ according to the C standard, meaning it is not safe to execute. CN points to the relevant source location, the addition `x+y`, and paragraph §6.5#5 of the standard, which specifies the undefined behaviour. It also includes a link to an HTML file with more details on the error to help in diagnosing the problem. + +Inspecting this HTML report (as we do in a moment) gives us possible example values for `x` and `y` that cause the undefined behaviour and hint at the problem: for very large values for `x` and `y`, such as `1073741825` and `1073741824`, the sum of `x` and `y` can exceed the representable range of a C `int` value: `1073741825 + 1073741824 = 2^31+1`, so their sum is larger than the maximal `int` value, `2^31-1`. + +Here `x` and `y` are _signed integers_, and in C, signed integer _overflow_ is undefined behaviour (UB). Hence, `add` is only safe to execute for smaller values. Similarly, _large negative_ values of `x` and `y` can cause signed integer _underflow_, also UB in C. We therefore need to rule out too-large values for `x` and `y`, both positive and negative, which we do by writing a CN function specification. + +### First function specification + +Shown below is our first function specification, for `add`, with a precondition that constrains `x` and `y` such that the sum of `x` and `y` lies between `-2147483648` and `2147483647`, so within the representable range of a C `int` value. + +```c title="solutions/add_0.c" +--8<-- +solutions/add_0.c +--8<-- +``` + +In detail: + +- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. + +- To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. + +- Finally, we require this sum to be between the minimal and maximal `int` values. Integer constants, such as `-2147483648i64`, must specifiy their CN type (`i64`). + + + +Running CN on the annotated program passes without errors. This means that, with our specified precondition, `add` is safe to execute. + +We may, however, wish to be more precise. So far, the specification gives no information to callers of `add` about its output. To describe its return value we add a postcondition to the specification using the `ensures` keyword. + +```c title="solutions/add_1.c" +--8<-- +solutions/add_1.c +--8<-- +``` + +Here, we specify that the return value is equal to `Sum` +as defined in the precondition, cast back to `i32` type: that is, `add` +returns the sum of `x` and `y`. + +Running CN confirms that this postcondition also holds. + +One final refinement of this example. CN defines constant functions `MINi32`, `MAXi64`, etc. so that specifications do not need to be littered with unreadable numeric constants. + +```c title="solutions/add_2.c" +--8<-- +solutions/add_2.c +--8<-- +``` + +Two things to note: (1) These are constant _functions_, so they +require a following `()`. And (2) The type of `MINi32()` is `i32`, so +if we want to use it as a 64-bit constant we need to add the explicit +coercion `(i64)`. + +## Error reports + +*Most of this material needs to be moved to +the first section where we talk about verification, but it will need a +different example (not involving i32 or UB)...* + +In the original example, CN reported a type error due to C undefined +behavior. While that example was perhaps simple enough to guess the +problem and solution, this can become quite challenging as program and +specification complexity increases. Diagnosing errors is +therefore an important part of using CN. CN tries to help with this by +producing detailed error information, in the form of an HTML error +report. + +Let’s return to the type error from earlier -- `add` without +precondition -- and take a closer look at this report. It +comprises two sections: + + + +![*CN error report*](images/0.error.png) + +_Path to error._ The first section contains information about the +control-flow path leading to the error. + +When checking a C function, CN examines each possible control-flow +path individually. If it detects UB or a violation of user-defined +specifications, CN reports the problematic control-flow path as a +nested structure of statements: the path is split into sections that +group together statements between high-level control-flow positions +(e.g. function entry, the start of a loop, the invocation of a +`continue`, `break`, or `return` statement, etc.); within each +section, statements are listed by source code location; finally, per +statement, CN lists the typechecked sub-expressions, and the memory +accesses and function calls within these. + +In our example, there is only one possible control-flow path: entering +the function body (section "`function body`") and executing the block +from lines 2 to 4, followed by the return statement at line 3. The +entry for the latter contains the sequence of sub-expressions in the +return statement, including reads of the variables `x` and `y`. + +In C, local variables in a function, including its arguments, are +mutable, their addresses can be taken and passed as values. CN +therefore represents local variables as memory allocations that are +manipulated using memory reads and writes. Here, type checking the +return statement includes checking memory reads for `x` and `y`, +at their locations `&ARG0` and `&ARG1`. The path report lists +these reads and their return values: the read at `&ARG0` returns +`x` (that is, the value of `x` originally passed to `add`); the +read at `&ARG1` returns `y`. Alongside this symbolic information, +CN displays concrete values: + +- `1073741825i32 /* 0x40000001 */` for x (the first value is the decimal representation, the second, in `/*...*/` comments, the hex equivalent) and + +- `1073741824i32 /* 0x40000000 */` for `y`. + +For now, ignore the pointer values `{@0; 4}` for `x` and `{@0; 0}` for `y`. + + + + +These concrete values are part of a _counterexample_: a concrete +valuation of variables and pointers in the program that that leads to +the error. (The exact values may vary on your machine, depending on +the SMT solver -- i.e., the particular version of Z3, CVC5, or +whatever installed on your system.) + +_Proof context._ The second section, below the error trace, lists the proof context CN has reached along this control-flow path. + +"`Available resources`" lists the owned resources, as discussed in later sections. + +"`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. + + + + +Finally, "`Constraints`" records all logical facts CN has learned along the path. This includes user-specified assumptions from preconditions or loop invariants, value ranges inferred from the C-types of variables, and facts learned during the type checking of the statements. Here -- when checking `add` without precondition -- the only constraints are those inferred from C-types in the code: + +- For instance, `good(x)` says that the initial value of + `x` is a "`good`" `signed int` value (i.e. in range). Here + `signed int` is the same type as `int`, CN just makes the sign + explicit. + + + For an integer type `T`, the type `good` requires the value to + be in range of type `T`; for pointer types `T`, it also requires + the pointer to be aligned. For structs and arrays, this extends in the + obvious way to struct members or array cells. + + +- `repr` requires representability (not alignment) at type `T`, so `repr(&ARGO)`, for instance, records that the pointer to `x` is representable at C-type `signed int*`; + +- `aligned(&ARGO, 4u64)`, moreover, states that it is 4-byte aligned. + + + + + + +### Another arithmetic example + +Let’s apply what we know so far to another simple arithmetic example. + +The function `doubled`, shown below, takes an int `n`, defines `a` as `n` incremented, `b` as `n` decremented, and returns the sum of the two. + + + +```c title="exercises/slf1_basic_example_let.signed.c" +--8<-- +exercises/slf1_basic_example_let.signed.c +--8<-- +``` + +We would like to verify this is safe and that `doubled` returns twice the value of `n`. Running CN on `doubled` leads to a type error: the increment of `a` has undefined behaviour. + +As in the first example, we need to ensure that `n+1` does not overflow and `n-1` does not underflow. Similarly `a+b` has to be representable at `int` type. + +```c title="solutions/slf1_basic_example_let.signed.c" +--8<-- +solutions/slf1_basic_example_let.signed.c +--8<-- +``` + + + + +We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. + + + + + +To capture the functional behaviour, the postcondition specifies that `return` is twice the value of `n`. + +### Exercises + +_Quadruple._ Specify the precondition needed to ensure safety of the C function `quadruple`, and a postcondition that describes its return value. + +```c title="exercises/slf2_basic_quadruple.signed.c" +--8<-- +exercises/slf2_basic_quadruple.signed.c +--8<-- +``` + +_Abs._ Give a specification to the C function `abs`, which computes the absolute value of a given `int` value. To describe the return value, use CN’s ternary "`_ ? _ : _`" operator. Given a boolean `b`, and expressions `e1` and `e2` of the same basetype, `b ? e1 : e2` returns `e1` if `b` holds and `e2` otherwise. +Note that most binary operators in CN have higher precedence than the ternary operator, so depending on your solution you may need to place the ternary expression in parentheses. + +```c title="exercises/abs.c" +--8<-- +exercises/abs.c +--8<-- +``` diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/testing/outline.md index 5aefc6a2..aacbb80a 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/testing/outline.md @@ -83,6 +83,10 @@ ____________________________________________________________________ - Here are requirements (with or without test cases); write the spec and the code +- Not sure exactly how to talk about signed arithmetic, etc., in the + context of "plain old specification and testing", before we get to + verification. + ____________________________________________________________________ # CN / VSCode Nits From 78610931f48454056424a7f91ec93de614818a25 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 4 Mar 2025 14:07:39 -0500 Subject: [PATCH 029/158] yCP --- .../{basics-with.verification.md => basics-with=verification.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/getting-started/tutorials/{basics-with.verification.md => basics-with=verification.md} (100%) diff --git a/docs/getting-started/tutorials/basics-with.verification.md b/docs/getting-started/tutorials/basics-with=verification.md similarity index 100% rename from docs/getting-started/tutorials/basics-with.verification.md rename to docs/getting-started/tutorials/basics-with=verification.md From 7f459558b6f58c74a240f1e6a8ef7237fb839219 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 4 Mar 2025 21:55:43 -0500 Subject: [PATCH 030/158] Work on tutorial --- README.md | 2 +- docs/README.md | 14 +- docs/getting-started/tutorials/0.error.png | Bin 786536 -> 0 bytes docs/getting-started/tutorials/README.md | 2 + ...ication.md => basics-with-verification.md} | 0 docs/getting-started/tutorials/first-taste.md | 21 +- docs/getting-started/tutorials/pointers.md | 373 ++++++++++++++++-- .../pointers-and-simple-ownership.md | 2 +- mkdocs.yml | 27 +- src/exercises/min3/cn.c | 16 - src/exercises/min3/cn.h | 39 -- .../min3/min3.instrument.broken-exec.c | 78 ---- src/exercises/min3/min3.test.partial.c | 2 +- src/exercises/read.c | 2 +- 14 files changed, 386 insertions(+), 192 deletions(-) delete mode 100644 docs/getting-started/tutorials/0.error.png rename docs/getting-started/tutorials/{basics-with=verification.md => basics-with-verification.md} (100%) delete mode 100644 src/exercises/min3/cn.c delete mode 100644 src/exercises/min3/cn.h delete mode 100644 src/exercises/min3/min3.instrument.broken-exec.c diff --git a/README.md b/README.md index 89765e8a..074a6e70 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Install dependencies: [asciidoctor](https://asciidoctor.org/). ## Tutorial examples -The tutorial examples live in [src/examples](./src/examples). +The tutorial examples live in [src/exercises](./src/exercises). As part of building the tutorial, the examples are lightly preprocessed to produce solutions and exercises (solutions with the CN specifications removed). diff --git a/docs/README.md b/docs/README.md index 84186c6e..85367959 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,22 +37,14 @@ appreciated! [:octicons-arrow-right-24: Installing CN](getting-started/installation.md) -- :fontawesome-brands-markdown:{ .lg .middle } __Your first spec__ +- :fontawesome-brands-markdown:{ .lg .middle } __Tutorial__ --- - Check out the *Basic Usage* tutorial to write, test, and verify your first + Check out the tutorial to learn how to write, test, and verify your first spec - [:octicons-arrow-right-24: Basic Usage](getting-started/tutorials/verification/basic-usage.md) - -- :material-format-font:{ .lg .middle } __Tutorials__ - - --- - - Find tutorials covering common tasks and introducing CN features - - [:octicons-arrow-right-24: Tutorials](getting-started/tutorials/README.md) + [:octicons-arrow-right-24: Tutorial](getting-started/tutorials/README.md) - :material-scale-balance:{ .lg .middle } __Language reference__ diff --git a/docs/getting-started/tutorials/0.error.png b/docs/getting-started/tutorials/0.error.png deleted file mode 100644 index 5aa67693c0ec7709085fbb79fd965c10939401ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 786536 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

    Sx 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�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 z
    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 on the buggy version to produce this output: @@ -123,4 +136,4 @@ Hooray! [1/1]: min3 -- pass ``` - Whereas `cn test` treats the function body as a black box, `cn verify` analyzes it directly, examining all possible paths through the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. \ No newline at end of file + Whereas `cn test` treats the function body as a black box, `cn verify` analyzes it directly, examining all possible paths through the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 2a8e8c3f..6e3b3fff 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,27 +1,348 @@ -# Programs with Pointers - -(but not yet dynamic storage allocation) - -- read.c - - unannotated version fails tests - - need to explain how to figure out WHY testing fails! - - explain ownership (copy/move from verification tutorial) - - version with proper spec works better! - - (lots of useful text) - - read.broken.c demonstrates linearity of resource usage -- exercises: - - quadruple_mem - - abs_mem -- slf0_basic_incr_signed.c - shows the difference between Block and Owned -- exercises - - zero.c - - basic_inplace_double.c involves UB, so skip? - - maybe something about swapping pointers? - -- add_read (but changing it to swapping or something, to avoid UB - issues) - -- everything up through pointers to compound objects seems to work - well, except for some of the resource inference stuff +# Pointers and Simple Ownership + + TODO + + - read.c + - unannotated version fails tests + - need to explain how to figure out WHY testing fails! + - explain ownership (copy/move from verification tutorial) + - version with proper spec works better! + - (lots of useful text) + - read.broken.c demonstrates linearity of resource usage + - exercises: + - quadruple_mem + - abs_mem + - slf0_basic_incr_signed.c + shows the difference between Block and Owned + - exercises + - zero.c + - basic_inplace_double.c involves UB, so skip? + - maybe something about swapping pointers? + + - add_read (but changing it to swapping or something, to avoid UB + issues) + + - everything up through pointers to compound objects seems to work + well, except for some of the resource inference stuff + +So far we’ve only considered functions manipulating integer +values. Specifications become more interesting and challenging when +_pointers_ are involved, because the safety of memory accesses via +pointers has to be taken into account. + +CN uses _separation logic resources_ and the concept of _ownership_ to +reason about memory accesses. A resource is the permission to access a +region of memory. Unlike logical constraints, resource ownership is +_unique_, meaning resources cannot be duplicated. + +Let’s look at a simple example. The function `read` takes an integer +pointer `p` and returns the pointee value. + +```c title="exercises/read.c" +--8<-- +exercises/read.c +--8<-- +``` + +Running CN on this example produces the following error: + + +``` +cn test read.c +Compiled 'read_test.c'. +Compiled 'read-exec.c'. +Compiled 'cn.c'. + +Linked C *.o files. + +Using seed: 65a9c0d1f79889a9 +Testing read::read: +FAILED + +Testing Summary: +cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 +``` + +For the read `*p` to be safe, we need to know that the function has +permission to access the memory pointed to by `p`. This permission is +represented by a _resource_ `Owned(p)`. + +### Owned resources + +Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). + +In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as shown below. For now ignore the notation `take ... = Owned(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. + +```c title="solutions/read.c" +--8<-- +solutions/read.c +--8<-- +``` + +This specification means that: + +- any function calling `read` has to be able to provide a resource `Owned(p)` to pass into `read`, and + +- the caller will receive back a resource `Owned(p)` when `read` returns. + +### Resource outputs + +A caller of `read` may also wish to know that `read` actually returns the correct value, the pointee of `p`, and also that it does not change memory at location `p`. To phrase both we need a way to refer to the pointee of `p`. + + + +In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `Owned(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. + + + + +CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = Owned(p)` does two things: (1) it assert ownership of resource `Owned(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. + + + + + +That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying + +1. that `read` returns `P` (the initial pointee value of `p`), and +1. that the pointee values `P` and `P_post` before and after execution of `read` (respectively) are the same. + +```c title="exercises/read2.c" +--8<-- +exercises/read2.c +--8<-- +``` + +_Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): + + + + + +``` +∀p. +∀v1. +{ p ↦ P } +read(p) +{ \return. ∃P_post. (p ↦ P_post) /\ return = P /\ P = P_post } +``` + +CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. + +### Linear resource ownership + +In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. + +Let’s try the `read` example from earlier again, but with a postcondition that does not return the ownership: + +```c title="exercises/read.broken.c" +--8<-- +exercises/read.broken.c +--8<-- +``` + +CN rejects this program with the following message: + +``` +cn verify exercises/read.broken.c +[1/1]: read +build/exercises/read.broken.c:4:3: error: Left_Sublist-over unused resource 'Owned(p)(v1)' +return \*p; +^~~~~~~~~~ +Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_17eb4a.html +``` + +CN has typechecked the function and verified (1) that it is safe to +execute under the precondition (given ownership `Owned(p)`) +and (2) that the function (vacuously) satisfies its postcondition. But +following the check of the postcondition it finds that not all +resources have been "`used up`". + +Indeed, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. + +CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "`forgotten`". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). + +CN’s motivation for linear tracking of resources is its focus on +low-level systems software in which memory is managed manually; in +this context, memory leaks are typically very undesirable. As a +consequence, function specifications have to do precise bookkeeping of +their resource footprint and, in particular, return any unused +resources back to the caller. + +### Exercises + +_Quadruple_. Specify the function `quadruple_mem`, which is similar to the earlier `quadruple` function, except that the input is passed as an `int` pointer. Write a specification that takes ownership of this pointer on entry and returns this ownership on exit, leaving the pointee value unchanged. + +```c title="exercises/slf_quadruple_mem.c" +--8<-- +exercises/slf_quadruple_mem.c +--8<-- +``` + +_Abs_. Give a specification to the function `abs_mem`, which computes the absolute value of a number passed as an `int` pointer. + +```c title="exercises/abs_mem.c" +--8<-- +exercises/abs_mem.c +--8<-- +``` + +### Block resources + +Aside from the `Owned` resources seen so far, CN has another +built-in type of resource called `Block`. Given a C-type `T` and +pointer `p`, `Block(p)` asserts the same ownership as +`Owned(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `Owned`, `Block` memory is not assumed +to be initialised. + +CN uses this distinction to prevent reads from uninitialised memory: + +- A read at C-type `T` and pointer `p` requires a resource + `Owned(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `Owned` resource unchanged. + +- A write at C-type `T` and pointer `p` needs only a +`Block(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `Block` resource +(it destroys it) and returns a new resource `Owned(p)` with the +value written as the output. This means the resource returned from a +write records the fact that this memory cell is now initialised and +can be read from. + + +Since `Owned` carries the same ownership as `Block`, just with the +additional information that the `Owned` memory is initalised, a +resource `Owned(p)` is "`at least as good`" as `Block(p)` — +an `Owned(p)` resource can be used whenever `Block(p)` is +needed. For instance CN’s type checking of a write to `p` requires a +`Block(p)`, but if an `Owned(p)` resource is what is +available, this can be used just the same. This allows an +already-initialised memory cell to be over-written again. + +Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. + +### Writing through pointers + +Let’s explore resources and their outputs in another example. The C function `incr` takes an `int` pointer `p` and increments the value in the memory cell that it poinbts to. + +```c title="exercises/slf0_basic_incr.signed.c" +--8<-- +exercises/slf0_basic_incr.signed.c +--8<-- +``` + +In the precondition we assert ownership of resource `Owned(p)`, +binding its output/pointee value to `P`, and use `P` to specify +that `p` must point to a sufficiently small value at the start of +the function so as not to overflow when incremented. The postcondition +asserts ownership of `p` with output `P_post`, as before, and uses +this to express that the value `p` points to is incremented by +`incr`: `P_post == P + 1i32`. + +If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. + +```c title="exercises/slf0_basic_incr.signed.broken.c" +--8<-- +exercises/slf0_basic_incr.signed.broken.c +--8<-- +``` + +CN reports: + +``` +build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading +int n = \*p; +^~ +Resource needed: Owned(p) +Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html +``` + +The `Owned(p)` resource required for reading is missing, since, per the precondition, only `Block(p)` is available. Checking the linked HTML file confirms this. Here the section "`Available resources`" lists all resource ownership at the point of the failure: + +- `Block(p)(u)`, i.e., ownership of uninitialised memory + at location `p`; the output is a `void`/`unit` value `u` + (specified in the second pair of parentheses) + +- `Owned(&ARG0)(p)`, the ownership of (initialised) + memory at location `&ARG0`, i.e., the memory location where the + first function argument is stored; its output is the pointer `p` + (not to be confused with the pointee of `p`); and finally + +- `__CN_Alloc(&ARG0)(void)` is a resource that records allocation + information for location `&ARG0`; this is related to CN’s + memory-object semantics, which we ignore for the moment. + + + + +### Exercises + +_Zero._ Write a specification for the function `zero`, which takes a pointer to _uninitialised_ memory and initialises it to `0`. + +```c title="exercises/zero.c" +--8<-- +exercises/zero.c +--8<-- +``` + +_In-place double._ Give a specification for the function `inplace_double`, which takes an `int` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. + +```c title="exercises/slf3_basic_inplace_double.c" +--8<-- +exercises/slf3_basic_inplace_double.c +--8<-- +``` + +### Multiple owned pointers + +When functions manipulate multiple pointers, we can assert their +ownership just like before. However +pointer ownership in CN is unique -- that is, simultaneously owning +`Owned` or `Block` resources for two pointers implies that these +pointers are disjoint. + +The following example shows the use of two `Owned` resources for +accessing two different pointers by a function `add`, which reads +two `int` values in memory, at locations `p` and `q`, and +returns their sum. + + + +```c title="exercises/add_read.c" +--8<-- +exercises/add_read.c +--8<-- +``` + +This time we use C’s `unsigned int` type. In C, over- and underflow of unsigned integers is not undefined behaviour, so we do not need any special preconditions to rule this out. Instead, when an arithmetic operation at unsigned type goes outside the representable range, the value "`wraps around`". + +The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. + +Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. + + + + + +In the following we will sometimes use unsigned integer types to focus on specifying memory ownership, rather than the conditions necessary to show absence of C arithmetic undefined behaviour. + +### Exercises + +_Swap._ Specify the function `swap`, which takes two owned `unsigned int` pointers and swaps their values. + +```c title="exercises/swap.c" +--8<-- +exercises/swap.c +--8<-- +``` + +_Transfer._ Write a specification for the function `transfer`, shown below. + +```c title="exercises/slf8_basic_transfer.c" +--8<-- +exercises/slf8_basic_transfer.c +--8<-- +``` + diff --git a/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md b/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md index 961661e0..059efc94 100644 --- a/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md +++ b/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md @@ -1,4 +1,4 @@ -# Pointer and Simple Ownership +# Pointers and Simple Ownership So far we’ve only considered example functions manipulating integer values. Verification becomes more interesting and challenging when _pointers_ are involved, because the safety of memory accesses via pointers has to be verified. diff --git a/mkdocs.yml b/mkdocs.yml index dfcbe8af..573c9536 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -98,20 +98,19 @@ nav: - Getting started: - README.md - Installation: getting-started/installation.md - - Tutorials: - - getting-started/tutorials/README.md - - Testing: - - "A first taste of CN": getting-started/tutorials/first-taste.md - - "CN basics": getting-started/tutorials/cn-basics.md - - Verification: - - "Basic usage": getting-started/tutorials/verification/basic-usage.md - - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md - - "Ownership of compound objects": getting-started/tutorials/verification/ownership-of-compound-objects.md - - "Arrays and loops": getting-started/tutorials/verification/arrays-and-loops.md - - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md - - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md - - "Lists": getting-started/tutorials/verification/lists.md - - "Working with external lemmas": getting-started/tutorials/verification/external-lemmas.md + - Tutorial: getting-started/tutorials/README.md +# - Testing: +# - "A first taste of CN": getting-started/tutorials/first-taste.md +# - "CN basics": getting-started/tutorials/cn-basics.md +# - Verification: +# - "Basic usage": getting-started/tutorials/verification/basic-usage.md +# - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md +# - "Ownership of compound objects": getting-started/tutorials/verification/ownership-of-compound-objects.md +# - "Arrays and loops": getting-started/tutorials/verification/arrays-and-loops.md +# - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md +# - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md +# - "Lists": getting-started/tutorials/verification/lists.md +# - "Working with external lemmas": getting-started/tutorials/verification/external-lemmas.md - "Case studies": - "Imperative queues": getting-started/case-studies/imperative-queues.md - "Doubly-linked lists": getting-started/case-studies/doubly-linked-lists.md diff --git a/src/exercises/min3/cn.c b/src/exercises/min3/cn.c deleted file mode 100644 index 32b31795..00000000 --- a/src/exercises/min3/cn.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "cn.h" - - -/* GENERATED STRUCT FUNCTIONS */ - - - -/* OWNERSHIP FUNCTIONS */ - - - - - -/* CN PREDICATES */ - - diff --git a/src/exercises/min3/cn.h b/src/exercises/min3/cn.h deleted file mode 100644 index 2918b9c0..00000000 --- a/src/exercises/min3/cn.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef CN_HEADER -#define CN_HEADER -#include - - - - - - -/* ORIGINAL C STRUCTS */ - - - -/* CN VERSIONS OF C STRUCTS */ - - - - - - -/* OWNERSHIP FUNCTIONS */ - - - - - -/* GENERATED STRUCT FUNCTIONS */ - - - - - -/* CN FUNCTIONS */ - - - - - -#endif \ No newline at end of file diff --git a/src/exercises/min3/min3.instrument.broken-exec.c b/src/exercises/min3/min3.instrument.broken-exec.c deleted file mode 100644 index fbdd2bfb..00000000 --- a/src/exercises/min3/min3.instrument.broken-exec.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "cn.h" -#include -#include -#include -#include - -int min3(int x, int y, int z) -/*@ ensures return <= x - && return <= y - && return <= z; -@*/ -{ - /* EXECUTABLE CN PRECONDITION */ - signed int __cn_ret; - ghost_stack_depth_incr(); - cn_bits_i32* x_cn = convert_to_cn_bits_i32(x); - cn_bits_i32* y_cn = convert_to_cn_bits_i32(y); - cn_bits_i32* z_cn = convert_to_cn_bits_i32(z); - - /* C OWNERSHIP */ - - c_add_to_ghost_state((uintptr_t) &x, sizeof(signed int), get_cn_stack_depth()); - c_add_to_ghost_state((uintptr_t) &y, sizeof(signed int), get_cn_stack_depth()); - c_add_to_ghost_state((uintptr_t) &z, sizeof(signed int), get_cn_stack_depth()); - - if (CN_LOAD(x) <= CN_LOAD(y) && CN_LOAD(x) <= CN_LOAD(z)) { - { __cn_ret = CN_LOAD(x); goto __cn_epilogue; } - } - else if (CN_LOAD(y) <= CN_LOAD(x) && CN_LOAD(y) <= CN_LOAD(z)) { - { __cn_ret = CN_LOAD(y); goto __cn_epilogue; } - } - else { - { __cn_ret = CN_LOAD(z); goto __cn_epilogue; } - } - -/* EXECUTABLE CN POSTCONDITION */ -__cn_epilogue: - - - /* C OWNERSHIP */ - - - c_remove_from_ghost_state((uintptr_t) &x, sizeof(signed int)); - - c_remove_from_ghost_state((uintptr_t) &y, sizeof(signed int)); - - c_remove_from_ghost_state((uintptr_t) &z, sizeof(signed int)); - -{ - cn_bits_i32* return_cn = convert_to_cn_bits_i32(__cn_ret); - update_cn_error_message_info("/*@ ensures return <= x\n ^~~~~~~~~~~ min3.instrument.broken.c:2:13-4:28"); - cn_assert(cn_bool_and(cn_bool_and(cn_bits_i32_le(return_cn, x_cn), cn_bits_i32_le(return_cn, y_cn)), cn_bits_i32_le(return_cn, z_cn))); - cn_pop_msg_info(); - ghost_stack_depth_decr(); -} - -return __cn_ret; - -} - -int main() { - /* EXECUTABLE CN PRECONDITION */ - signed int __cn_ret = 0; - initialise_ownership_ghost_state(); - initialise_ghost_stack_depth(); - - int r = min3(1,2,3); -c_add_to_ghost_state((uintptr_t) &r, sizeof(signed int), get_cn_stack_depth()); - - -c_remove_from_ghost_state((uintptr_t) &r, sizeof(signed int)); - -/* EXECUTABLE CN POSTCONDITION */ -__cn_epilogue: - -return __cn_ret; - -} diff --git a/src/exercises/min3/min3.test.partial.c b/src/exercises/min3/min3.test.partial.c index 6ce215e2..3fa2d781 100644 --- a/src/exercises/min3/min3.test.partial.c +++ b/src/exercises/min3/min3.test.partial.c @@ -1,5 +1,5 @@ unsigned int min3(unsigned int x, unsigned int y, unsigned int z) -/*@ ensures return <= x +/*@ ensures return <= x && return <= y && return <= z; @*/ diff --git a/src/exercises/read.c b/src/exercises/read.c index 04892f56..bf7c58c7 100644 --- a/src/exercises/read.c +++ b/src/exercises/read.c @@ -1,4 +1,4 @@ -int read (int *p) +int read (unsigned *p) /* --BEGIN-- */ /*@ requires take P = Owned(p); ensures take P_post = Owned(p); From c84cadc0393c7f9adbcc915d0abff84e28fe5660 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 4 Mar 2025 21:56:31 -0500 Subject: [PATCH 031/158] One more --- docs/getting-started/tutorials/pointers.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 6e3b3fff..2d7d5aa2 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -69,6 +69,8 @@ represented by a _resource_ `Owned(p)`. ### Owned resources +================ BCP STOPPED HERE ================= + Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as shown below. For now ignore the notation `take ... = Owned(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. From 6b88c956f862774091cbbcc80ded9e3bd7153c0c Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 5 Mar 2025 12:24:45 -0500 Subject: [PATCH 032/158] Fix read.c --- src/exercises/read.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/exercises/read.c b/src/exercises/read.c index bf7c58c7..40caf7a7 100644 --- a/src/exercises/read.c +++ b/src/exercises/read.c @@ -1,7 +1,7 @@ -int read (unsigned *p) +unsigned read (unsigned *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = Owned(p); + ensures take P_post = Owned(p); @*/ /* --END-- */ { From 83d830f27f78b70cc88061e4fc025cf0858b1fd7 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 5 Mar 2025 12:52:39 -0500 Subject: [PATCH 033/158] Incorporate recent changes from main --- .../tutorials}/images/0_error.png | Bin .../tutorials}/images/string_error.png | Bin docs/getting-started/tutorials/numeric.md | 39 +++++++++++++++--- 3 files changed, 33 insertions(+), 6 deletions(-) rename {src => docs/getting-started/tutorials}/images/0_error.png (100%) rename {src => docs/getting-started/tutorials}/images/string_error.png (100%) diff --git a/src/images/0_error.png b/docs/getting-started/tutorials/images/0_error.png similarity index 100% rename from src/images/0_error.png rename to docs/getting-started/tutorials/images/0_error.png diff --git a/src/images/string_error.png b/docs/getting-started/tutorials/images/string_error.png similarity index 100% rename from src/images/string_error.png rename to docs/getting-started/tutorials/images/string_error.png diff --git a/docs/getting-started/tutorials/numeric.md b/docs/getting-started/tutorials/numeric.md index b3eed4f7..650464a4 100644 --- a/docs/getting-started/tutorials/numeric.md +++ b/docs/getting-started/tutorials/numeric.md @@ -102,12 +102,39 @@ producing detailed error information, in the form of an HTML error report. Let’s return to the type error from earlier -- `add` without -precondition -- and take a closer look at this report. It -comprises two sections: - - - -![*CN error report*](images/0.error.png) +precondition -- and take a closer look at this report. + +_CN error report_ +![*CN error report: 0*](images/0_error.png) + +_Definitions and constraints not handled automatically_ + +CN checks that the code matches its specification with the help of an SMT +solver. CN passes a set of constraints along with program context to the SMT +solver, which either confirms that a given constraint will always hold in +that program context, provides a counterexample in which the constraint does +not hold, or times out. To avoid timeouts, CN avoids passing some definitions +to the solver, including recursive functions, some predicates with branching, +and constraints with `forall`. The error file displays in this section which +definitions and constraints CN did not pass to the solver. + +_Resources that do not satisfy predicate definitions_ + +Because CN does not pass certain definitions to the solver, it may return +spurious counterexamples that do not respect those definitions. Consider this +example: + +![*CN error report: string*](images/string_error.png) + +`String` is a predicate representing a null-terminated string. +In general, CN does not know how much to unfold the mutually recursive +predicates `String` and `StringAux`, so it does not pass their full +definition to the solver. This leads to a spurious counterexample: `sIn` is the +singleton string containing exactly the null character `0u8`. This is +impossible; the predicate leaves out the null when constructing the logical +representation of a string. To make clear that this is a bad counterexample, +the error file lists `String(s) (sIn)` under _Resources that do not satisfy +predicate definitions_. _Path to error._ The first section contains information about the control-flow path leading to the error. From ec222eea6eea45a5a3fc389428685a4322bef081 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 5 Mar 2025 12:53:16 -0500 Subject: [PATCH 034/158] ignore docs/exercises.zip --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6b21bfd0..2958500e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ docs/exercises docs/solutions /_opam/ /_tests/ +/docs/exercises.zip From f50dbb0be95471488b01f579f6a89160ce505d6b Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Wed, 5 Mar 2025 13:33:13 -0500 Subject: [PATCH 035/158] save progress on cn-basics --- docs/getting-started/tutorials/cn-basics.md | 19 +++++++++++++++---- src/exercises/add.partial.c | 4 ++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/exercises/add.partial.c diff --git a/docs/getting-started/tutorials/cn-basics.md b/docs/getting-started/tutorials/cn-basics.md index d20e1107..8f501044 100644 --- a/docs/getting-started/tutorials/cn-basics.md +++ b/docs/getting-started/tutorials/cn-basics.md @@ -1,8 +1,19 @@ +# More CN Basics + In this chapter, we will practice writing and testing specifications for simple arithmetic functions. -[exercise: `add`] -[maybe: exercise: `abs`] +_Exercise: Add._ Practice the workflow of specifying and testing the function `add`. + +- Add a specification that the function should return the sum of the inputs. +- Write an incorrect implementation, and check that `cn test` fails. +- Write a correct implementation, and check that `cn test` succeeds. + +```c title="exercises/add.partial.c" +--8<-- +exercises/add.partial.c +--8<-- +``` -[example to introduce `requires`: `div`] +Let's walk through an example that will introduce a few more CN specification features. [div 2 mul 2] -[exercise: `floorsqrt`] \ No newline at end of file +[sub 2 add 2] \ No newline at end of file diff --git a/src/exercises/add.partial.c b/src/exercises/add.partial.c new file mode 100644 index 00000000..78e1e35c --- /dev/null +++ b/src/exercises/add.partial.c @@ -0,0 +1,4 @@ +unsigned int add(unsigned int x, unsigned int y) +{ + +} From b1b7e51a6dc2988fbb80d2b13a481d9dc0962fd9 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Wed, 5 Mar 2025 14:17:13 -0500 Subject: [PATCH 036/158] finish draft of cn basics chapter --- docs/getting-started/tutorials/README.md | 2 +- docs/getting-started/tutorials/cn-basics.md | 42 ++++++++++++++++++--- src/exercises/id_by_div.broken.c | 5 +++ src/exercises/id_by_div.fixed.c | 6 +++ src/exercises/id_by_div_n.broken.c | 5 +++ 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/exercises/id_by_div.broken.c create mode 100644 src/exercises/id_by_div.fixed.c create mode 100644 src/exercises/id_by_div_n.broken.c diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index b04fd4a4..d3ec1725 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,7 +4,7 @@ ## A Tour of CN - [A first taste of CN](first-taste.md) -- [CN basics](basics.md) +- [CN basics](cn-basics.md) - [CN basics (with verification)](basics-with-verification.md) - [Working with pointers](pointers.md) - [Working with arrays](arrays.md) diff --git a/docs/getting-started/tutorials/cn-basics.md b/docs/getting-started/tutorials/cn-basics.md index 8f501044..ae5c6207 100644 --- a/docs/getting-started/tutorials/cn-basics.md +++ b/docs/getting-started/tutorials/cn-basics.md @@ -1,10 +1,10 @@ -# More CN Basics +# CN Basics In this chapter, we will practice writing and testing specifications for simple arithmetic functions. -_Exercise: Add._ Practice the workflow of specifying and testing the function `add`. +_Exercise._ Practice the workflow of specifying and testing the function `add`. -- Add a specification that the function should return the sum of the inputs. +- Write a specification with the postcondition that `add` should return the sum of its inputs. Remember that CN supports standard arithmetic and boolean operators such as `+` and `==`. - Write an incorrect implementation, and check that `cn test` fails. - Write a correct implementation, and check that `cn test` succeeds. @@ -14,6 +14,38 @@ exercises/add.partial.c --8<-- ``` -Let's walk through an example that will introduce a few more CN specification features. [div 2 mul 2] +### Preconditions -[sub 2 add 2] \ No newline at end of file +Let's walk through an example that will introduce a few more CN specification features. Here's a silly way of writing a function that (we claim) returns the same value as its input: + +```c title="exercises/id_by_div.broken.c" +--8<-- +exercises/id_by_div.broken.c +--8<-- +``` + +If we try to `cn test` this function, however, we will get a counterexample such as this one: + +``` +x = 7 +``` + +Oh! Because integer division is truncated, our function will only work as desired when the input `x` is even. We can add this requirement as a _precondition_, using the `requires` keyword. + +```c title="exercises/id_by_div.fixed.c" +--8<-- +exercises/id_by_div.fixed.c +--8<-- +``` + +That is, a specification with preconditions and postconditions asserts that if the preconditions held prior to the function call, then the postconditions will hold after the function returns. + +The other new piece of syntax here is the `u32` type annotations. In CN specifications, numeric types need to be annotated explicitly, and we use `u32` for `unsigned int`. (As we will see later, we use `i32` for `int`.) Try removing the annotations to see the error message. + +_Exercise._ Without changing the postcondition or implementation, fix the specification by adding a precondition on the inputs `x` and `n`. Check that `cn test` succeeds. + +```c title="exercises/id_by_div_n.broken.c" +--8<-- +exercises/id_by_div_n.broken.c +--8<-- +``` \ No newline at end of file diff --git a/src/exercises/id_by_div.broken.c b/src/exercises/id_by_div.broken.c new file mode 100644 index 00000000..a7e5f759 --- /dev/null +++ b/src/exercises/id_by_div.broken.c @@ -0,0 +1,5 @@ +unsigned int id_by_div(unsigned int x) +/*@ ensures return == x; @*/ +{ + return (x / 2) * 2; +} \ No newline at end of file diff --git a/src/exercises/id_by_div.fixed.c b/src/exercises/id_by_div.fixed.c new file mode 100644 index 00000000..aeafe018 --- /dev/null +++ b/src/exercises/id_by_div.fixed.c @@ -0,0 +1,6 @@ +unsigned int id_by_div(unsigned int x) +/*@ requires x % 2u32 == 0u32; + ensures return == x; @*/ +{ + return (x / 2) * 2; +} \ No newline at end of file diff --git a/src/exercises/id_by_div_n.broken.c b/src/exercises/id_by_div_n.broken.c new file mode 100644 index 00000000..6eaa66a4 --- /dev/null +++ b/src/exercises/id_by_div_n.broken.c @@ -0,0 +1,5 @@ +unsigned int id_by_div_n(unsigned int x, unsigned int n) +/*@ ensures return == x; @*/ +{ + return (x / n) * n; +} \ No newline at end of file From e15d66c014909be61126787122b037c056cd41a3 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 5 Mar 2025 15:18:53 -0500 Subject: [PATCH 037/158] Remove unused file --- docs/getting-started/tutorials/basics.md | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 docs/getting-started/tutorials/basics.md diff --git a/docs/getting-started/tutorials/basics.md b/docs/getting-started/tutorials/basics.md deleted file mode 100644 index 6f35cae2..00000000 --- a/docs/getting-started/tutorials/basics.md +++ /dev/null @@ -1,22 +0,0 @@ -# cn Basics - - - Some more examples of very simple C programs - - use unsigned arithmetic in all the early sections to avoid UB! - - (convert all the existing examples and exercises to unsigned, - leaving signed arithmetic and UB to a later section by - themselves) - - [BCP: In the rest of the tutorial, maybe we could be agnostic - (somewhat agnostic, at least) about whether people are using unit - tests or PBT. I don't have a sense yet of whether that will really - work, but it would have the good effect of focusing everybody's - attention on specifications and how to think about them, rather than - the testing process itself.] - - Throughout, we want several sorts of exercises: - - Here's the code; write a spec; now here's a broken version of the - code - does your spec catch it? - - Here's the code; write and validate a spec by breaking it yourself - - Here's a spec; write the program - - Here are requirements (with or without test cases); write the spec - and the code From 7c116860431fc672a606c509ba2f303bc64fac44 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 5 Mar 2025 17:01:41 -0500 Subject: [PATCH 038/158] Progress on new tutorial --- Makefile | 2 + docs/getting-started/tutorials/README.md | 4 +- docs/getting-started/tutorials/block.md | 37 +++ docs/getting-started/tutorials/cn-basics.md | 51 --- docs/getting-started/tutorials/first-taste.md | 16 +- docs/getting-started/tutorials/numeric.md | 78 +++-- docs/getting-started/tutorials/pointers.md | 296 +++++++++--------- .../tutorials/preconditions.md | 48 +++ .../allocating-and-deallocating-memory.md | 20 +- .../verification/arrays-and-loops.md | 54 +++- .../verification/defining-predicates.md | 54 +++- .../tutorials/verification/external-lemmas.md | 44 ++- .../tutorials/verification/lists.md | 64 +++- .../ownership-of-compound-objects.md | 24 +- .../pointers-and-simple-ownership.md | 66 +++- docs/getting-started/tutorials/welcome.md | 8 +- src/exercises/read.broken.c | 4 +- src/exercises/read2.c | 6 +- 18 files changed, 563 insertions(+), 313 deletions(-) create mode 100644 docs/getting-started/tutorials/block.md delete mode 100644 docs/getting-started/tutorials/cn-basics.md create mode 100644 docs/getting-started/tutorials/preconditions.md diff --git a/Makefile b/Makefile index 2a13f269..766193d0 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,8 @@ all: default clean: rm -rf docs/exercises docs/solutions docs/exercises.zip \ build TAGS _tests +# find . -type f -regex 'cn.*' -delete +# find . -type f -regex '*-exec.*' -delete ############################################################################## # Exercises diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index d3ec1725..e2af6b40 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,8 +4,8 @@ ## A Tour of CN - [A first taste of CN](first-taste.md) -- [CN basics](cn-basics.md) -- [CN basics (with verification)](basics-with-verification.md) +- [Preconditions](preconditions.md) +- [V: A first taste of verification](basics-with-verification.md) - [Working with pointers](pointers.md) - [Working with arrays](arrays.md) - [Dynamic storage allocation](dynamic.md) diff --git a/docs/getting-started/tutorials/block.md b/docs/getting-started/tutorials/block.md new file mode 100644 index 00000000..5b41e05a --- /dev/null +++ b/docs/getting-started/tutorials/block.md @@ -0,0 +1,37 @@ +# Block resources + +Aside from the `Owned` resources seen so far, CN has another +built-in type of resource called `Block`. Given a C-type `T` and +pointer `p`, `Block(p)` asserts the same ownership as +`Owned(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `Owned`, `Block` memory is not assumed +to be initialised. + +CN uses this distinction to prevent reads from uninitialised memory: + +- A read at C-type `T` and pointer `p` requires a resource + `Owned(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `Owned` resource unchanged. + +- A write at C-type `T` and pointer `p` needs only a +`Block(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `Block` resource +(it destroys it) and returns a new resource `Owned(p)` with the +value written as the output. This means the resource returned from a +write records the fact that this memory cell is now initialised and +can be read from. + +BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. + + +Since `Owned` carries the same ownership as `Block`, just with the +additional information that the `Owned` memory is initalised, a +resource `Owned(p)` is "at least as good" as `Block(p)` — +an `Owned(p)` resource can be used whenever `Block(p)` is +needed. For instance CN’s type checking of a write to `p` requires a +`Block(p)`, but if an `Owned(p)` resource is what is +available, this can be used just the same. This allows an +already-initialised memory cell to be over-written again. + +Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. + diff --git a/docs/getting-started/tutorials/cn-basics.md b/docs/getting-started/tutorials/cn-basics.md deleted file mode 100644 index ae5c6207..00000000 --- a/docs/getting-started/tutorials/cn-basics.md +++ /dev/null @@ -1,51 +0,0 @@ -# CN Basics - -In this chapter, we will practice writing and testing specifications for simple arithmetic functions. - -_Exercise._ Practice the workflow of specifying and testing the function `add`. - -- Write a specification with the postcondition that `add` should return the sum of its inputs. Remember that CN supports standard arithmetic and boolean operators such as `+` and `==`. -- Write an incorrect implementation, and check that `cn test` fails. -- Write a correct implementation, and check that `cn test` succeeds. - -```c title="exercises/add.partial.c" ---8<-- -exercises/add.partial.c ---8<-- -``` - -### Preconditions - -Let's walk through an example that will introduce a few more CN specification features. Here's a silly way of writing a function that (we claim) returns the same value as its input: - -```c title="exercises/id_by_div.broken.c" ---8<-- -exercises/id_by_div.broken.c ---8<-- -``` - -If we try to `cn test` this function, however, we will get a counterexample such as this one: - -``` -x = 7 -``` - -Oh! Because integer division is truncated, our function will only work as desired when the input `x` is even. We can add this requirement as a _precondition_, using the `requires` keyword. - -```c title="exercises/id_by_div.fixed.c" ---8<-- -exercises/id_by_div.fixed.c ---8<-- -``` - -That is, a specification with preconditions and postconditions asserts that if the preconditions held prior to the function call, then the postconditions will hold after the function returns. - -The other new piece of syntax here is the `u32` type annotations. In CN specifications, numeric types need to be annotated explicitly, and we use `u32` for `unsigned int`. (As we will see later, we use `i32` for `int`.) Try removing the annotations to see the error message. - -_Exercise._ Without changing the postcondition or implementation, fix the specification by adding a precondition on the inputs `x` and `n`. Check that `cn test` succeeds. - -```c title="exercises/id_by_div_n.broken.c" ---8<-- -exercises/id_by_div_n.broken.c ---8<-- -``` \ No newline at end of file diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index f759955a..cff9a7c3 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -109,7 +109,7 @@ cases: 1, passed: 1, failed: 0, errored: 0, skipped: 0 Hooray! -### Exercises +## Exercises _Refining the specification of `min3`_: The specification we wrote is a bit loose: It says the result value should be smaller than `x`, `y`, @@ -117,6 +117,20 @@ and `z`, but it does not say that it must be equal to one of these. For example, a function that always returns `0` would satisfy this spec specification. Improve it. +_Exercise._ Practice the workflow of specifying and testing the function `add`. + +- Write a specification with the postcondition that `add` should + return the sum of its inputs. Remember that CN supports standard + arithmetic and boolean operators such as `+` and `==`. +- Write an _incorrect_ implementation of `add` and check that `cn test` fails. +- Write a _correct_ implementation and check that `cn test` succeeds. + +```c title="exercises/add.partial.c" +--8<-- +exercises/add.partial.c +--8<-- +``` + ??? note "(Optional) Verifying `min3`" Property-based testing is great for increasing our confidence that the function satisfies its specification, but we might also want to _verify_ this formally. Run `cn verify ` on the buggy version to produce this output: diff --git a/docs/getting-started/tutorials/numeric.md b/docs/getting-started/tutorials/numeric.md index 650464a4..a65e6fd7 100644 --- a/docs/getting-started/tutorials/numeric.md +++ b/docs/getting-started/tutorials/numeric.md @@ -50,13 +50,21 @@ solutions/add_0.c In detail: -- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. +- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. +BCP: I understand this reasoning, but I wonder whether it introduces more confusion than it avoids -- it means there are two ways of writing everything, and people have to remember whether the particular thing they are writing right now is C or CN... + + BCP: Hopefully we are moving toward unifying these notations anyway? + - To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. - Finally, we require this sum to be between the minimal and maximal `int` values. Integer constants, such as `-2147483648i64`, must specifiy their CN type (`i64`). - - + +BCP: We should use the new ' syntax (or whatever it turned out to be) for numeric constants + + +Dhruv: Yet to be implemented: rems-project/cerberus#337 + Running CN on the annotated program passes without errors. This means that, with our specified precondition, `add` is safe to execute. @@ -173,8 +181,12 @@ CN displays concrete values: For now, ignore the pointer values `{@0; 4}` for `x` and `{@0; 0}` for `y`. - - + +BCP: Where are these things discussed? Anywhere? (When) are they useful? + + +Dhruv: These are part of VIP memory model things I'm working on, which will hopefully be implemented and enabled in the next few weeks. + These concrete values are part of a _counterexample_: a concrete valuation of variables and pointers in the program that that leads to @@ -188,8 +200,12 @@ _Proof context._ The second section, below the error trace, lists the proof cont "`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. - - + +BCP: Again, where are these things discussed? Should they be? + + +Dhruv: Also VIP. + Finally, "`Constraints`" records all logical facts CN has learned along the path. This includes user-specified assumptions from preconditions or loop invariants, value ranges inferred from the C-types of variables, and facts learned during the type checking of the statements. Here -- when checking `add` without precondition -- the only constraints are those inferred from C-types in the code: @@ -197,22 +213,34 @@ Finally, "`Constraints`" records all logical facts CN has learned along the path `x` is a "`good`" `signed int` value (i.e. in range). Here `signed int` is the same type as `int`, CN just makes the sign explicit. - + +BCP: Yikes! This seems potentially confusing + For an integer type `T`, the type `good` requires the value to be in range of type `T`; for pointer types `T`, it also requires the pointer to be aligned. For structs and arrays, this extends in the obvious way to struct members or array cells. - + +BCP: Is this information actually ever useful? Is it currently suppressed? + - `repr` requires representability (not alignment) at type `T`, so `repr(&ARGO)`, for instance, records that the pointer to `x` is representable at C-type `signed int*`; - `aligned(&ARGO, 4u64)`, moreover, states that it is 4-byte aligned. - - - - + +URGENT: BCP: Some of the above (especially the bit at the end) feels like TMI for many/most users, especially at this point in the tutorial. + + +Dhruv: Probably true, we actually even hide some of these by default. + + + BCP: I propose we hide the rest and move this discussion to somewhere else ("Gory Details" section of the tutorial, or better yet reference manual). + + +Dhruv: Thumbs up + ### Another arithmetic example @@ -220,7 +248,9 @@ Let’s apply what we know so far to another simple arithmetic example. The function `doubled`, shown below, takes an int `n`, defines `a` as `n` incremented, `b` as `n` decremented, and returns the sum of the two. - + +BCP: Is it important to number the slf examples? If so, we should do it consistently, but IMO it is not. Better to rename them without numbers. + ```c title="exercises/slf1_basic_example_let.signed.c" --8<-- @@ -238,14 +268,24 @@ solutions/slf1_basic_example_let.signed.c --8<-- ``` - - + +BCP: WHy n*+n\_ in some places and n\*2i32 in others? + + +Dhruv: Unlikely to be meaningful, either is fine. + We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. - - - + +BCP: How about renaming N to n64? + + +Dhruv: Sensible. + + + BCP: (someone do it on next pass) + To capture the functional behaviour, the postcondition specifies that `return` is twice the value of `n`. diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 2d7d5aa2..6eb57c14 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,6 +1,8 @@ # Pointers and Simple Ownership - TODO + +Things to do: + - read.c - unannotated version fails tests @@ -46,7 +48,9 @@ exercises/read.c Running CN on this example produces the following error: - + +BCP: This output needs updated. + ``` cn test read.c Compiled 'read_test.c'. @@ -65,15 +69,23 @@ cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. This permission is -represented by a _resource_ `Owned(p)`. +represented by a _resource_ `Owned(p)`. + +BCP: Is that right?? Should it be just Owned(p)? Or just Owned(p)?? + -### Owned resources +## Owned resources -================ BCP STOPPED HERE ================= +Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts +_ownership_ of a memory cell at location `p` of the size of C-type +`T`. -Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). - -In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as shown below. For now ignore the notation `take ... = Owned(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. +In this example, we can ensure the safe execution of `read` by adding +a precondition that requires ownership of `Owned(p)`, as +shown below. (For now ignore the `take ... =` part.) Since reading the pointer does not disturb its value, +we can also add a corresponding postcondition, whereby `read` returns +ownership of `p` after it is finished executing, in the form of +another `Owned(p)` resource. ```c title="solutions/read.c" --8<-- @@ -81,28 +93,73 @@ solutions/read.c --8<-- ``` -This specification means that: - -- any function calling `read` has to be able to provide a resource `Owned(p)` to pass into `read`, and - -- the caller will receive back a resource `Owned(p)` when `read` returns. - -### Resource outputs - -A caller of `read` may also wish to know that `read` actually returns the correct value, the pointee of `p`, and also that it does not change memory at location `p`. To phrase both we need a way to refer to the pointee of `p`. - - - -In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `Owned(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. - - - - -CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = Owned(p)` does two things: (1) it assert ownership of resource `Owned(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. - - - - +This specification can be read as follows: + +- any function calling `read` has to be able to provide a resource + `Owned(p)` to pass into `read`, and + +- the caller will receive back a resource `Owned(p)` when + `read` returns. + + +BCP: Is this going slowly enough for "real-world +engineers"? Where do we need more detail? + + +## Resource outputs + + BCP: The idea that "resources have outputs" +is very mind-boggling to many new users, _especially_ folks with some +separation logic background. Needs to be explained very +carefully. Also, there's some semantic muddle in the terminology: Is a +resource (1) a thing in the heap, (2) a thing in the heap that one is +currently holding, or (3) the act of holding a thing in the heap? +These are definitely not at all the same thing, but our language at +different points suggests all three! To me, (1) is the natural sense +of the word "resource"; (2) is somewhat awkward, and (3) is extremely +awkward. + +A caller of `read` may also wish to know that `read` actually returns +the correct value (i.e., the thing that `p` points to), and also that +it does not change memory at location `p`. To phrase both we need a +way to refer to the pointee of `p`. + +In CN, resources have _outputs_. Each resource outputs the information +that can be derived from ownership of the resource. What information +is returned is specific to the type of resource. A resource +`Owned(p)` (for some C-type `T`) outputs the _pointee value_ of +`p`, since that can be derived from the resource ownership: assume you +have a pointer `p` and the associated ownership, then this uniquely +determines the pointee value of `p`. + + +BCP: ... in a given heap! (The real problem here is that "and the associated ownership" is pretty vague.) + + +Dhruv: Perhaps mentioning sub-heaps will help? + + +CN uses the `take` notation seen in the example above to bind the +output of a resource to a new name. The precondition `take P = +Owned(p)` does two things: (1) it assert ownership of resource +`Owned(p)`, and (2) it binds the name `P` to the resource output, +here the pointee value of `p` at the start of the function. Similarly, +the postcondition introduces the name `P_post` for the pointee value +on function return. + + +BCP: But, as we've discussed, the word "take" in the postcondition is +quite confusing: What it's doing is precisely the _opposite_ of +"taking" the resournce, not taking it but giving it back!! It would be +much better if we could choose a more neutral word that doesn't imply +either taking or giving. E.g. "resource". (I forget if we decided on +something like this in the last round of syntax changes...) + + + +BCP: This might be a good place for a comment on naming +conventions. Plus a pointer to a longer discussion if needed. + That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying @@ -115,23 +172,28 @@ exercises/read2.c --8<-- ``` -_Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): +??? note "Aside (for separation-logic experts)" + _Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): - + + Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. + - + + Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? + -``` -∀p. -∀v1. -{ p ↦ P } -read(p) -{ \return. ∃P_post. (p ↦ P_post) /\ return = P /\ P = P_post } -``` + ``` + ∀p. + ∀v1. + { p ↦ P } + read(p) + { \return. ∃P_post. (p ↦ P_post) /\ return = P /\ P = P_post } + ``` -CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. + CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. -### Linear resource ownership +## Linear resource ownership In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. @@ -146,23 +208,26 @@ exercises/read.broken.c CN rejects this program with the following message: ``` -cn verify exercises/read.broken.c -[1/1]: read -build/exercises/read.broken.c:4:3: error: Left_Sublist-over unused resource 'Owned(p)(v1)' -return \*p; -^~~~~~~~~~ -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_17eb4a.html +> cn test exercises/read.broken.c +... +FAILED +... +Postcondition leak check failed, ownership leaked for pointer 0x1243d8a82 +... ``` + +BCP: Explain what that means. Update if the output format changes. + CN has typechecked the function and verified (1) that it is safe to -execute under the precondition (given ownership `Owned(p)`) +execute under the precondition (given ownership `Owned(p)`) and (2) that the function (vacuously) satisfies its postcondition. But following the check of the postcondition it finds that not all -resources have been "`used up`". +resources have been "used up". Indeed, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. -CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "`forgotten`". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). +CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "forgotten". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). CN’s motivation for linear tracking of resources is its focus on low-level systems software in which memory is managed manually; in @@ -171,9 +236,13 @@ consequence, function specifications have to do precise bookkeeping of their resource footprint and, in particular, return any unused resources back to the caller. -### Exercises +## Exercises -_Quadruple_. Specify the function `quadruple_mem`, which is similar to the earlier `quadruple` function, except that the input is passed as an `int` pointer. Write a specification that takes ownership of this pointer on entry and returns this ownership on exit, leaving the pointee value unchanged. +_Quadruple_. Specify the function `quadruple_mem`, which is similar to +the earlier `quadruple` function, except that the input is passed as a +pointer to an `unsigned`. Write a specification that takes ownership +of this pointer on entry and returns this ownership on exit, leaving +the pointee value unchanged. ```c title="exercises/slf_quadruple_mem.c" --8<-- @@ -181,7 +250,9 @@ exercises/slf_quadruple_mem.c --8<-- ``` -_Abs_. Give a specification to the function `abs_mem`, which computes the absolute value of a number passed as an `int` pointer. +_Abs_. Give a specification to the function `abs_mem`, which computes +the absolute value of a number passed as an `int` pointer. +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Fix ```c title="exercises/abs_mem.c" --8<-- @@ -189,44 +260,9 @@ exercises/abs_mem.c --8<-- ``` -### Block resources - -Aside from the `Owned` resources seen so far, CN has another -built-in type of resource called `Block`. Given a C-type `T` and -pointer `p`, `Block(p)` asserts the same ownership as -`Owned(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `Owned`, `Block` memory is not assumed -to be initialised. - -CN uses this distinction to prevent reads from uninitialised memory: - -- A read at C-type `T` and pointer `p` requires a resource - `Owned(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `Owned` resource unchanged. - -- A write at C-type `T` and pointer `p` needs only a -`Block(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `Block` resource -(it destroys it) and returns a new resource `Owned(p)` with the -value written as the output. This means the resource returned from a -write records the fact that this memory cell is now initialised and -can be read from. - - -Since `Owned` carries the same ownership as `Block`, just with the -additional information that the `Owned` memory is initalised, a -resource `Owned(p)` is "`at least as good`" as `Block(p)` — -an `Owned(p)` resource can be used whenever `Block(p)` is -needed. For instance CN’s type checking of a write to `p` requires a -`Block(p)`, but if an `Owned(p)` resource is what is -available, this can be used just the same. This allows an -already-initialised memory cell to be over-written again. - -Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. +## Writing through pointers -### Writing through pointers - -Let’s explore resources and their outputs in another example. The C function `incr` takes an `int` pointer `p` and increments the value in the memory cell that it poinbts to. +Let’s explore resources and their outputs in another example. The C function `incr` takes an `unsigned` pointer `p` and increments the value in the memory cell that it poinbts to. ```c title="exercises/slf0_basic_incr.signed.c" --8<-- @@ -234,7 +270,7 @@ exercises/slf0_basic_incr.signed.c --8<-- ``` -In the precondition we assert ownership of resource `Owned(p)`, +In the precondition we assert ownership of resource `Owned(p)`, binding its output/pointee value to `P`, and use `P` to specify that `p` must point to a sufficiently small value at the start of the function so as not to overflow when incremented. The postcondition @@ -242,43 +278,7 @@ asserts ownership of `p` with output `P_post`, as before, and uses this to express that the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. -If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. - -```c title="exercises/slf0_basic_incr.signed.broken.c" ---8<-- -exercises/slf0_basic_incr.signed.broken.c ---8<-- -``` - -CN reports: - -``` -build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading -int n = \*p; -^~ -Resource needed: Owned(p) -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html -``` - -The `Owned(p)` resource required for reading is missing, since, per the precondition, only `Block(p)` is available. Checking the linked HTML file confirms this. Here the section "`Available resources`" lists all resource ownership at the point of the failure: - -- `Block(p)(u)`, i.e., ownership of uninitialised memory - at location `p`; the output is a `void`/`unit` value `u` - (specified in the second pair of parentheses) - -- `Owned(&ARG0)(p)`, the ownership of (initialised) - memory at location `&ARG0`, i.e., the memory location where the - first function argument is stored; its output is the pointer `p` - (not to be confused with the pointee of `p`); and finally - -- `__CN_Alloc(&ARG0)(void)` is a resource that records allocation - information for location `&ARG0`; this is related to CN’s - memory-object semantics, which we ignore for the moment. - - - - -### Exercises +## Exercises _Zero._ Write a specification for the function `zero`, which takes a pointer to _uninitialised_ memory and initialises it to `0`. @@ -288,7 +288,7 @@ exercises/zero.c --8<-- ``` -_In-place double._ Give a specification for the function `inplace_double`, which takes an `int` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. +_In-place double._ Give a specification for the function `inplace_double`, which takes an `unsigned` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. ```c title="exercises/slf3_basic_inplace_double.c" --8<-- @@ -296,20 +296,34 @@ exercises/slf3_basic_inplace_double.c --8<-- ``` -### Multiple owned pointers +## Multiple owned pointers + +======================= BCP STOPPED HERE ==================== When functions manipulate multiple pointers, we can assert their ownership just like before. However pointer ownership in CN is unique -- that is, simultaneously owning -`Owned` or `Block` resources for two pointers implies that these +resources for two pointers implies that these pointers are disjoint. The following example shows the use of two `Owned` resources for accessing two different pointers by a function `add`, which reads -two `int` values in memory, at locations `p` and `q`, and +two `unsigned` values in memory, at locations `p` and `q`, and returns their sum. - + +BCP: The way I've been naming things is not working that well +here. The problem is that in examples like this we computer "thing +pointed to by p" at both C and CN levels. At the C level, the thing +pointed to by p obviously cannot also be called p, so it doesn't make +sense for it to be called P at the CN level, right? This should be +fixed by the proposed `$p` syntax. + + + +BCP: Is there a difference between `unsigned int` and `unsigned`? Not +sure which I should be using. + ```c title="exercises/add_read.c" --8<-- @@ -317,19 +331,15 @@ exercises/add_read.c --8<-- ``` -This time we use C’s `unsigned int` type. In C, over- and underflow of unsigned integers is not undefined behaviour, so we do not need any special preconditions to rule this out. Instead, when an arithmetic operation at unsigned type goes outside the representable range, the value "`wraps around`". - -The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. - + +BCP: Does this belong here? + +The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned` type. Like C’s unsigned integer arithmetic, CN unsigned values wrap around when exceeding the value range of the type. Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. - - - - In the following we will sometimes use unsigned integer types to focus on specifying memory ownership, rather than the conditions necessary to show absence of C arithmetic undefined behaviour. -### Exercises +## Exercises _Swap._ Specify the function `swap`, which takes two owned `unsigned int` pointers and swaps their values. diff --git a/docs/getting-started/tutorials/preconditions.md b/docs/getting-started/tutorials/preconditions.md new file mode 100644 index 00000000..34332715 --- /dev/null +++ b/docs/getting-started/tutorials/preconditions.md @@ -0,0 +1,48 @@ +# Preconditions + +Next, let's walk through an example that will introduce a few more CN +specification features. Here's a silly way of writing a function that +returns whatever number it is given as input: + +```c title="exercises/id_by_div.broken.c" +--8<-- +exercises/id_by_div.broken.c +--8<-- +``` + +If we try to `cn test` this function, however, we will get a counterexample such as this one: + +BCP: update this! + +``` +x = 7 +``` + +Oh! Because integer division is truncating, our silly function will +only work as desired when the input `x` is even. We can add this +requirement as a _precondition_, using the `requires` keyword. + +```c title="exercises/id_by_div.fixed.c" +--8<-- +exercises/id_by_div.fixed.c +--8<-- +``` + +A specification with preconditions and postconditions asserts that, if +the preconditions hold at the point where the function is called, then the +postconditions will hold when the function returns. + +The other new piece of syntax here is the `u32` type annotations. In +CN specifications, numeric types need to be annotated explicitly, and +we use `u32` for `unsigned int`. Try removing the annotations to see +the error message. + +_Exercise._ Without changing the postcondition or implementation, fix +the specification in the following example by adding a precondition on +the inputs `x` and `n`. Check that `cn test` succeeds. + +```c title="exercises/id_by_div_n.broken.c" +--8<-- +exercises/id_by_div_n.broken.c +--8<-- +``` diff --git a/docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md b/docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md index 7a1fde04..caf90644 100644 --- a/docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md +++ b/docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md @@ -1,6 +1,8 @@ # Allocating and Deallocating Memory - + +BCP: Again, more text is needed to set up this discussion. + At the moment, CN does not understand the `malloc` and `free` functions. They are a bit tricky because they rely on a bit of @@ -49,9 +51,11 @@ exercises/ref.h --8<-- ``` - + + ```c title="exercises/slf16_basic_succ_using_incr.c" --8<-- @@ -61,7 +65,9 @@ exercises/slf16_basic_succ_using_incr.c ### Exercises - + +BCP: There should be a non-ref-using version of this earlier, for comparison. + Prove a specification for the following program that reveals _only_ that it returns a pointer to a number that is greater than the number @@ -78,9 +84,11 @@ exercises/slf_ref_greater.c Here is another syntax for external / unknown functions, together with an example of a loose specification: - + + ```c title="exercises/slf18_two_dice.c" --8<-- diff --git a/docs/getting-started/tutorials/verification/arrays-and-loops.md b/docs/getting-started/tutorials/verification/arrays-and-loops.md index 5bcc7646..ff6da597 100644 --- a/docs/getting-started/tutorials/verification/arrays-and-loops.md +++ b/docs/getting-started/tutorials/verification/arrays-and-loops.md @@ -4,7 +4,9 @@ Another common datatype in C is arrays. Reasoning about memory ownership for arr To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `int` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: - + +BCP: Another tricky naming / capitalization puzzle: The index of an "each" has CN type i32, so strictly speaking I believe it should be written with a capital "I". But insisting on this feels like insisting on a distinction that most CN programmers would never even notice, much less be confused by. I think this is another instance of the way C and CN integer types are partly but not completely squished together. + ```c each (i32 i; 0i32 <= i && i < 10i32) @@ -127,7 +129,9 @@ the same — and that the value returned is `A[i]`. _Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. - + +BCP: When we get around to renaming files in the examples directory, we should call this one array_swap or something else beginning with "array". + ```c title="exercises/add_two_array.c" --8<-- @@ -135,11 +139,13 @@ exercises/add_two_array.c --8<-- ``` - + + _Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. @@ -149,7 +155,8 @@ exercises/swap_array.c --8<-- ``` - + + ### Loops @@ -180,7 +188,9 @@ In order to verify code with loops, CN requires the user to supply loop invarian Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. - + +BCP: Rename to array_init.c + ```c title="exercises/init_array.c" --8<-- @@ -198,9 +208,11 @@ solutions/init_array.c --8<-- ``` - + + The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. @@ -208,9 +220,11 @@ The second thing we need to do, however, is less straightforward. Recall that, a **Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. - + + The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. @@ -260,8 +274,12 @@ As before, we also have to instruct CN to `extract` ownership of individual arra - finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. - - + +BCP: That last bit is mysterious. + + +Dhruv: See long explanation and issue here: rems-project/cerberus#498 + ### Exercises @@ -273,9 +291,12 @@ exercises/init_array_rev.c --8<-- ``` - + +BCP: The transition to the next section is awkward. Needs a sentence or two to signal that we're changing topics. Some better visual indication would also be nice. + + + - + + diff --git a/docs/getting-started/tutorials/verification/defining-predicates.md b/docs/getting-started/tutorials/verification/defining-predicates.md index d55f33c2..8a8b298a 100644 --- a/docs/getting-started/tutorials/verification/defining-predicates.md +++ b/docs/getting-started/tutorials/verification/defining-predicates.md @@ -1,12 +1,18 @@ # Defining Predicates - - + + We should show how to define predicates earlier -- + + + - e.g., with numeric ranges!! + + + - + + Suppose we want to write a function that takes _two_ pointers to integers and increments the contents of both of them. @@ -31,17 +37,29 @@ exercises/slf_incr2_alias.c This version does correctly state that the final values of `p` and `q` are,m respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. - - - + +Sainati: I think it would be useful here to add an explanation for how CN's type checking works. + + + For example, in the definition of BothOwned here, how is CN able to prove that `take pv = Owned(p);` + + + type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? + A better way is to define a _predicate_ that captures both the aliased and the non-aliased cases together and use it in the pre- and postconditions: - - - + +Sainati: I think it would be useful here to add an explanation for how CN's type checking works. + + + For example, in the definition of BothOwned here, how is CN able to prove that `take pv = Owned(p);` + + + type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? + ```c title="exercises/slf_incr2.c" --8<-- @@ -49,9 +67,17 @@ exercises/slf_incr2.c --8<-- ``` - - - - + +BCP: "BothOwned" is a pretty awkward name. + + +BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types. + + +BCP: the annotation on incr2 needs some unpacking for readers!! + + +BCP: first use of the "split_case" annotation + diff --git a/docs/getting-started/tutorials/verification/external-lemmas.md b/docs/getting-started/tutorials/verification/external-lemmas.md index 9ab953eb..a12bfcaa 100644 --- a/docs/getting-started/tutorials/verification/external-lemmas.md +++ b/docs/getting-started/tutorials/verification/external-lemmas.md @@ -1,18 +1,26 @@ # Working with External Lemmas - + +BCP: This section should also show what the proof of the lemmas +looks like on the Coq side! + - - + +BCP: This needs to be filled in urgently!! + + + Dhruyv: There are some examples in the Cerberus repo tests? rems-project/cerberus@20d9d5c + + + - + + ### List reverse @@ -46,12 +54,14 @@ Having stated these lemmas, we can now complete the specification and proof of `IntList_rev`. Note the two places where `apply` is used to tell the SMT solver where to pay attention to the lemmas. - + + ```c title="exercises/list/rev.c" --8<-- @@ -62,7 +72,9 @@ exercises/list/rev.c For comparison, here is another way to write the program, using a while loop instead of recursion, with its specification and proof. - + +BCP: Why 0 instead of NULL?? (Is 0 better?) + ```c title="exercises/list/rev_alt.c" --8<-- @@ -74,7 +86,9 @@ exercises/list/rev_alt.c **Sized stacks:** Fill in annotations where requested: - + +BCP: type_synonym has not been introduced yet + ```c title="exercises/slf_sized_stack.c" --8<-- @@ -82,9 +96,12 @@ exercises/slf_sized_stack.c --8<-- ``` - + + ====================================================================== + + + - + + diff --git a/docs/getting-started/tutorials/verification/lists.md b/docs/getting-started/tutorials/verification/lists.md index b2221315..9b558697 100644 --- a/docs/getting-started/tutorials/verification/lists.md +++ b/docs/getting-started/tutorials/verification/lists.md @@ -1,13 +1,17 @@ # Lists - + +BCP: Better intro needed + Now it's time to look at some more interesting heap structures. To begin with, here is a C definition for linked list cells, together with allocation and deallocation functions: - + +BCP: Here and in several other places, we should use the "take \_ = ..." syntax when the owned value is not used. And we should explain it the first time we use it. + ```c title="exercises/list/c_types.h" --8<-- @@ -15,9 +19,15 @@ exercises/list/c_types.h --8<-- ``` - - - + +BCP: Per discussion with Christopher, Cassia, and Daniel, the word "predicate" is quite confusing for newcomers (in logic, predicates do not return things!). A more neutral word might make for significantly easier onboarding. + + +Dhruv: Or no keyword? rems-project/cerberus#304 How about traversal? + + + BCP: No keyword sounds even better. But "traversal" in the interim is not bad. Or maybe "extractor" or something like that? + To write specifications for C functions that manipulate lists, we need to define a CN "predicate" that describes specification-level list @@ -63,11 +73,13 @@ exercises/list/headers.h --8<-- ``` - + + ### Append @@ -88,7 +100,9 @@ of the `unfold` annotation in the body, which are needed to help the CN typechecker. The `unfold` annotation is an instruction to CN to replace a call to a recursive (CN) function (in this case `append`) with its definition, and is necessary because CN is unable to automatically determine when and where to expand recursive definitions on its own. - + +BCP: Can someone add a more technical explanation of why they are needed and exactly what they do? + ```c title="exercises/list/append.c" --8<-- @@ -109,16 +123,22 @@ exercises/list/copy.c ### Merge sort - + +BCP: This could use a gentler explanation (probably in pieces) + Finally, here is a slightly tricky in-place version of merge sort that avoids allocating any new list cells in the splitting step by taking alternate cells from the original list and linking them together into two new lists of roughly equal lengths. - + +BCP: We've heard from more than one reader that this example is particularly hard to digest without some additional help + - + +BCP: Nit: Merge multiple requires and ensures clauses into one + ```c title="exercises/list/mergesort.c" --8<-- @@ -160,12 +180,22 @@ exercises/list/free.c _Length with an accumulator_. Add annotations as appropriate: - - - - - - + +BCP: Removing / forgetting the unfold in this one gives a truly + + + bizarre error message saying that the constraint "n == (n + length(L1))" + + + is unsatisfiable... + + + +Sainati: when I went through the tutorial, the file provided for this exercise was already "complete" in that + + + it already had all the necessary annotations present for CN to verify it + ```c title="exercises/slf_length_acc.c" --8<-- diff --git a/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md b/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md index e68c02ce..63b111ca 100644 --- a/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md +++ b/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md @@ -17,16 +17,20 @@ postcondition similarly asserts ownership of `p`, with output `P_post`, and asserts the coordinates have been swapped, by referring to the members of `P` and `P_post` individually. - + +BCP: This paragraph is quite confusing if read carefully: it seems to say that the "take" in the requires clause returns a different type than the "tajke" in the "ensures" clause. Moreover, even if the reader decides that this cannot be the case and they have to return the same type, they may wonder whether thius type is a C type (which is what it looks like, since there is only one struct declaration, and it is not in a magic comment) or a CN type (which might be expected, since it is the result of a "take"). I _guess_ what's going on here is that every C type is automatically reflected as a CN type with the same name. But this story is also not 100% satisfying, since the basic numeric types don't work this way: each C numeric type has an _analog_ in CN, but with a different name. + + + - + + ### Compound Owned and Block resources @@ -58,7 +62,9 @@ To handle the required resource inference, CN "`eagerly`" decomposes all `struct We can see this if, for instance, we experimentally change the `transpose` example from above to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of the `transpose` function, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) - + +BCP: Recheck that what we say here matches what it actually looks like + ```c title="exercises/transpose.broken.c" --8<-- @@ -72,7 +78,9 @@ The precondition of `transpose` asserts ownership of an `Owned(p)` - `Owned(member_shift(p, y))` with output `P.y` - + +BCP: We should verify that it really does say this. + Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. @@ -90,12 +98,14 @@ exercises/transpose2.c --8<-- ``` - + + diff --git a/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md b/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md index 059efc94..12e15f41 100644 --- a/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md +++ b/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md @@ -28,9 +28,12 @@ For the read `*p` to be safe, ownership of a resource is missing: a resource `Ow ### Owned resources - + + TODO: BCP: Perhaps this is a good time for one last discussion of the keyword "Owned", which I have never found very helpful: the resource itself isn't owned -- it's a description of something that _can_ be owned. (It's "take" that does the owning.) Moreover, "Owned" and "Block" are badly non-parallel, both grammatically and semantically. I suggest "Resource" instead of "Owned". (We can keep "Block" -- it's not too bad, IMO.) + + + - + + Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). @@ -62,18 +66,28 @@ This specification means that: A caller of `read` may also wish to know that `read` actually returns the correct value, the pointee of `p`, and also that it does not change memory at location `p`. To phrase both we need a way to refer to the pointee of `p`. - + + TODO: BCP: The idea that "resources have outputs" is very mind-boggling to many new users, _especially_ folks with some separation logic background. Needs to be explained very carefully. Also, there's some semantic muddle in the terminology: Is a resource (1) a thing in the heap, (2) a thing in the heap that one is currently holding, or (3) the act of holding a thing in the heap? These are definitely not at all the same thing, but our language at different points suggests all three! To me, (1) is the natural sense of the word "resource"; (2) is somewhat awkward, and (3) is extremely awkward. + In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `Owned(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. - - + + TODO: BCP: ... in a given heap! (The real problem here is that "and the associated ownership" is pretty vague.) + + +Dhruv: Perhaps mentioning sub-heaps will help? + CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = Owned(p)` does two things: (1) it assert ownership of resource `Owned(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. - + + TODO: BCP: But, as we've discussed, the word "take" in the postcondition is quite confusing: What it's doing is precisely the _opposite_ of "taking" the resournce, not taking it but giving it back!! It would be much better if we could choose a more neutral word that doesn't imply either taking or giving. E.g. "resource". + - + + TODO: BCP: This might be a good place for a comment on naming conventions. Plus a pointer to a longer discussion if needed + That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying @@ -88,9 +102,13 @@ exercises/read2.c _Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): - + + TODO: Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. + - + + Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? + ``` ∀p. @@ -182,7 +200,9 @@ are fine). The write consumes ownership of the `Block` resource value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. - + + TODO: BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. + Since `Owned` carries the same ownership as `Block`, just with the additional information that the `Owned` memory is initalised, a @@ -246,8 +266,12 @@ The `Owned(p)` resource required for reading is missing, since, per the pre information for location `&ARG0`; this is related to CN’s memory-object semantics, which we ignore for the moment. - - + + TODO: BCP: These bullet points are all a bit mysterious and maybe TMI. More generally, we should double check that this is actually the information displayed in the current HTML output... + + +Dhruv: It is displayed, but hidden. And perhaps TMI right now, but once the memory model lands properly, will sadly be the price of entry to writing verifiable (semantically well-defined) C. + ### Exercises @@ -280,7 +304,9 @@ accessing two different pointers by a function `add`, which reads two `int` values in memory, at locations `p` and `q`, and returns their sum. - + + TODO: BCP: Hmmm -- I'm not very sure that the way I've been naming things is actually working that well. The problem is that in examples like this we computer "thing pointed to by p" at both C and CN levels. At the C level, the thing pointed to by p obviously cannot also be called p, so it doesn't make sense for it to be called P at the CN level, right? Maybe we need to think again, but hoinestly I am not certain that it is _not_ working either. So I'm going to opush on for now... + ```c title="exercises/add_read.c" --8<-- @@ -294,9 +320,15 @@ The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee value Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. - - - + + TODO: BCP: I wonder whether we should uniformly use i32 integers everywhere in the tutorial (just mentioning in the bullet list below that there are other integer types, and using i64 for calculations that may overflow). Forgetting which integer type I was using was a common (and silly) failure mode when I was first working through the tutorial. + + +Dhruv: Sensible. + + + BCP: ... On second thought, maybe settling on u32 instead of i32 in most places is better (fewer things to prove). Or maybe it doesn't matter much. For the start of the tutorial, i32 is important because the examples are all about overflow. But after that we could go either way. + In the following we will sometimes use unsigned integer types to focus on specifying memory ownership, rather than the conditions necessary to show absence of C arithmetic undefined behaviour. diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index cb9d292e..c0ac2c4a 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -7,8 +7,12 @@ This tutorial introduces CN through a series of examples and case studies, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. - - + +BCP: Once the structure of the tutorial stabilizes, we + + + could outline the material it covers in more detail... + CN can be used in two distinct ways: - The simpler way is as a framework for writing down formal diff --git a/src/exercises/read.broken.c b/src/exercises/read.broken.c index 1ec35621..3da42b9e 100644 --- a/src/exercises/read.broken.c +++ b/src/exercises/read.broken.c @@ -1,5 +1,5 @@ -int read (int *p) -/*@ requires take v1 = Owned(p); @*/ +unsigned read (unsigned *p) +/*@ requires take v1 = Owned(p); @*/ { return *p; } diff --git a/src/exercises/read2.c b/src/exercises/read2.c index 94ca64ea..a39dbdf7 100644 --- a/src/exercises/read2.c +++ b/src/exercises/read2.c @@ -1,6 +1,6 @@ -int read (int *p) -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +unsigned read (unsigned *p) +/*@ requires take P = Owned(p); + ensures take P_post = Owned(p); return == P; P_post == P; @*/ From e4b62da8dc75b317462e4639befdbe9a93f3cf1e Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 6 Mar 2025 10:48:47 -0500 Subject: [PATCH 039/158] Record instructions for running tests with replication output --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 766193d0..eb1cac4f 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,8 @@ WORKING=$(wildcard src/exercises/list_*.c) WORKING_AUX=$(patsubst src/exercises/%, docs/solutions/%, $(WORKING)) temp: $(WORKING_AUX) docs-exercises-dirs +# cn test --output-dir=$(HOME)/tmp --replicas read.broken.c + ############################################################################## # Check that the examples all run correctly From 9ccc8a533ac1e0be3f0e5fef22422df8be248ea7 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 6 Mar 2025 13:51:54 -0500 Subject: [PATCH 040/158] Finished rough draft of pointers.md --- docs/getting-started/tutorials/README.md | 8 +++- docs/getting-started/tutorials/arrays.md | 5 +++ .../{testing => }/overview-fulminate.md | 0 .../tutorials/{testing => }/overview-pbt.md | 0 docs/getting-started/tutorials/pointers.md | 25 +++++------- .../tutorials/{testing/outline.md => todo.md} | 40 ++----------------- 6 files changed, 24 insertions(+), 54 deletions(-) rename docs/getting-started/tutorials/{testing => }/overview-fulminate.md (100%) rename docs/getting-started/tutorials/{testing => }/overview-pbt.md (100%) rename docs/getting-started/tutorials/{testing/outline.md => todo.md} (73%) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index e2af6b40..b24e1da5 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -17,9 +17,12 @@ - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) - [Airport Simulation](../case-studies/the-runway.md) -## OLD STUFF + +## TODOs + +- [TODO list and discussion](todo.md) -*Delete me...* +## OLD STUFF - [Pointers and simple ownership](verification/pointers-and-simple-ownership.md) - [Ownership of compound objects](verification/ownership-of-compound-objects.md) @@ -28,6 +31,7 @@ - [Allocating and deallocating memory](verification/allocating-and-deallocating-memory.md) - [Lists](verification/lists.md) - [Working with external lemmas](verification/external-lemmas.md) + diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index d52df74c..fd2a9591 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -1,2 +1,7 @@ # Arrays + + +A potential case study (involving nested iteration): + + https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128 diff --git a/docs/getting-started/tutorials/testing/overview-fulminate.md b/docs/getting-started/tutorials/overview-fulminate.md similarity index 100% rename from docs/getting-started/tutorials/testing/overview-fulminate.md rename to docs/getting-started/tutorials/overview-fulminate.md diff --git a/docs/getting-started/tutorials/testing/overview-pbt.md b/docs/getting-started/tutorials/overview-pbt.md similarity index 100% rename from docs/getting-started/tutorials/testing/overview-pbt.md rename to docs/getting-started/tutorials/overview-pbt.md diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 6eb57c14..2a29f4fd 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -71,7 +71,9 @@ For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. This permission is represented by a _resource_ `Owned(p)`. -BCP: Is that right?? Should it be just Owned(p)? Or just Owned(p)?? +BCP: Is that right?? Should it be just Owned(p)? Or just +Owned(p)?? (I think just Owned(p) is OK, and we should use that +everywhere it's OK!) ## Owned resources @@ -298,13 +300,11 @@ exercises/slf3_basic_inplace_double.c ## Multiple owned pointers -======================= BCP STOPPED HERE ==================== - -When functions manipulate multiple pointers, we can assert their -ownership just like before. However -pointer ownership in CN is unique -- that is, simultaneously owning +When functions manipulate multiple pointers, we can assert +ownership of each one, just like before. But there is an additional +twist: pointer ownership in CN is _unique_ -- that is, simultaneously owning resources for two pointers implies that these -pointers are disjoint. +pointers refer to _disjoint_ regions of memory. The following example shows the use of two `Owned` resources for accessing two different pointers by a function `add`, which reads @@ -313,11 +313,10 @@ returns their sum. BCP: The way I've been naming things is not working that well -here. The problem is that in examples like this we computer "thing +here. The problem is that in examples like this we compute "thing pointed to by p" at both C and CN levels. At the C level, the thing pointed to by p obviously cannot also be called p, so it doesn't make -sense for it to be called P at the CN level, right? This should be -fixed by the proposed `$p` syntax. +sense for it to be called P at the CN level, right? @@ -332,13 +331,11 @@ exercises/add_read.c ``` -BCP: Does this belong here? +BCP: Does this belong here? Could it go in the later section on numeric types? The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned` type. Like C’s unsigned integer arithmetic, CN unsigned values wrap around when exceeding the value range of the type. Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. -In the following we will sometimes use unsigned integer types to focus on specifying memory ownership, rather than the conditions necessary to show absence of C arithmetic undefined behaviour. - ## Exercises _Swap._ Specify the function `swap`, which takes two owned `unsigned int` pointers and swaps their values. @@ -356,5 +353,3 @@ _Transfer._ Write a specification for the function `transfer`, shown below. exercises/slf8_basic_transfer.c --8<-- ``` - - diff --git a/docs/getting-started/tutorials/testing/outline.md b/docs/getting-started/tutorials/todo.md similarity index 73% rename from docs/getting-started/tutorials/testing/outline.md rename to docs/getting-started/tutorials/todo.md index aacbb80a..352db192 100644 --- a/docs/getting-started/tutorials/testing/outline.md +++ b/docs/getting-started/tutorials/todo.md @@ -1,34 +1,4 @@ -# CN Tutorial - -*Temporary -- stuff is moving to other files...* - -## PBT - - - Hello-world example of PBT (min3) - - original version: - ```c title="exercises/min3/min3.orig.c" - --8<-- - exercises/min3/min3-orig.c - --8<-- - ``` - - with a specification: - ```c title="exercises/min3/min3.test.c" - --8<-- - exercises/min3/min3.test.c - --8<-- - ``` - - with a spec and a mistake: - ```c title="exercises/min3/min3.brokentest.c" - --8<-- - exercises/min3/min3.brokentest.c - --8<-- - ``` - - - instructions for running PBT - - an exercise to try it out on min3 - - an exercise to find a bug in a variant of min3 - - couple more (similar, optional) exercises -- e.g., sorting three - numbers +# Things to do ## Case studies @@ -47,9 +17,7 @@ The current case studies from the verification tutorial - make a testing variant and an optional verification variant of each of them -____________________________________________________________________ - -# Questions and Discussion Points +## Questions and Discussion Points - The naming of exercises is hideous (esp. the slf ones) @@ -87,9 +55,7 @@ ____________________________________________________________________ context of "plain old specification and testing", before we get to verification. -____________________________________________________________________ - -# CN / VSCode Nits +## CN / VSCode Nits - It would be nice if (a) errors were indicated more boldly (e.g., a red slug in the margin, not just red squiggles) and (b) successful From 6b496ae04b667a8ec22848f6ba3896db96f4a626 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 6 Mar 2025 17:31:37 -0500 Subject: [PATCH 041/158] More progress on testing tutorial --- docs/getting-started/tutorials/README.md | 4 +- docs/getting-started/tutorials/arrays.md | 304 ++++++++++++++- ...hip-of-compound-objects.md => compound.md} | 56 ++- docs/getting-started/tutorials/pointers.md | 78 +++- .../verification/arrays-and-loops.md | 315 ---------------- .../pointers-and-simple-ownership.md | 353 ------------------ src/exercises/array_load.broken.c | 12 +- src/exercises/init_point.c | 14 +- src/exercises/transpose.broken.c | 6 +- src/exercises/transpose.c | 6 +- src/exercises/zero.c | 8 +- 11 files changed, 441 insertions(+), 715 deletions(-) rename docs/getting-started/tutorials/{verification/ownership-of-compound-objects.md => compound.md} (64%) delete mode 100644 docs/getting-started/tutorials/verification/arrays-and-loops.md delete mode 100644 docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index b24e1da5..ed682753 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -7,7 +7,8 @@ - [Preconditions](preconditions.md) - [V: A first taste of verification](basics-with-verification.md) - [Working with pointers](pointers.md) -- [Working with arrays](arrays.md) +- [Ownership of structured objects](compound.md) +- [Arrays and Loops](arrays.md) - [Dynamic storage allocation](dynamic.md) - [More on numeric types](numeric.md) @@ -24,7 +25,6 @@ ## OLD STUFF -- [Pointers and simple ownership](verification/pointers-and-simple-ownership.md) - [Ownership of compound objects](verification/ownership-of-compound-objects.md) - [Arrays and loops](verification/arrays-and-loops.md) - [Defining predicates](verification/defining-predicates.md) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index fd2a9591..aa15eeca 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -1,7 +1,307 @@ -# Arrays +# Arrays and Loops +Another common datatype in C is arrays. Reasoning about memory ownership for arrays is more difficult than for the datatypes we have seen so far, for two reasons: (1) C allows the programmer to access arrays using _computed pointers_, and (2) the size of an array does not need to be known as a constant at compile time. +To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `unsigned` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: -A potential case study (involving nested iteration): +```c +each (i32 i; 0i32 <= i && i < 10i32) +{ Owned(array_shift(p,i)) } +``` + +In detail, this can be read as follows: + +- for each integer `i` of CN type `i32`, … + +- if `i` is between `0` and `10`, … + +- assert ownership of a resource `Owned` … + +- for cell `i` of the array with base-address `p`. + +Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. + +In general, iterated resource specifications take the form + +```c +each (BT Q; GUARD) { RESOURCE } +``` + +comprising three parts: + +- `BT Q`, for some CN type `BT` and name `Q`, introduces the quantifier `Q` of basetype `BT`, which is bound in `GUARD` and `RESOURCE`; + +- `GUARD` is a boolean-typed expression delimiting the instances of `Q` for which ownership is asserted; and + +- `RESOURCE` is any non-iterated CN resource. + +### First array example + +Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. + +```c title="exercises/array_load.broken.c" +--8<-- +exercises/array_load.broken.c +--8<-- +``` + +The CN precondition requires + +- ownership of the array on entry — one `Owned` resource for each array index between `0` and `n` — and +- that `i` lies within the range of owned indices. + +On exit the array ownership is returned again. + + +BCP: Split the file here. In the testing variant, do several more +examples (e.g., maybe working up to sorting?). + + +This specification, in principle, should ensure that the access `p[i]` is safe. However, running CN on the example produces an error: CN is unable to find the required ownership for reading `p[i]`. + + +BCP: Update it + +``` +cn verify solutions/array_load.broken.c +[1/1]: read +build/solutions/array_load.broken.c:5:10: error: Missing resource for reading +return p[i]; +^~~~ +Resource needed: Owned(array_shift(p, (u64)i)) +``` + +The reason is that, when searching for a required resource, such as the `Owned` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. + + +BCP: This is more verification-relevant + + +To make the `Owned` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`extract`" ownership for index `i` out of the iterated resource. + +```c title="exercises/array_load.c" +--8<-- +exercises/array_load.c +--8<-- +``` + +Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: + +```c +each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } +``` + +is split into + +1. the instantiation of the iterated resource at `i` + +```c +Owned(array_shift(p,i)) +``` + +2. the remainder of the iterated resource, the ownership for all indices except `i` + +```c + each(i32 j; 0i32 <= j && j < n && j != i) + { Owned(array_shift(p,j)) } +``` + +After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. + +Following an `extract` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. + +So far the specification only guarantees safe execution but does not +specify the behaviour of `read`. To address this, let’s return to +the iterated resources in the function specification. When we specify +`take A = each ...` here, what is `A`? In CN, the output of an +iterated resource is a _map_ from indices to resource outputs. In this +example, where index `j` has CN type `i32` and the iterated +resource is `Owned`, the output `A` is a map from `i32` +indices to `i32` values — CN type `map`. If the type of +`j` was `i64` and the resource `Owned`, `A` would have +type `map`. + +We can use this to refine our specification with information about the functional behaviour of `read`. + +```c title="exercises/array_load2.c" +--8<-- +exercises/array_load2.c +--8<-- +``` + +We specify that `read` does not change the array — the outputs of `Owned`, +`A` and `A_post`, taken before and after running the function, are +the same — and that the value returned is `A[i]`. + +### Exercises + +_Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. + + +BCP: When we get around to renaming files in the examples directory, +we should call this one array_swap or something else beginning with +"array". Or put it in a subdirectory. + + +```c title="exercises/add_two_array.c" +--8<-- +exercises/add_two_array.c +--8<-- +``` + + +BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the extract declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) + + + +Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints + + +_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. + +```c title="exercises/swap_array.c" +--8<-- +exercises/swap_array.c +--8<-- +``` + + +TODO: BCP: I wrote this, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfecdt understanding of how the numeric stuff works. + + void swap_array (unsigned *p, unsigned n, unsigned i, unsigned j) + /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + 0i32 <= i && i < n; + 0i32 <= j && j < n; + j != i; + take xi = Owned(array_shift(p,i)); + take xj = Owned(array_shift(p,j)) + ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + a1[i:xj][j:xi] == a2 + @*/ + { + extract Owned, i; + extract Owned, j; + unsigned tmp = p[i]; + p[i] = p[j]; + p[j] = tmp; + } + + + + +### Loops + +The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. + +In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all owned resources and the constraints required to verify each iteration of the loop. + +Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. + + +BCP: Rename to array_init.c + + +```c title="exercises/init_array.c" +--8<-- +exercises/init_array.c +--8<-- +``` + +If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `Owned` resource -- one `Owned` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. + +To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). + +```c title="solutions/init_array.c" +--8<-- +solutions/init_array.c +--8<-- +``` + + + +TODO: BCP: Concrete syntax: Why not write something like "unchanged {p,n}" or "unchanged: p,n"? + + + +The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. + +The second thing we need to do, however, is less straightforward. Recall that, as discussed at the start of the tutorial, function arguments in C are mutable. Although, in this example, it is obvious that `p` and `n` do not change, CN currently requires the loop invariant to explicitly state this, using special notation `{p} unchanged` (and similarly for `n`). + +**Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. + + + +TODO: BCP: This seems like a good idea! + + + +The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. + +With the `inv` and `extract` statements in place, CN accepts the function. + +### Second loop example + +The specification of `init_array` is overly strong: it requires an iterated `Owned` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `Block` resource for the array should also be sufficient. The modified specification is then as follows. + +```c title="exercises/init_array2.c" +--8<-- +exercises/init_array2.c +--8<-- +``` + +This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `Block` to `Owned` "`state`", so that on function return the full array is initialised. (Recall that stores only require `Block` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) + +To verify this modified example we again need a loop Invariant. But +this time the loop invariant is more involved: since each iteration of +the loop initialises one more array cell, the loop invariant has to do +precise book-keeping of the initialisation status of the different +sections of the array. + +To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `Owned` resource, for all other array indices we have the (unchanged) `Block` ownership. + +```c title="solutions/init_array2.c" +--8<-- +solutions/init_array2.c +--8<-- +``` + +Let's go through this line-by-line: + +- We assert ownership of an iterated `Owned` resource, one for each index `i` strictly smaller than loop variable `j`. + +- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `Block` resource. + +- As in the previous example, we assert `p` and `n` are unchanged. + +- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `Owned` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. + +As before, we also have to instruct CN to `extract` ownership of individual array cells out of the iterated resources: + +- to allow CN to extract the individual `Block` to be written, we use `extract Block, j;`; + +- the store returns a matching `Owned` resource for index `j`; + +- finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. + + +BCP: That last bit is mysterious. + + +Dhruv: See long explanation and issue here: rems-project/cerberus#498 + + +### Exercises + +**Init array reverse.** Verify the function `init_array_rev`, which has the same specification as `init_array2`, but initializes the array in decreasing index order (from right to left). + +```c title="exercises/init_array_rev.c" +--8<-- +exercises/init_array_rev.c +--8<-- +``` + + +A potential case study (involving nested iteration): https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128 + diff --git a/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md b/docs/getting-started/tutorials/compound.md similarity index 64% rename from docs/getting-started/tutorials/verification/ownership-of-compound-objects.md rename to docs/getting-started/tutorials/compound.md index 63b111ca..fae2f6dc 100644 --- a/docs/getting-started/tutorials/verification/ownership-of-compound-objects.md +++ b/docs/getting-started/tutorials/compound.md @@ -1,6 +1,9 @@ -# Ownership of Compound Objects +# Ownership of Structured Objects -So far, our examples have worked with just integers and pointers, but larger programs typically also manipulate compound values, often represented using C struct types. Specifying functions manipulating structs works in much the same way as with basic types. +So far, our examples have worked with just integers and pointers, but +larger programs typically also manipulate compound values, often +represented using C `struct`s. Specifying functions manipulating +structs works in much the same way as with basic types. For instance, the following example uses a `struct` `point` to represent a point in two-dimensional space. The function `transpose` swaps a point’s `x` and `y` coordinates. @@ -10,6 +13,11 @@ exercises/transpose.c --8<-- ``` + +BCP: This talks about "CN types," which haven't really been +introduced. It also talks about i32, whereas (a) we are using u32 and +(b) I don't know if this has been introduced anyway. + Here the precondition asserts ownership for `p`, at type `struct point`; the output `P_post` is a value of CN type `struct point`, i.e. a record with members `i32` `x` and `i32` `y`. The @@ -18,31 +26,43 @@ postcondition similarly asserts ownership of `p`, with output the members of `P` and `P_post` individually. -BCP: This paragraph is quite confusing if read carefully: it seems to say that the "take" in the requires clause returns a different type than the "tajke" in the "ensures" clause. Moreover, even if the reader decides that this cannot be the case and they have to return the same type, they may wonder whether thius type is a C type (which is what it looks like, since there is only one struct declaration, and it is not in a magic comment) or a CN type (which might be expected, since it is the result of a "take"). I _guess_ what's going on here is that every C type is automatically reflected as a CN type with the same name. But this story is also not 100% satisfying, since the basic numeric types don't work this way: each C numeric type has an _analog_ in CN, but with a different name. +BCP: This paragraph is quite confusing if read carefully: it seems to say that the "take" in the requires clause returns a different type than the "tajke" in the "ensures" clause. Moreover, even if the reader decides that this cannot be the case and they have to return the same type, they may wonder whether this type is a C type (which is what it looks like, since there is only one struct declaration, and it is not in a magic comment) or a CN type (which might be expected, since it is the result of a "take"). I _guess_ what's going on here is that every C type is automatically reflected as a CN type with the same name. But this story is also not 100% satisfying, since the basic numeric types don't work this way: each C numeric type has an _analog_ in CN, but with a different name. - --- Dhruv: +Dhruv: C supports strong updates in certain situations and so take _ = Owned(p) in the requires clause could very well have a different C type than take _ = Owned(p) in the ensures clause. + -The reason Owned needs a C-type is so that it can (a) figure out the size of the sub-heap being claimed and (b) figure out how one may need to destructure the type (unions, struct fields and padding, arrays). The relationship is that for take x = Owned(expr), expr : pointer, x : to_basetype(ct). -There is a design decision to consider here rems-project/cerberus#349 +The reason `Owned` needs a C-type annotation is so that it can (a) +figure out the size of the sub-heap being claimed and (b) figure out +how one may need to destructure the type (unions, struct fields and +padding, arrays). The relationship is that for `take x = +Owned(expr)` we have `expr : pointer, x : to_basetype(ct)`. + +There is a design decision to consider here rems-project/cerberus#349 ### Compound Owned and Block resources + +BCP: The rest fo the chapter is probably just for verification. + + While one might like to think of a struct as a single (compound) object that is manipulated as a whole, C permits more flexible struct manipulation: given a struct pointer, programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `Owned` and `Block` are defined inductively on the structure of the C-type `T`. For struct types `T`, the `Owned` resource is defined as the collection of `Owned` resources for its members (as well as `Block` resources for any padding bytes in-between them). The resource `Block`, similarly, is made up of `Block` resources for all members (and padding bytes). + +BCP: Is this relevant to testing? + To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. -Recall the function `zero` from our earlier exercise. It takes an `int` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. +Recall the function `zero` from our earlier exercise. It takes an `unsigned` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. Now consider the function `init_point`, shown below, which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. @@ -52,9 +72,9 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `Block(p)`. The `zero` function, however, works on `int` pointers and requires `Block` ownership. +As stated in its precondition, `init_point` receives ownership `Block(p)`. The `zero` function, however, works on `unsigned` pointers and requires `Block` ownership. -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. +CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. ### Resource inference @@ -74,9 +94,9 @@ exercises/transpose.broken.c The precondition of `transpose` asserts ownership of an `Owned(p)` resource. The error report now instead lists under "`Available resources`" two resources: -- `Owned(member_shift(p, x))` with output `P.x` and +- `Owned(member_shift(p, x))` with output `P.x` and -- `Owned(member_shift(p, y))` with output `P.y` +- `Owned(member_shift(p, y))` with output `P.y` BCP: We should verify that it really does say this. @@ -89,8 +109,16 @@ When the function returns, the two member resources are recombined "`on demand`" ### Exercises _Init point._ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. + +BCP: That's just for verification. + + _Transpose (again)._ Recreate the transpose function from before, now using the swap function verified earlier (for `struct upoint`, with unsigned member values). + +BCP: No need for upoint now... + + ```c title="exercises/transpose2.c" --8<-- @@ -99,13 +127,11 @@ exercises/transpose2.c ``` - -TODO: BCP: Some more things to think about including... - Something about CN's version of the frame rule (see +BCP: Some more things to think about including... - Something about CN's version of the frame rule (see bcp_framerule.c, though the example is arguably a bit unnatural). - Examples from Basic.v with allocation - there are lots of interesting ones! CP: Agreed. For now continuing with arrays, but will return to this later. - diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 2a29f4fd..6852d56a 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -13,7 +13,8 @@ Things to do: - read.broken.c demonstrates linearity of resource usage - exercises: - quadruple_mem - - abs_mem + - abs_mem (doesn't work, but we can use the other examples + from the previous section) - slf0_basic_incr_signed.c shows the difference between Block and Owned - exercises @@ -27,10 +28,10 @@ Things to do: - everything up through pointers to compound objects seems to work well, except for some of the resource inference stuff -So far we’ve only considered functions manipulating integer -values. Specifications become more interesting and challenging when -_pointers_ are involved, because the safety of memory accesses via -pointers has to be taken into account. +So far we’ve only considered functions manipulating numeric +values. Specifications become more interesting when _pointers_ are +involved, because the safety of memory accesses via pointers has to be +taken into account. CN uses _separation logic resources_ and the concept of _ownership_ to reason about memory accesses. A resource is the permission to access a @@ -262,10 +263,51 @@ exercises/abs_mem.c --8<-- ``` +## Block resources + +Aside from the `Owned` resources seen so far, CN has another +built-in type of resource called `Block`. Given a C-type `T` and +pointer `p`, `Block(p)` asserts the same ownership as +`Owned(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `Owned`, `Block` memory is not assumed +to be initialised. + +CN uses this distinction to prevent reads from uninitialised memory: + +- A read at C-type `T` and pointer `p` requires a resource + `Owned(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `Owned` resource unchanged. + +- A write at C-type `T` and pointer `p` needs only a +`Block(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `Block` resource +(it destroys it) and returns a new resource `Owned(p)` with the +value written as the output. This means the resource returned from a +write records the fact that this memory cell is now initialised and +can be read from. + +BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. + + +Since `Owned` carries the same ownership as `Block`, just with the +additional information that the `Owned` memory is initalised, a +resource `Owned(p)` is "at least as good" as `Block(p)` — +an `Owned(p)` resource can be used whenever `Block(p)` is +needed. For instance CN’s type checking of a write to `p` requires a +`Block(p)`, but if an `Owned(p)` resource is what is +available, this can be used just the same. This allows an +already-initialised memory cell to be over-written again. + +Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. + ## Writing through pointers Let’s explore resources and their outputs in another example. The C function `incr` takes an `unsigned` pointer `p` and increments the value in the memory cell that it poinbts to. + +BCP: unsigned! (there are both signed and unsigned versions at the +moment -- how do they relate?) + ```c title="exercises/slf0_basic_incr.signed.c" --8<-- exercises/slf0_basic_incr.signed.c @@ -280,6 +322,32 @@ asserts ownership of `p` with output `P_post`, as before, and uses this to express that the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. +If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. + + +BCP: change it to unsigned... + + + +```c title="exercises/slf0_basic_incr.signed.broken.c" +--8<-- +exercises/slf0_basic_incr.signed.broken.c +--8<-- +``` + +CN reports: + +BCP: fix it... + + +``` +build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading +int n = \*p; +^~ +Resource needed: Owned(p) +Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html +``` + ## Exercises _Zero._ Write a specification for the function `zero`, which takes a pointer to _uninitialised_ memory and initialises it to `0`. diff --git a/docs/getting-started/tutorials/verification/arrays-and-loops.md b/docs/getting-started/tutorials/verification/arrays-and-loops.md deleted file mode 100644 index ff6da597..00000000 --- a/docs/getting-started/tutorials/verification/arrays-and-loops.md +++ /dev/null @@ -1,315 +0,0 @@ -# Arrays and Loops - -Another common datatype in C is arrays. Reasoning about memory ownership for arrays is more difficult than for the datatypes we have seen so far, for two reasons: (1) C allows the programmer to access arrays using _computed pointers_, and (2) the size of an array does not need to be known as a constant at compile time. - -To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `int` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: - - -BCP: Another tricky naming / capitalization puzzle: The index of an "each" has CN type i32, so strictly speaking I believe it should be written with a capital "I". But insisting on this feels like insisting on a distinction that most CN programmers would never even notice, much less be confused by. I think this is another instance of the way C and CN integer types are partly but not completely squished together. - - -```c -each (i32 i; 0i32 <= i && i < 10i32) -{ Owned(array_shift(p,i)) } -``` - -In detail, this can be read as follows: - -- for each integer `i` of CN type `i32`, … - -- if `i` is between `0` and `10`, … - -- assert ownership of a resource `Owned` … - -- for cell `i` of the array with base-address `p`. - -Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. - -In general, iterated resource specifications take the form - -```c -each (BT Q; GUARD) { RESOURCE } -``` - -comprising three parts: - -- `BT Q`, for some CN type `BT` and name `Q`, introduces the quantifier `Q` of basetype `BT`, which is bound in `GUARD` and `RESOURCE`; - -- `GUARD` is a boolean-typed expression delimiting the instances of `Q` for which ownership is asserted; and - -- `RESOURCE` is any non-iterated CN resource. - -### First array example - -Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. - -```c title="exercises/array_load.broken.c" ---8<-- -exercises/array_load.broken.c ---8<-- -``` - -The CN precondition requires - -- ownership of the array on entry — one `Owned` resource for each array index between `0` and `n` — and -- that `i` lies within the range of owned indices. - -On exit the array ownership is returned again. - -This specification, in principle, should ensure that the access `p[i]` is safe. However, running CN on the example produces an error: CN is unable to find the required ownership for reading `p[i]`. - -``` -cn verify solutions/array_load.broken.c -[1/1]: read -build/solutions/array_load.broken.c:5:10: error: Missing resource for reading -return p[i]; -^~~~ -Resource needed: Owned(array_shift(p, (u64)i)) -``` - -The reason is that, when searching for a required resource, such as the `Owned` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. - -To make the `Owned` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`extract`" ownership for index `i` out of the iterated resource. - -```c title="exercises/array_load.c" ---8<-- -exercises/array_load.c ---8<-- -``` - -Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: - -```c -each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } -``` - -is split into - -1. the instantiation of the iterated resource at `i` - -```c -Owned(array_shift(p,i)) -``` - -2. the remainder of the iterated resource, the ownership for all indices except `i` - -```c - each(i32 j; 0i32 <= j && j < n && j != i) - { Owned(array_shift(p,j)) } -``` - -After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. - -Following an `extract` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. - -So far the specification only guarantees safe execution but does not -specify the behaviour of `read`. To address this, let’s return to -the iterated resources in the function specification. When we specify -`take A = each ...` here, what is `A`? In CN, the output of an -iterated resource is a _map_ from indices to resource outputs. In this -example, where index `j` has CN type `i32` and the iterated -resource is `Owned`, the output `A` is a map from `i32` -indices to `i32` values — CN type `map`. If the type of -`j` was `i64` and the resource `Owned`, `A` would have -type `map`. - -We can use this to refine our specification with information about the functional behaviour of `read`. - -```c title="exercises/array_load2.c" ---8<-- -exercises/array_load2.c ---8<-- -``` - -We specify that `read` does not change the array — the outputs of `Owned`, -`A` and `A_post`, taken before and after running the function, are -the same — and that the value returned is `A[i]`. - -### Exercises - -_Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. - - -BCP: When we get around to renaming files in the examples directory, we should call this one array_swap or something else beginning with "array". - - -```c title="exercises/add_two_array.c" ---8<-- -exercises/add_two_array.c ---8<-- -``` - - - -TODO: BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the extract declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) - -TODO: Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints - - - -_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. - -```c title="exercises/swap_array.c" ---8<-- -exercises/swap_array.c ---8<-- -``` - - - -TODO: BCP: I wrote this, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfecdt understanding of how the numeric stuff works. - - void swap_array (int *p, int n, int i, int j) - /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; - 0i32 <= i && i < n; - 0i32 <= j && j < n; - j != i; - take xi = Owned(array_shift(p,i)); - take xj = Owned(array_shift(p,j)) - ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; - a1[i:xj][j:xi] == a2 - @*/ - { - extract Owned, i; - extract Owned, j; - int tmp = p[i]; - p[i] = p[j]; - p[j] = tmp; - } - - - - -### Loops - -The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. - -In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all owned resources and the constraints required to verify each iteration of the loop. - -Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. - - -BCP: Rename to array_init.c - - -```c title="exercises/init_array.c" ---8<-- -exercises/init_array.c ---8<-- -``` - -If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `Owned` resource -- one `Owned` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. - -To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). - -```c title="solutions/init_array.c" ---8<-- -solutions/init_array.c ---8<-- -``` - - - -TODO: BCP: Concrete syntax: Why not write something like "unchanged {p,n}" or "unchanged: p,n"? - - - -The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. - -The second thing we need to do, however, is less straightforward. Recall that, as discussed at the start of the tutorial, function arguments in C are mutable. Although, in this example, it is obvious that `p` and `n` do not change, CN currently requires the loop invariant to explicitly state this, using special notation `{p} unchanged` (and similarly for `n`). - -**Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. - - - -TODO: BCP: This seems like a good idea! - - - -The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. - -With the `inv` and `extract` statements in place, CN accepts the function. - -### Second loop example - -The specification of `init_array` is overly strong: it requires an iterated `Owned` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `Block` resource for the array should also be sufficient. The modified specification is then as follows. - -```c title="exercises/init_array2.c" ---8<-- -exercises/init_array2.c ---8<-- -``` - -This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `Block` to `Owned` "`state`", so that on function return the full array is initialised. (Recall that stores only require `Block` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) - -To verify this modified example we again need a loop Invariant. But -this time the loop invariant is more involved: since each iteration of -the loop initialises one more array cell, the loop invariant has to do -precise book-keeping of the initialisation status of the different -sections of the array. - -To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `Owned` resource, for all other array indices we have the (unchanged) `Block` ownership. - -```c title="solutions/init_array2.c" ---8<-- -solutions/init_array2.c ---8<-- -``` - -Let's go through this line-by-line: - -- We assert ownership of an iterated `Owned` resource, one for each index `i` strictly smaller than loop variable `j`. - -- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `Block` resource. - -- As in the previous example, we assert `p` and `n` are unchanged. - -- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `Owned` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. - -As before, we also have to instruct CN to `extract` ownership of individual array cells out of the iterated resources: - -- to allow CN to extract the individual `Block` to be written, we use `extract Block, j;`; - -- the store returns a matching `Owned` resource for index `j`; - -- finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. - - -BCP: That last bit is mysterious. - - -Dhruv: See long explanation and issue here: rems-project/cerberus#498 - - -### Exercises - -**Init array reverse.** Verify the function `init_array_rev`, which has the same specification as `init_array2`, but initializes the array in decreasing index order (from right to left). - -```c title="exercises/init_array_rev.c" ---8<-- -exercises/init_array_rev.c ---8<-- -``` - - -BCP: The transition to the next section is awkward. Needs a sentence or two to signal that we're changing topics. Some better visual indication would also be nice. - - - - - ---- - ---- - ---- - ---- - ---- - -TODO: BCP: I'll put my new stuff below here... - - - - diff --git a/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md b/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md deleted file mode 100644 index 12e15f41..00000000 --- a/docs/getting-started/tutorials/verification/pointers-and-simple-ownership.md +++ /dev/null @@ -1,353 +0,0 @@ -# Pointers and Simple Ownership - -So far we’ve only considered example functions manipulating integer values. Verification becomes more interesting and challenging when _pointers_ are involved, because the safety of memory accesses via pointers has to be verified. - -CN uses _separation logic resources_ and the concept of _ownership_ to reason about memory accesses. A resource is the permission to access a region of memory. Unlike logical constraints, resource ownership is _unique_, meaning resources cannot be duplicated. - -Let’s look at a simple example. The function `read` takes an `int` pointer `p` and returns the pointee value. - -```c title="exercises/read.c" ---8<-- -exercises/read.c ---8<-- -``` - -Running CN on this example produces the following error: - -``` -cn verify exercises/read.c -[1/1]: read -exercises/read.c:3:10: error: Missing resource for reading -return \*p; -^~ -Resource needed: Owned(p) -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_403624.html -``` - -For the read `*p` to be safe, ownership of a resource is missing: a resource `Owned(p)`. - -### Owned resources - - - TODO: BCP: Perhaps this is a good time for one last discussion of the keyword "Owned", which I have never found very helpful: the resource itself isn't owned -- it's a description of something that _can_ be owned. (It's "take" that does the owning.) Moreover, "Owned" and "Block" are badly non-parallel, both grammatically and semantically. I suggest "Resource" instead of "Owned". (We can keep "Block" -- it's not too bad, IMO.) - - - - -Dhruv: -We use the word "resources" to describe any "resource predicate" owned, or user-defined, (and eventually live allocations and locks) so I'm not sure that suggestion works any better. It is just a points-to with read and write permissions, so perhaps a RW(p)? (or ReadWrite(p)?). - -@bcpierce00 -Both of these are better than Owned! - -(And then Block can become WriteOnly.) - -BCP: I think this discussion is reflected in the GitHub exchange - - - -Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). - -In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as shown below. For now ignore the notation `take ... = Owned(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. - -```c title="solutions/read.c" ---8<-- -solutions/read.c ---8<-- -``` - -This specification means that: - -- any function calling `read` has to be able to provide a resource `Owned(p)` to pass into `read`, and - -- the caller will receive back a resource `Owned(p)` when `read` returns. - -### Resource outputs - -A caller of `read` may also wish to know that `read` actually returns the correct value, the pointee of `p`, and also that it does not change memory at location `p`. To phrase both we need a way to refer to the pointee of `p`. - - - TODO: BCP: The idea that "resources have outputs" is very mind-boggling to many new users, _especially_ folks with some separation logic background. Needs to be explained very carefully. Also, there's some semantic muddle in the terminology: Is a resource (1) a thing in the heap, (2) a thing in the heap that one is currently holding, or (3) the act of holding a thing in the heap? These are definitely not at all the same thing, but our language at different points suggests all three! To me, (1) is the natural sense of the word "resource"; (2) is somewhat awkward, and (3) is extremely awkward. - - -In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `Owned(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. - - - TODO: BCP: ... in a given heap! (The real problem here is that "and the associated ownership" is pretty vague.) - - -Dhruv: Perhaps mentioning sub-heaps will help? - - -CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = Owned(p)` does two things: (1) it assert ownership of resource `Owned(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. - - - TODO: BCP: But, as we've discussed, the word "take" in the postcondition is quite confusing: What it's doing is precisely the _opposite_ of "taking" the resournce, not taking it but giving it back!! It would be much better if we could choose a more neutral word that doesn't imply either taking or giving. E.g. "resource". - - - - TODO: BCP: This might be a good place for a comment on naming conventions. Plus a pointer to a longer discussion if needed - - -That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying - -1. that `read` returns `P` (the initial pointee value of `p`), and -1. that the pointee values `P` and `P_post` before and after execution of `read` (respectively) are the same. - -```c title="exercises/read2.c" ---8<-- -exercises/read2.c ---8<-- -``` - -_Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): - - - TODO: Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. - - - - Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? - - -``` -∀p. -∀v1. -{ p ↦ P } -read(p) -{ \return. ∃P_post. (p ↦ P_post) /\ return = P /\ P = P_post } -``` - -CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. - -### Linear resource ownership - -In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. - -Let’s try the `read` example from earlier again, but with a postcondition that does not return the ownership: - -```c title="exercises/read.broken.c" ---8<-- -exercises/read.broken.c ---8<-- -``` - -CN rejects this program with the following message: - -``` -cn verify exercises/read.broken.c -[1/1]: read -build/exercises/read.broken.c:4:3: error: Left_Sublist-over unused resource 'Owned(p)(v1)' -return \*p; -^~~~~~~~~~ -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_17eb4a.html -``` - -CN has typechecked the function and verified (1) that it is safe to -execute under the precondition (given ownership `Owned(p)`) -and (2) that the function (vacuously) satisfies its postcondition. But -following the check of the postcondition it finds that not all -resources have been "`used up`". - -Indeed, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. - -CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "`forgotten`". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). - -CN’s motivation for linear tracking of resources is its focus on -low-level systems software in which memory is managed manually; in -this context, memory leaks are typically very undesirable. As a -consequence, function specifications have to do precise bookkeeping of -their resource footprint and, in particular, return any unused -resources back to the caller. - -### Exercises - -_Quadruple_. Specify the function `quadruple_mem`, which is similar to the earlier `quadruple` function, except that the input is passed as an `int` pointer. Write a specification that takes ownership of this pointer on entry and returns this ownership on exit, leaving the pointee value unchanged. - -```c title="exercises/slf_quadruple_mem.c" ---8<-- -exercises/slf_quadruple_mem.c ---8<-- -``` - -_Abs_. Give a specification to the function `abs_mem`, which computes the absolute value of a number passed as an `int` pointer. - -```c title="exercises/abs_mem.c" ---8<-- -exercises/abs_mem.c ---8<-- -``` - -### Block resources - -Aside from the `Owned` resources seen so far, CN has another -built-in type of resource called `Block`. Given a C-type `T` and -pointer `p`, `Block(p)` asserts the same ownership as -`Owned(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `Owned`, `Block` memory is not assumed -to be initialised. - -CN uses this distinction to prevent reads from uninitialised memory: - -- A read at C-type `T` and pointer `p` requires a resource - `Owned(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `Owned` resource unchanged. - -- A write at C-type `T` and pointer `p` needs only a -`Block(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `Block` resource -(it destroys it) and returns a new resource `Owned(p)` with the -value written as the output. This means the resource returned from a -write records the fact that this memory cell is now initialised and -can be read from. - - TODO: BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. - - -Since `Owned` carries the same ownership as `Block`, just with the -additional information that the `Owned` memory is initalised, a -resource `Owned(p)` is "`at least as good`" as `Block(p)` — -an `Owned(p)` resource can be used whenever `Block(p)` is -needed. For instance CN’s type checking of a write to `p` requires a -`Block(p)`, but if an `Owned(p)` resource is what is -available, this can be used just the same. This allows an -already-initialised memory cell to be over-written again. - -Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. - -### Writing through pointers - -Let’s explore resources and their outputs in another example. The C function `incr` takes an `int` pointer `p` and increments the value in the memory cell that it poinbts to. - -```c title="exercises/slf0_basic_incr.signed.c" ---8<-- -exercises/slf0_basic_incr.signed.c ---8<-- -``` - -In the precondition we assert ownership of resource `Owned(p)`, -binding its output/pointee value to `P`, and use `P` to specify -that `p` must point to a sufficiently small value at the start of -the function so as not to overflow when incremented. The postcondition -asserts ownership of `p` with output `P_post`, as before, and uses -this to express that the value `p` points to is incremented by -`incr`: `P_post == P + 1i32`. - -If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. - -```c title="exercises/slf0_basic_incr.signed.broken.c" ---8<-- -exercises/slf0_basic_incr.signed.broken.c ---8<-- -``` - -CN reports: - -``` -build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading -int n = \*p; -^~ -Resource needed: Owned(p) -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html -``` - -The `Owned(p)` resource required for reading is missing, since, per the precondition, only `Block(p)` is available. Checking the linked HTML file confirms this. Here the section "`Available resources`" lists all resource ownership at the point of the failure: - -- `Block(p)(u)`, i.e., ownership of uninitialised memory - at location `p`; the output is a `void`/`unit` value `u` - (specified in the second pair of parentheses) - -- `Owned(&ARG0)(p)`, the ownership of (initialised) - memory at location `&ARG0`, i.e., the memory location where the - first function argument is stored; its output is the pointer `p` - (not to be confused with the pointee of `p`); and finally - -- `__CN_Alloc(&ARG0)(void)` is a resource that records allocation - information for location `&ARG0`; this is related to CN’s - memory-object semantics, which we ignore for the moment. - - - TODO: BCP: These bullet points are all a bit mysterious and maybe TMI. More generally, we should double check that this is actually the information displayed in the current HTML output... - - -Dhruv: It is displayed, but hidden. And perhaps TMI right now, but once the memory model lands properly, will sadly be the price of entry to writing verifiable (semantically well-defined) C. - - -### Exercises - -_Zero._ Write a specification for the function `zero`, which takes a pointer to _uninitialised_ memory and initialises it to `0`. - -```c title="exercises/zero.c" ---8<-- -exercises/zero.c ---8<-- -``` - -_In-place double._ Give a specification for the function `inplace_double`, which takes an `int` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. - -```c title="exercises/slf3_basic_inplace_double.c" ---8<-- -exercises/slf3_basic_inplace_double.c ---8<-- -``` - -### Multiple owned pointers - -When functions manipulate multiple pointers, we can assert their -ownership just like before. However -pointer ownership in CN is unique -- that is, simultaneously owning -`Owned` or `Block` resources for two pointers implies that these -pointers are disjoint. - -The following example shows the use of two `Owned` resources for -accessing two different pointers by a function `add`, which reads -two `int` values in memory, at locations `p` and `q`, and -returns their sum. - - - TODO: BCP: Hmmm -- I'm not very sure that the way I've been naming things is actually working that well. The problem is that in examples like this we computer "thing pointed to by p" at both C and CN levels. At the C level, the thing pointed to by p obviously cannot also be called p, so it doesn't make sense for it to be called P at the CN level, right? Maybe we need to think again, but hoinestly I am not certain that it is _not_ working either. So I'm going to opush on for now... - - -```c title="exercises/add_read.c" ---8<-- -exercises/add_read.c ---8<-- -``` - -This time we use C’s `unsigned int` type. In C, over- and underflow of unsigned integers is not undefined behaviour, so we do not need any special preconditions to rule this out. Instead, when an arithmetic operation at unsigned type goes outside the representable range, the value "`wraps around`". - -The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. - -Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. - - - TODO: BCP: I wonder whether we should uniformly use i32 integers everywhere in the tutorial (just mentioning in the bullet list below that there are other integer types, and using i64 for calculations that may overflow). Forgetting which integer type I was using was a common (and silly) failure mode when I was first working through the tutorial. - - -Dhruv: Sensible. - - - BCP: ... On second thought, maybe settling on u32 instead of i32 in most places is better (fewer things to prove). Or maybe it doesn't matter much. For the start of the tutorial, i32 is important because the examples are all about overflow. But after that we could go either way. - - -In the following we will sometimes use unsigned integer types to focus on specifying memory ownership, rather than the conditions necessary to show absence of C arithmetic undefined behaviour. - -### Exercises - -_Swap._ Specify the function `swap`, which takes two owned `unsigned int` pointers and swaps their values. - -```c title="exercises/swap.c" ---8<-- -exercises/swap.c ---8<-- -``` - -_Transfer._ Write a specification for the function `transfer`, shown below. - -```c title="exercises/slf8_basic_transfer.c" ---8<-- -exercises/slf8_basic_transfer.c ---8<-- -``` - - diff --git a/src/exercises/array_load.broken.c b/src/exercises/array_load.broken.c index 446072cf..4909ee38 100644 --- a/src/exercises/array_load.broken.c +++ b/src/exercises/array_load.broken.c @@ -1,9 +1,9 @@ -int read (int *p, int n, int i) -/*@ requires take A = each(i32 j; 0i32 <= j && j < n) { - Owned(array_shift(p,j)) }; - 0i32 <= i && i < n; - ensures take A_post = each(i32 j; 0i32 <= j && j < n) { - Owned(array_shift(p,j)) }; +int read (unsigned *p, unsigned n, unsigned i) +/*@ requires take A = each(u32 j; 0u32 <= j && j < n) { + Owned(array_shift(p,j)) }; + 0u32 <= i && i < n; + ensures take A_post = each(u32 j; 0u32 <= j && j < n) { + Owned(array_shift(p,j)) }; @*/ { return p[i]; diff --git a/src/exercises/init_point.c b/src/exercises/init_point.c index 4ecb67f3..64ae0b7b 100644 --- a/src/exercises/init_point.c +++ b/src/exercises/init_point.c @@ -1,18 +1,18 @@ -void zero (int *coord) -/*@ requires take Coord = Block(coord); - ensures take Coord_post = Owned(coord); - Coord_post == 0i32; @*/ +void zero (unsigned *coord) +/*@ requires take Coord = Block(coord); + ensures take Coord_post = Owned(coord); + Coord_post == 0u32; @*/ { *coord = 0; } -struct point { int x; int y; }; +struct point { unsigned x; unsigned y; }; void init_point(struct point *p) /*@ requires take P = Block(p); ensures take P_post = Owned(p); - P_post.x == 0i32; - P_post.y == 0i32; + P_post.x == 0u32; + P_post.y == 0u32; @*/ { zero(&p->x); diff --git a/src/exercises/transpose.broken.c b/src/exercises/transpose.broken.c index 47ef9479..33cf20b4 100644 --- a/src/exercises/transpose.broken.c +++ b/src/exercises/transpose.broken.c @@ -1,4 +1,4 @@ -struct point { int x; int y; }; +struct point { unsigned x; unsigned y; }; void transpose (struct point *p) /*@ requires take P = Owned(p); @@ -7,8 +7,8 @@ void transpose (struct point *p) P_post.y == P.x; @*/ { - int temp_x = p->x; - int temp_y = p->y; + unsigned temp_x = p->x; + unsigned temp_y = p->y; /*@ assert(false); @*/ p->x = temp_y; p->y = temp_x; diff --git a/src/exercises/transpose.c b/src/exercises/transpose.c index 03b1d9d8..36b85334 100644 --- a/src/exercises/transpose.c +++ b/src/exercises/transpose.c @@ -1,4 +1,4 @@ -struct point { int x; int y; }; +struct point { unsigned x; unsigned y; }; void transpose (struct point *p) /*@ requires take P = Owned(p); @@ -7,8 +7,8 @@ void transpose (struct point *p) P_post.y == P.x; @*/ { - int temp_x = p->x; - int temp_y = p->y; + unsigned temp_x = p->x; + unsigned temp_y = p->y; p->x = temp_y; p->y = temp_x; } diff --git a/src/exercises/zero.c b/src/exercises/zero.c index c7fbf8c7..8454b9af 100644 --- a/src/exercises/zero.c +++ b/src/exercises/zero.c @@ -1,8 +1,8 @@ -void zero (int *p) +void zero (unsigned *p) /* --BEGIN-- */ -/*@ requires take P = Block(p); - ensures take P_post = Owned(p); - P_post == 0i32; +/*@ requires take P = Block(p); + ensures take P_post = Owned(p); + P_post == 0u32; @*/ /* --END-- */ { From 842d6b05b270a8722b6bba124a37dc742766af7d Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Sat, 8 Mar 2025 20:07:14 -0500 Subject: [PATCH 042/158] WIP revamping the Makefile for testing --- Makefile | 92 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index eb1cac4f..8fc3a848 100644 --- a/Makefile +++ b/Makefile @@ -7,47 +7,65 @@ all: default clean: rm -rf docs/exercises docs/solutions docs/exercises.zip \ - build TAGS _tests + build TAGS _temp # find . -type f -regex 'cn.*' -delete # find . -type f -regex '*-exec.*' -delete ############################################################################## # Exercises -SRC_EXERCISES=$(shell find src/exercises -type f) -SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(SRC_EXERCISES)) -EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(SRC_EXERCISES)) +EXCLUDE = cn.c cn.h run_tests.sh *-exec.c *_test.c -CN=cn verify -CNTEST=cn test +H = $(shell find src/exercises -type f -name *.h) +C = $(shell find src/exercises -type f -name *.c) +ALL = $(H) $(C) +NOTBROKEN = $(filter-out %broken%, $(C)) + +SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(ALL)) +EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(ALL)) +VERIFIED=$(patsubst src/exercises/%, _temp/verified/%, $(NOTBROKEN)) +TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(NOTBROKEN)) -exercises: docs-exercises-dirs $(EXERCISES) $(SOLUTIONS) +exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) -docs-exercises-dirs: - mkdir -p docs/exercises - mkdir -p docs/solutions +CN=cn verify +# make sure to add --output _temp again +CNTEST=cn test --replicas --trace-granularity=none +# CNTEST=cn test --replicas --output _temp --trace-granularity=none +# The --trace-granularity=none part can be deleted soon + +V=@ + +_temp/tested/% : src/exercises/% + $(V)echo Testing $< + $(V)-mkdir -p $(dir $@) + $(V)# Next line should be reverted! + $(V)(cd src/exercises; $(CNTEST) ../../$< 2>&1 | tee ../../$@.test.out) + $(V)#$(CNTEST) $< 2>&1 | tee $@.test.out + $(V)# Next line should go away! + $(V)(cd src/exercises; rm -f cn.c cn.h run_tests.sh *-exec.c *_test.c) + $(V)-grep PASSED $@.test.out || true + $(V)-grep FAILED $@.test.out || true + $(V)if grep -q "fatal error" $@.test.out; then \ + exit 1; \ + fi + $(V)touch $@ + +_temp/verified/% : src/exercises/% + $(V)@echo Verify $@ + $(V)echo Verifying $< + $(V)@-mkdir -p $(dir $@) + $(V)$(CN) $< 2>&1 | tee $@.verif.out docs/exercises/%: src/exercises/% - @echo Rebuild $@ - @-mkdir -p $(dir $@) - @sed -E '\|^.*--BEGIN--.*$$|,\|^.*--END--.*$$|d' $< > $@ + $(V)echo Rebuild $@ + $(V)-mkdir -p $(dir $@) + $(V)sed -E '\|^.*--BEGIN--.*$$|,\|^.*--END--.*$$|d' $< > $@ docs/solutions/%: src/exercises/% - @-mkdir -p $(dir $@) - @-mkdir -p _tests - @if [ `which cn` ]; then \ - if [[ "$<" = *".c"* ]]; then \ - if [[ "$<" != *"broken"* && "$<" != *"partial"* && "$<" != *".DS_Store"* ]]; then \ - if [[ "$<" = *".test."*c ]]; then \ - echo $(CNTEST) $< && $(CNTEST) test $< --output _tests; \ - else \ - echo $(CN) $< && $(CN) $<; \ - fi; \ - fi; \ - fi \ - fi - @echo Rebuild $@ - @cat $< | sed '\|^.*--BEGIN--.*$$|d' | sed '\|^.*--END--.*$$|d' > $@ + $(V)echo Rebuild $@ + $(V)-mkdir -p $(dir $@) + $(V)cat $< | sed '\|^.*--BEGIN--.*$$|d' | sed '\|^.*--END--.*$$|d' > $@ docs/exercises.zip: $(EXERCISES) cd docs; zip -r exercises.zip exercises > /dev/null @@ -58,6 +76,24 @@ temp: $(WORKING_AUX) docs-exercises-dirs # cn test --output-dir=$(HOME)/tmp --replicas read.broken.c +# OLD +# docs/solutions/%: src/exercises/% +# @-mkdir -p $(dir $@) +# @-mkdir -p _tests +# @if [ `which cn` ]; then \ +# if [[ "$<" = *".c"* ]]; then \ +# if [[ "$<" != *"broken"* && "$<" != *"partial"* && "$<" != *".DS_Store"* ]]; then \ +# if [[ "$<" = *".test."*c ]]; then \ +# echo $(CNTEST) $< && $(CNTEST) $< --output _tests; \ +# else \ +# echo $(CN) $< && $(CN) $<; \ +# fi; \ +# fi; \ +# fi \ +# fi +# @echo Rebuild $@ +# @cat $< | sed '\|^.*--BEGIN--.*$$|d' | sed '\|^.*--END--.*$$|d' > $@ + ############################################################################## # Check that the examples all run correctly From c06b6d60ac2089a0629b6653b26bb7068cab2b71 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Sat, 8 Mar 2025 21:01:24 -0500 Subject: [PATCH 043/158] Testing Makefile seems to be working --- Makefile | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 8fc3a848..e892c1cb 100644 --- a/Makefile +++ b/Makefile @@ -5,12 +5,15 @@ MAKEFILE_DIR:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) default: tutorial all: default -clean: +clean: tidy rm -rf docs/exercises docs/solutions docs/exercises.zip \ build TAGS _temp # find . -type f -regex 'cn.*' -delete # find . -type f -regex '*-exec.*' -delete +tidy: + (cd src/exercises; rm -rf cn.c cn.h *-exec.* *_gen.* *_test.* tests.out cn.o constructors.h) + ############################################################################## # Exercises @@ -19,7 +22,16 @@ EXCLUDE = cn.c cn.h run_tests.sh *-exec.c *_test.c H = $(shell find src/exercises -type f -name *.h) C = $(shell find src/exercises -type f -name *.c) ALL = $(H) $(C) -NOTBROKEN = $(filter-out %broken%, $(C)) +BROKEN = $(shell find src/exercises -type f -name *broken*) +NOTBROKEN = $(filter-out $(BROKEN), $(C)) + +test: + @echo $(NOTBROKEN) + +test1: + @echo $(filter-out foo food, baz food foo bar) + + SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(ALL)) EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(ALL)) @@ -29,10 +41,10 @@ TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(NOTBROKEN)) exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) CN=cn verify -# make sure to add --output _temp again +# make sure to add --output _temp again once CN testing is cleaned up CNTEST=cn test --replicas --trace-granularity=none # CNTEST=cn test --replicas --output _temp --trace-granularity=none -# The --trace-granularity=none part can be deleted soon +# (The --trace-granularity=none part can be deleted soon too) V=@ @@ -43,10 +55,11 @@ _temp/tested/% : src/exercises/% $(V)(cd src/exercises; $(CNTEST) ../../$< 2>&1 | tee ../../$@.test.out) $(V)#$(CNTEST) $< 2>&1 | tee $@.test.out $(V)# Next line should go away! - $(V)(cd src/exercises; rm -f cn.c cn.h run_tests.sh *-exec.c *_test.c) + $(V)(cd src/exercises; rm -f cn.c cn.h run_tests.sh *-exec.c *_test.c) 2>&1 | tee $@.test.out $(V)-grep PASSED $@.test.out || true $(V)-grep FAILED $@.test.out || true - $(V)if grep -q "fatal error" $@.test.out; then \ + $(V)#Reinstate this check! + $(V)#if grep -q "fatal error" $@.test.out; then \ exit 1; \ fi $(V)touch $@ From d9540cd8a7ea8b67adad3b5671f1f545710953f4 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 10 Mar 2025 02:52:20 -0400 Subject: [PATCH 044/158] Update Makefile w.r.t new testing defaults --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e892c1cb..0e3c797f 100644 --- a/Makefile +++ b/Makefile @@ -42,9 +42,8 @@ exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) CN=cn verify # make sure to add --output _temp again once CN testing is cleaned up -CNTEST=cn test --replicas --trace-granularity=none -# CNTEST=cn test --replicas --output _temp --trace-granularity=none -# (The --trace-granularity=none part can be deleted soon too) +CNTEST=cn test +# CNTEST=cn test --output _temp V=@ @@ -87,7 +86,7 @@ WORKING=$(wildcard src/exercises/list_*.c) WORKING_AUX=$(patsubst src/exercises/%, docs/solutions/%, $(WORKING)) temp: $(WORKING_AUX) docs-exercises-dirs -# cn test --output-dir=$(HOME)/tmp --replicas read.broken.c +# cn test --output-dir=$(HOME)/tmp read.broken.c # OLD # docs/solutions/%: src/exercises/% From 9bffadcbe7dea76747028ebef8f5d8b461d05edf Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 11:06:03 -0400 Subject: [PATCH 045/158] Checkpoint tutorial makefile hacking --- Makefile | 10 ++++------ docs/getting-started/tutorials/todo.md | 4 ++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index e892c1cb..187bd45c 100644 --- a/Makefile +++ b/Makefile @@ -42,9 +42,8 @@ exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) CN=cn verify # make sure to add --output _temp again once CN testing is cleaned up -CNTEST=cn test --replicas --trace-granularity=none -# CNTEST=cn test --replicas --output _temp --trace-granularity=none -# (The --trace-granularity=none part can be deleted soon too) +CNTEST=cn test +# CNTEST=cn test --output _temp V=@ @@ -55,11 +54,10 @@ _temp/tested/% : src/exercises/% $(V)(cd src/exercises; $(CNTEST) ../../$< 2>&1 | tee ../../$@.test.out) $(V)#$(CNTEST) $< 2>&1 | tee $@.test.out $(V)# Next line should go away! - $(V)(cd src/exercises; rm -f cn.c cn.h run_tests.sh *-exec.c *_test.c) 2>&1 | tee $@.test.out + $(V)(cd src/exercises; rm -f cn.c cn.h run_tests.sh *-exec.c *_test.c) $(V)-grep PASSED $@.test.out || true $(V)-grep FAILED $@.test.out || true - $(V)#Reinstate this check! - $(V)#if grep -q "fatal error" $@.test.out; then \ + $(V)if grep -q "fatal error" $@.test.out; then \ exit 1; \ fi $(V)touch $@ diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 352db192..f39a79a5 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -1,5 +1,9 @@ # Things to do +## General notes + +- good pedagogical practice: "given a spec, show both examples and counterexamples" + ## Case studies Case studies drawn from the SUT(s), focused on specs From 8a4beab8f7f1df9c743eb36a5b4079389087e7f3 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 12:17:27 -0400 Subject: [PATCH 046/158] Tutorial compiles again, with some files not tested to avoid CN #include issues --- Makefile | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 42ebc39a..c1a5b446 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,6 @@ TESTED = \ _temp/tested/abs_mem_struct.c \ _temp/tested/bcp_framerule.c \ _temp/tested/slf_quadruple_mem.c \ - _temp/tested/_temp/funcs2-exec.c \ - _temp/tested/_temp/const_example-exec.c \ _temp/tested/const_example_lessgood.c \ _temp/tested/transpose2.c \ _temp/tested/slf2_basic_quadruple.signed.c \ @@ -78,11 +76,13 @@ TESTED = \ _temp/tested/slf0_basic_incr.signed.c \ _temp/tested/slf15_basic_succ_using_incr_attempt_.c +temp: + @echo $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) + exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) CN=cn verify -CNTEST=cn test --output ../../_temp -# CNTEST=cn test --output _temp +CNTEST=cn test --output _temp # Control verbosity (run make with V= to show everything that's happening) V=@ @@ -90,14 +90,12 @@ V=@ _temp/tested/% : src/exercises/% $(V)echo Testing $< $(V)-mkdir -p $(dir $@) - $(V)(cd src/exercises; $(CNTEST) ../../$< 2>&1 | tee ../../$@.test.out) + $(V)$(CNTEST) $< 2>&1 | tee $@.test.out $(V)-grep PASSED $@.test.out || true $(V)-grep FAILED $@.test.out || true - @# This should not be needed! + @# Next line should not be needed! $(V)if grep -q "fatal error\\|Failed to compile" $@.test.out; then \ exit 1; \ - else \ - echo NO FAIL $@; \ fi $(V)touch $@ @@ -122,7 +120,6 @@ docs/exercises.zip: $(EXERCISES) WORKING=$(wildcard src/exercises/list_*.c) WORKING_AUX=$(patsubst src/exercises/%, docs/solutions/%, $(WORKING)) -temp: $(WORKING_AUX) docs-exercises-dirs # cn test --output-dir=$(HOME)/tmp read.broken.c From e669802eccbeac40e5f0d77f56b08a641d2f6987 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 12:22:53 -0400 Subject: [PATCH 047/158] Makefile nits --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2958500e..fe901c51 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ docs/solutions /_opam/ /_tests/ /docs/exercises.zip +/_temp/ +*.tmp From 6a1ba8af5abce95b48b8ce40064cb90b08f7ee20 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 13:16:13 -0400 Subject: [PATCH 048/158] Polishing on early bits of the tutorial --- Makefile | 12 +-- .../tutorials/basics-with-verification.md | 35 ++++++++ docs/getting-started/tutorials/first-taste.md | 88 +++++++++++-------- .../tutorials/preconditions.md | 2 +- docs/getting-started/tutorials/todo.md | 7 +- docs/getting-started/tutorials/welcome.md | 15 ++-- .../{min3.test.broken.c => min3.broken.c} | 0 .../{min3.test.partial.c => min3.partia1l.c} | 2 +- src/exercises/min3/min3.partial.c | 2 +- 9 files changed, 110 insertions(+), 53 deletions(-) rename src/exercises/min3/{min3.test.broken.c => min3.broken.c} (100%) rename src/exercises/min3/{min3.test.partial.c => min3.partia1l.c} (94%) diff --git a/Makefile b/Makefile index c1a5b446..cbdf0f7b 100644 --- a/Makefile +++ b/Makefile @@ -61,8 +61,8 @@ TESTED = \ _temp/tested/add.partial.c \ _temp/tested/init_point.c \ _temp/tested/min3/min3.fixed.c \ - _temp/tested/min3/min3.test.partial.c \ _temp/tested/min3/min3.partial.c \ + _temp/tested/min3/min3.partial1.c \ _temp/tested/slf_incr2.c \ _temp/tested/id_by_div.fixed.c \ _temp/tested/slf2_basic_quadruple.c \ @@ -100,10 +100,10 @@ _temp/tested/% : src/exercises/% $(V)touch $@ _temp/verified/% : src/exercises/% - $(V)@echo Verify $@ $(V)echo Verifying $< - $(V)@-mkdir -p $(dir $@) + $(V)-mkdir -p $(dir $@) $(V)$(CN) $< 2>&1 | tee $@.verif.out + $(V)touch $@ docs/exercises/%: src/exercises/% $(V)echo Rebuild $@ @@ -159,10 +159,12 @@ check: check-tutorial check-archive ############################################################################## # Tutorial document -tutorial: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) +# BCP: This runs mkdocs every time we run make, which is a little +# noisy -- would be nicer to run it only when other things change +tutorial: docs/exercises.zip mkdocs.yml $(shell find docs -type f) mkdocs build --strict -serve: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) +serve: docs/exercises.zip mkdocs.yml $(shell find docs -type f) mkdocs serve ############################################################################## diff --git a/docs/getting-started/tutorials/basics-with-verification.md b/docs/getting-started/tutorials/basics-with-verification.md index 49cebaca..0749f1d7 100644 --- a/docs/getting-started/tutorials/basics-with-verification.md +++ b/docs/getting-started/tutorials/basics-with-verification.md @@ -1,2 +1,37 @@ # CN Basics (with Verification) +## Verifying `min3` + +Property-based testing is great for increasing our confidence that +the function satisfies its specification, but we might also want +to _verify_ this formally. Run `cn verify ` on the buggy +version to produce this output: + +``` +[1/1]: min3 -- fail +min3.c:11:9: error: Unprovable constraint + return x; + ^~~~~~~~~ +Constraint from min3.c:2:13: +/*@ ensures return <= x + ^~~~~~~~~~~ +State file: file:///var/folders/_5/81fbkyvn3n5dsm34qw2zpr7w0000gn/T/state__min3.c__min3.html +``` + +And on the fixed version to produce this output: +``` +[1/1]: min3 -- pass +``` + +Whereas `cn test` treats the function body as a black box, `cn +verify` analyzes it directly, examining all possible paths through +the code until it either succeeds in constructing a formal proof +that the function satisfies the specification, or it encounters a +constraint that cannot be satisfied. + +## More stuff + + +Write me... + + diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index cff9a7c3..75ed39f7 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,4 +1,4 @@ -# A First Taste of CN +# Specifications Suppose we are writing a function `min3`, which takes three `int` arguments. @@ -8,9 +8,11 @@ exercises/min3/min3.partial.c --8<-- ``` -The desired behavior of `min3` is to return the smallest of the three inputs. That is, the return value should be less than or equal to `x` and to `y` and to `z`. More formally: +The desired behavior of `min3` is to return the smallest of the three +inputs. We expect, then, that the return value should be less +than or equal to `x` and to `y` and to `z`. More formally: -```c title="exercises/min3/min3.test.partial.c" +```c title="exercises/min3/min3.partial1.c" --8<-- exercises/min3/min3.test.partial.c --8<-- @@ -27,22 +29,31 @@ In more detail... - The keyword `return` refers to the return value. -- CN provides a variety of arithmetic and logical operators, which we use here to require that the return value is less than or equal to each of the three inputs. +- CN provides a variety of arithmetic and logical operators, which we + use here to state that the return value should be less than or equal + to each of the three inputs. - Each clause of the specification concludes with a semicolon. -Next, suppose we have implemented `min3` as shown below. +Next, suppose we have implemented `min3` (not quite correctly) as +shown below. -```c title="exercises/min3/min3.test.broken.c" +```c title="exercises/min3/min3.broken.c" --8<-- -exercises/min3/min3.test.broken.c +exercises/min3/min3.broken.c --8<-- ``` -How can we figure out if our implementation satisfies our specification? We can test it! Run the command `cn test ` to produce an output along these lines: +How can we figure out if our implementation satisfies our +specification? We can test it! Run the command `cn test ` to +produce an output along these lines: + + +BCP: Refresh this: + ``` -$ cn test min3.c +$ cn test min3.broken.c Compiled 'min3_test.c'. Compiled 'min3-exec.c'. @@ -66,19 +77,40 @@ Testing Summary: cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 ``` -Hmm, it seems like there might be an issue with our implementation. We'll return to that in a second, but first, let's explain what happened when we ran `cn test`. - -`cn test` does _property-based testing_. You may instead be accustomed to input-output testing, where the user manually writes unit tests that assert what the output of a function should be on a given input. With property-based testing, things are much more automatic. Test inputs are _randomly generated_, and then assessed against the specification (i.e., the "property"). - -Here, `cn test` generates three integer inputs, runs `min3` on these inputs, and checks that the output satisfies the postcondition. It repeats this process until either some number (by default, 100) of tests succeed, or a failing test, called a _counterexample_, is encountered. - -We can do X to see our counterexample inputs: +CN reports that there seems to be an issue with our +implementation. We'll return to that in a second, but first, let's +explain what happened when we ran `cn test`. + +The `cn test` command does _property-based random testing_. You may +instead be accustomed to input-output testing, where the developer +writes _unit tests_ that assert what the output of a function should +be on a given input. With property-based random testing, things are +much more automatic. First, instead of requiring the developer to +manually construct a suite of interesting test _inputs_, CN +automatically generates large number of random test inputs. Second, +instead of requiring the developer to manually calculate the expected +_output_ for each test input, CN uses the provided specification to +check whether the program's behavior is satisfactory. + +Here, `cn test` generates three integer inputs, runs `min3` on these +inputs, and checks that the output satisfies the postcondition. It +repeats this process until either some number (by default, 100) of +tests succeed or else a failing test, called a _counterexample_, is +encountered. + +We can do +(what do we need to do??) + +to see our counterexample inputs: ``` x = 13 y = 4 z = 9 ``` -(The counterexample you generated is most likely different, due to randomness, but the debugging logic will be the same.) + +(The counterexample you will see if you run the tests yourself will +most likely be different, due to randomness, but the debugging logic +will be the same.) Given these three inputs, we expect the function to enter this branch: @@ -88,7 +120,7 @@ Given these three inputs, we expect the function to enter this branch: } ``` -Oops! We made a mistake here. We should `return y`, not `x`, in this case. +Aha! Here is the mistake: we should `return y`, not `x`, in this case. Let's fix the bug: ```c title="exercises/min3/min3.fixed.c" @@ -131,23 +163,3 @@ exercises/add.partial.c --8<-- ``` -??? note "(Optional) Verifying `min3`" - Property-based testing is great for increasing our confidence that the function satisfies its specification, but we might also want to _verify_ this formally. Run `cn verify ` on the buggy version to produce this output: - - ``` - [1/1]: min3 -- fail - min3.c:11:9: error: Unprovable constraint - return x; - ^~~~~~~~~ - Constraint from min3.c:2:13: - /*@ ensures return <= x - ^~~~~~~~~~~ - State file: file:///var/folders/_5/81fbkyvn3n5dsm34qw2zpr7w0000gn/T/state__min3.c__min3.html - ``` - - And on the fixed version to produce this output: - ``` - [1/1]: min3 -- pass - ``` - - Whereas `cn test` treats the function body as a black box, `cn verify` analyzes it directly, examining all possible paths through the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. diff --git a/docs/getting-started/tutorials/preconditions.md b/docs/getting-started/tutorials/preconditions.md index 34332715..cf4a551f 100644 --- a/docs/getting-started/tutorials/preconditions.md +++ b/docs/getting-started/tutorials/preconditions.md @@ -1,4 +1,4 @@ -# Preconditions +# Specifications with Preconditions Next, let's walk through an example that will introduce a few more CN specification features. Here's a silly way of writing a function that diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index f39a79a5..7c0fe5ec 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -1,8 +1,13 @@ # Things to do +## Things to clean up at the end + +- Format exercises consistently throughout + ## General notes -- good pedagogical practice: "given a spec, show both examples and counterexamples" +- good pedagogical practice: "given a spec, show both examples and + counterexamples" ## Case studies diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index c0ac2c4a..5c61fe0f 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -1,5 +1,7 @@ # Welcome +## Introduction + CN is an integrated specification, testing, and verification framework for low-level software systems written in ISO C. @@ -7,12 +9,11 @@ This tutorial introduces CN through a series of examples and case studies, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. - + CN can be used in two distinct ways: - The simpler way is as a framework for writing down formal @@ -32,8 +33,10 @@ the document. Most readers -- even readers whose primary interest is verification -- should skip these sections on a first reading and, if desired, come back to them on a second pass. +## Setup + Before getting started, make sure you have a running installation of CN and a local copy of the source files for all the exercises and examples; these can be downloaded from [here](link:exercises.zip). -*Move that to the first section where we ask -them to do something.* + + diff --git a/src/exercises/min3/min3.test.broken.c b/src/exercises/min3/min3.broken.c similarity index 100% rename from src/exercises/min3/min3.test.broken.c rename to src/exercises/min3/min3.broken.c diff --git a/src/exercises/min3/min3.test.partial.c b/src/exercises/min3/min3.partia1l.c similarity index 94% rename from src/exercises/min3/min3.test.partial.c rename to src/exercises/min3/min3.partia1l.c index 3fa2d781..b800b4c0 100644 --- a/src/exercises/min3/min3.test.partial.c +++ b/src/exercises/min3/min3.partia1l.c @@ -4,5 +4,5 @@ unsigned int min3(unsigned int x, unsigned int y, unsigned int z) && return <= z; @*/ { - + // ... } diff --git a/src/exercises/min3/min3.partial.c b/src/exercises/min3/min3.partial.c index 561c77fd..15f9bcc9 100644 --- a/src/exercises/min3/min3.partial.c +++ b/src/exercises/min3/min3.partial.c @@ -1,4 +1,4 @@ unsigned int min3(unsigned int x, unsigned int y, unsigned int z) { - + // ... } From 340fcc11e89f8895de8c63a50cfb72eb9b68634a Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 14:18:09 -0400 Subject: [PATCH 049/158] More polishing --- Makefile | 2 +- docs/getting-started/tutorials/pointers.md | 17 +++++++------- .../tutorials/preconditions.md | 22 ++++++++----------- docs/getting-started/tutorials/todo.md | 18 ++++++++++++--- src/exercises/add.partial.c | 2 +- .../{ => id_by_div}/id_by_div.broken.c | 2 +- .../{ => id_by_div}/id_by_div.fixed.c | 0 .../{ => id_by_div}/id_by_div_n.broken.c | 0 8 files changed, 35 insertions(+), 28 deletions(-) rename src/exercises/{ => id_by_div}/id_by_div.broken.c (52%) rename src/exercises/{ => id_by_div}/id_by_div.fixed.c (100%) rename src/exercises/{ => id_by_div}/id_by_div_n.broken.c (100%) diff --git a/Makefile b/Makefile index cbdf0f7b..005f299e 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ TESTED = \ _temp/tested/min3/min3.partial.c \ _temp/tested/min3/min3.partial1.c \ _temp/tested/slf_incr2.c \ - _temp/tested/id_by_div.fixed.c \ + _temp/tested/id_by_div/id_by_div.fixed.c \ _temp/tested/slf2_basic_quadruple.c \ _temp/tested/slf18_two_dice.c \ _temp/tested/swap.c \ diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 6852d56a..cf60eefc 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -34,9 +34,8 @@ involved, because the safety of memory accesses via pointers has to be taken into account. CN uses _separation logic resources_ and the concept of _ownership_ to -reason about memory accesses. A resource is the permission to access a -region of memory. Unlike logical constraints, resource ownership is -_unique_, meaning resources cannot be duplicated. +reason about memory accesses. A _resource_, intuitively, represents +the permission to access a region of memory. Let’s look at a simple example. The function `read` takes an integer pointer `p` and returns the pointee value. @@ -49,9 +48,6 @@ exercises/read.c Running CN on this example produces the following error: - -BCP: This output needs updated. - ``` cn test read.c Compiled 'read_test.c'. @@ -74,14 +70,17 @@ represented by a _resource_ `Owned(p)`. BCP: Is that right?? Should it be just Owned(p)? Or just Owned(p)?? (I think just Owned(p) is OK, and we should use that -everywhere it's OK!) +everywhere it's OK! We'll need a bit of explanation when we reach the +first place where it is _not_ OK.) ## Owned resources Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts -_ownership_ of a memory cell at location `p` of the size of C-type -`T`. +_ownership_ of a memory region at location `p` of the size of the C type +`T`. If `T` is a single-word type, then `` can be omitted. + + In this example, we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as diff --git a/docs/getting-started/tutorials/preconditions.md b/docs/getting-started/tutorials/preconditions.md index cf4a551f..fadbadca 100644 --- a/docs/getting-started/tutorials/preconditions.md +++ b/docs/getting-started/tutorials/preconditions.md @@ -1,19 +1,15 @@ # Specifications with Preconditions -Next, let's walk through an example that will introduce a few more CN -specification features. Here's a silly way of writing a function that +Here's a silly way of writing a function that returns whatever number it is given as input: -```c title="exercises/id_by_div.broken.c" +```c title="exercises/id_by_div/id_by_div.broken.c" --8<-- -exercises/id_by_div.broken.c +exercises/id_by_div/id_by_div.broken.c --8<-- ``` If we try to `cn test` this function, however, we will get a counterexample such as this one: - -BCP: update this! - ``` x = 7 ``` @@ -22,27 +18,27 @@ Oh! Because integer division is truncating, our silly function will only work as desired when the input `x` is even. We can add this requirement as a _precondition_, using the `requires` keyword. -```c title="exercises/id_by_div.fixed.c" +```c title="exercises/id_by_div/id_by_div.fixed.c" --8<-- -exercises/id_by_div.fixed.c +exercises/id_by_div/id_by_div.fixed.c --8<-- ``` -A specification with preconditions and postconditions asserts that, if +A specification with both preconditions and postconditions says that, if the preconditions hold at the point where the function is called, then the postconditions will hold when the function returns. The other new piece of syntax here is the `u32` type annotations. In CN specifications, numeric types need to be annotated explicitly, and we use `u32` for `unsigned int`. Try removing the annotations to see -the error message. +the error message that results. _Exercise._ Without changing the postcondition or implementation, fix the specification in the following example by adding a precondition on the inputs `x` and `n`. Check that `cn test` succeeds. -```c title="exercises/id_by_div_n.broken.c" +```c title="exercises/id_by_div/id_by_div_n.broken.c" --8<-- -exercises/id_by_div_n.broken.c +exercises/id_by_div/id_by_div_n.broken.c --8<-- ``` diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 7c0fe5ec..120f942d 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -1,8 +1,20 @@ # Things to do -## Things to clean up at the end - -- Format exercises consistently throughout +## Things to clean up later (but before releasing to newbies!) + +- Make a pass through the whole document and refresh all the displayed + outputs from the system +- Format exercises consistently throughout +- Rename exercise files sensibly / consistently and organize them into + subdirectories +- Fix the top-level README.md with correct names for chapters +- Figure out how to separate specification stuff from verification + stuff + - e.g., make a whole separate TOC for the verification flow, with + extra chapters as appropriate + - (but even if we do this, we need to name the verification + chapters so that people can distinguish them from specification + chapters) ## General notes diff --git a/src/exercises/add.partial.c b/src/exercises/add.partial.c index 78e1e35c..4e46c9df 100644 --- a/src/exercises/add.partial.c +++ b/src/exercises/add.partial.c @@ -1,4 +1,4 @@ unsigned int add(unsigned int x, unsigned int y) { - + // ... } diff --git a/src/exercises/id_by_div.broken.c b/src/exercises/id_by_div/id_by_div.broken.c similarity index 52% rename from src/exercises/id_by_div.broken.c rename to src/exercises/id_by_div/id_by_div.broken.c index a7e5f759..1330ebc1 100644 --- a/src/exercises/id_by_div.broken.c +++ b/src/exercises/id_by_div/id_by_div.broken.c @@ -1,4 +1,4 @@ -unsigned int id_by_div(unsigned int x) +unsigned int id_by_div/id_by_div(unsigned int x) /*@ ensures return == x; @*/ { return (x / 2) * 2; diff --git a/src/exercises/id_by_div.fixed.c b/src/exercises/id_by_div/id_by_div.fixed.c similarity index 100% rename from src/exercises/id_by_div.fixed.c rename to src/exercises/id_by_div/id_by_div.fixed.c diff --git a/src/exercises/id_by_div_n.broken.c b/src/exercises/id_by_div/id_by_div_n.broken.c similarity index 100% rename from src/exercises/id_by_div_n.broken.c rename to src/exercises/id_by_div/id_by_div_n.broken.c From ec19e2a3b94ce408ed591d32dc9dc2831479af33 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 14:54:31 -0400 Subject: [PATCH 050/158] Use `unsigned int` consistently (instead of `unsigned`) --- Makefile | 11 ++---- docs/getting-started/tutorials/arrays.md | 38 +++++++++---------- docs/getting-started/tutorials/compound.md | 12 +++--- docs/getting-started/tutorials/pointers.md | 35 ++++++++--------- src/exercises/array_load.broken.c | 6 +-- src/exercises/id_by_div_n.broken.c | 5 +++ src/exercises/init_point.c | 8 ++-- .../min3/{min3.partia1l.c => min3.partial1.c} | 0 src/exercises/read.broken.c | 4 +- src/exercises/read.c | 6 +-- src/exercises/read2.c | 6 +-- src/exercises/transpose.broken.c | 6 +-- src/exercises/transpose.c | 6 +-- src/exercises/zero.c | 6 +-- src/old/tutorial.md | 6 ++- 15 files changed, 78 insertions(+), 77 deletions(-) create mode 100644 src/exercises/id_by_div_n.broken.c rename src/exercises/min3/{min3.partia1l.c => min3.partial1.c} (100%) diff --git a/Makefile b/Makefile index 005f299e..827ea666 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,8 @@ all: default clean: tidy rm -rf docs/exercises docs/solutions docs/exercises.zip \ - build TAGS _temp -# find . -type f -regex 'cn.*' -delete -# find . -type f -regex '*-exec.*' -delete + build TAGS _temp _tests + find . -type f -regex '*.tmp' -delete tidy: (cd src/exercises; rm -rf cn.c cn.h *-exec.* *_gen.* *_test.* tests.out cn.o constructors.h) @@ -17,8 +16,6 @@ tidy: ############################################################################## # Exercises -EXCLUDE = cn.c cn.h run_tests.sh *-exec.c *_test.c - H = $(shell find src/exercises -type f -name *.h) C = $(shell find src/exercises -type f -name *.c) ALL = $(H) $(C) @@ -161,10 +158,10 @@ check: check-tutorial check-archive # BCP: This runs mkdocs every time we run make, which is a little # noisy -- would be nicer to run it only when other things change -tutorial: docs/exercises.zip mkdocs.yml $(shell find docs -type f) +tutorial: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) mkdocs build --strict -serve: docs/exercises.zip mkdocs.yml $(shell find docs -type f) +serve: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) mkdocs serve ############################################################################## diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index aa15eeca..0a683eb9 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -6,7 +6,7 @@ To support reasoning about code manipulating arrays and computed pointers, CN ha ```c each (i32 i; 0i32 <= i && i < 10i32) -{ Owned(array_shift(p,i)) } +{ Owned(array_shift(p,i)) } ``` In detail, this can be read as follows: @@ -15,11 +15,11 @@ In detail, this can be read as follows: - if `i` is between `0` and `10`, … -- assert ownership of a resource `Owned` … +- assert ownership of a resource `Owned` … - for cell `i` of the array with base-address `p`. -Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. +Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. In general, iterated resource specifications take the form @@ -37,7 +37,7 @@ comprising three parts: ### First array example -Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. +Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. ```c title="exercises/array_load.broken.c" --8<-- @@ -47,7 +47,7 @@ exercises/array_load.broken.c The CN precondition requires -- ownership of the array on entry — one `Owned` resource for each array index between `0` and `n` — and +- ownership of the array on entry — one `Owned` resource for each array index between `0` and `n` — and - that `i` lies within the range of owned indices. On exit the array ownership is returned again. @@ -85,10 +85,10 @@ exercises/array_load.c --8<-- ``` -Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: +Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: ```c -each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } +each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } ``` is split into @@ -96,14 +96,14 @@ is split into 1. the instantiation of the iterated resource at `i` ```c -Owned(array_shift(p,i)) +Owned(array_shift(p,i)) ``` 2. the remainder of the iterated resource, the ownership for all indices except `i` ```c each(i32 j; 0i32 <= j && j < n && j != i) - { Owned(array_shift(p,j)) } + { Owned(array_shift(p,j)) } ``` After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. @@ -116,7 +116,7 @@ the iterated resources in the function specification. When we specify `take A = each ...` here, what is `A`? In CN, the output of an iterated resource is a _map_ from indices to resource outputs. In this example, where index `j` has CN type `i32` and the iterated -resource is `Owned`, the output `A` is a map from `i32` +resource is `Owned`, the output `A` is a map from `i32` indices to `i32` values — CN type `map`. If the type of `j` was `i64` and the resource `Owned`, `A` would have type `map`. @@ -157,7 +157,7 @@ BCP: In this one I got quite tangled up in different kinds of integers, then got Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints -_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. +_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. ```c title="exercises/swap_array.c" --8<-- @@ -169,20 +169,20 @@ exercises/swap_array.c TODO: BCP: I wrote this, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfecdt understanding of how the numeric stuff works. - void swap_array (unsigned *p, unsigned n, unsigned i, unsigned j) - /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + void swap_array (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) + /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; 0i32 <= i && i < n; 0i32 <= j && j < n; j != i; - take xi = Owned(array_shift(p,i)); - take xj = Owned(array_shift(p,j)) - ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + take xi = Owned(array_shift(p,i)); + take xj = Owned(array_shift(p,j)) + ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; a1[i:xj][j:xi] == a2 @*/ { - extract Owned, i; - extract Owned, j; - unsigned tmp = p[i]; + extract Owned, i; + extract Owned, j; + unsigned int tmp = p[i]; p[i] = p[j]; p[j] = tmp; } diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index fae2f6dc..28530032 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -62,7 +62,7 @@ BCP: Is this relevant to testing? To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. -Recall the function `zero` from our earlier exercise. It takes an `unsigned` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. +Recall the function `zero` from our earlier exercise. It takes an `unsigned int` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. Now consider the function `init_point`, shown below, which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. @@ -72,9 +72,9 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `Block(p)`. The `zero` function, however, works on `unsigned` pointers and requires `Block` ownership. +As stated in its precondition, `init_point` receives ownership `Block(p)`. The `zero` function, however, works on `unsigned int` pointers and requires `Block` ownership. -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. +CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. ### Resource inference @@ -94,9 +94,9 @@ exercises/transpose.broken.c The precondition of `transpose` asserts ownership of an `Owned(p)` resource. The error report now instead lists under "`Available resources`" two resources: -- `Owned(member_shift(p, x))` with output `P.x` and +- `Owned(member_shift(p, x))` with output `P.x` and -- `Owned(member_shift(p, y))` with output `P.y` +- `Owned(member_shift(p, y))` with output `P.y` BCP: We should verify that it really does say this. @@ -114,7 +114,7 @@ BCP: That's just for verification. -_Transpose (again)._ Recreate the transpose function from before, now using the swap function verified earlier (for `struct upoint`, with unsigned member values). +_Transpose (again)._ Recreate the transpose function from before, now using the swap function verified earlier (for `struct upoint`, with unsigned int member values). BCP: No need for upoint now... diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index cf60eefc..35092d95 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -66,7 +66,7 @@ cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. This permission is -represented by a _resource_ `Owned(p)`. +represented by a _resource_ `Owned(p)`. BCP: Is that right?? Should it be just Owned(p)? Or just Owned(p)?? (I think just Owned(p) is OK, and we should use that @@ -83,11 +83,11 @@ _ownership_ of a memory region at location `p` of the size of the C type In this example, we can ensure the safe execution of `read` by adding -a precondition that requires ownership of `Owned(p)`, as +a precondition that requires ownership of `Owned(p)`, as shown below. (For now ignore the `take ... =` part.) Since reading the pointer does not disturb its value, we can also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of -another `Owned(p)` resource. +another `Owned(p)` resource. ```c title="solutions/read.c" --8<-- @@ -98,9 +98,9 @@ solutions/read.c This specification can be read as follows: - any function calling `read` has to be able to provide a resource - `Owned(p)` to pass into `read`, and + `Owned(p)` to pass into `read`, and -- the caller will receive back a resource `Owned(p)` when +- the caller will receive back a resource `Owned(p)` when `read` returns. @@ -143,8 +143,8 @@ Dhruv: Perhaps mentioning sub-heaps will help? CN uses the `take` notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = -Owned(p)` does two things: (1) it assert ownership of resource -`Owned(p)`, and (2) it binds the name `P` to the resource output, +Owned(p)` does two things: (1) it assert ownership of resource +`Owned(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. @@ -222,7 +222,7 @@ BCP: Explain what that means. Update if the output format changes. CN has typechecked the function and verified (1) that it is safe to -execute under the precondition (given ownership `Owned(p)`) +execute under the precondition (given ownership `Owned(p)`) and (2) that the function (vacuously) satisfies its postcondition. But following the check of the postcondition it finds that not all resources have been "used up". @@ -242,7 +242,7 @@ resources back to the caller. _Quadruple_. Specify the function `quadruple_mem`, which is similar to the earlier `quadruple` function, except that the input is passed as a -pointer to an `unsigned`. Write a specification that takes ownership +pointer to an `unsigned int`. Write a specification that takes ownership of this pointer on entry and returns this ownership on exit, leaving the pointee value unchanged. @@ -301,7 +301,7 @@ Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful out ## Writing through pointers -Let’s explore resources and their outputs in another example. The C function `incr` takes an `unsigned` pointer `p` and increments the value in the memory cell that it poinbts to. +Let’s explore resources and their outputs in another example. The C function `incr` takes an `unsigned int` pointer `p` and increments the value in the memory cell that it poinbts to. BCP: unsigned! (there are both signed and unsigned versions at the @@ -313,7 +313,7 @@ exercises/slf0_basic_incr.signed.c --8<-- ``` -In the precondition we assert ownership of resource `Owned(p)`, +In the precondition we assert ownership of resource `Owned(p)`, binding its output/pointee value to `P`, and use `P` to specify that `p` must point to a sufficiently small value at the start of the function so as not to overflow when incremented. The postcondition @@ -321,7 +321,7 @@ asserts ownership of `p` with output `P_post`, as before, and uses this to express that the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. -If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. +If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. BCP: change it to unsigned... @@ -357,7 +357,7 @@ exercises/zero.c --8<-- ``` -_In-place double._ Give a specification for the function `inplace_double`, which takes an `unsigned` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. +_In-place double._ Give a specification for the function `inplace_double`, which takes an `unsigned int` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. ```c title="exercises/slf3_basic_inplace_double.c" --8<-- @@ -375,7 +375,7 @@ pointers refer to _disjoint_ regions of memory. The following example shows the use of two `Owned` resources for accessing two different pointers by a function `add`, which reads -two `unsigned` values in memory, at locations `p` and `q`, and +two `unsigned int` values in memory, at locations `p` and `q`, and returns their sum. @@ -386,11 +386,6 @@ pointed to by p obviously cannot also be called p, so it doesn't make sense for it to be called P at the CN level, right? - -BCP: Is there a difference between `unsigned int` and `unsigned`? Not -sure which I should be using. - - ```c title="exercises/add_read.c" --8<-- exercises/add_read.c @@ -400,7 +395,7 @@ exercises/add_read.c BCP: Does this belong here? Could it go in the later section on numeric types? -The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned` type. Like C’s unsigned integer arithmetic, CN unsigned values wrap around when exceeding the value range of the type. +The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. ## Exercises diff --git a/src/exercises/array_load.broken.c b/src/exercises/array_load.broken.c index 4909ee38..866c701b 100644 --- a/src/exercises/array_load.broken.c +++ b/src/exercises/array_load.broken.c @@ -1,9 +1,9 @@ -int read (unsigned *p, unsigned n, unsigned i) +int read (unsigned int *p, unsigned int n, unsigned int i) /*@ requires take A = each(u32 j; 0u32 <= j && j < n) { - Owned(array_shift(p,j)) }; + Owned(array_shift(p,j)) }; 0u32 <= i && i < n; ensures take A_post = each(u32 j; 0u32 <= j && j < n) { - Owned(array_shift(p,j)) }; + Owned(array_shift(p,j)) }; @*/ { return p[i]; diff --git a/src/exercises/id_by_div_n.broken.c b/src/exercises/id_by_div_n.broken.c new file mode 100644 index 00000000..bfe6bbe8 --- /dev/null +++ b/src/exercises/id_by_div_n.broken.c @@ -0,0 +1,5 @@ +unsigned int id_by_div_n(unsigned int x, unsigned int n) +/*@ ensures return == x; @*/ +{ + return (x / n) * n; +} diff --git a/src/exercises/init_point.c b/src/exercises/init_point.c index 64ae0b7b..b43f2618 100644 --- a/src/exercises/init_point.c +++ b/src/exercises/init_point.c @@ -1,12 +1,12 @@ -void zero (unsigned *coord) -/*@ requires take Coord = Block(coord); - ensures take Coord_post = Owned(coord); +void zero (unsigned int *coord) +/*@ requires take Coord = Block(coord); + ensures take Coord_post = Owned(coord); Coord_post == 0u32; @*/ { *coord = 0; } -struct point { unsigned x; unsigned y; }; +struct point { unsigned int x; unsigned int y; }; void init_point(struct point *p) /*@ requires take P = Block(p); diff --git a/src/exercises/min3/min3.partia1l.c b/src/exercises/min3/min3.partial1.c similarity index 100% rename from src/exercises/min3/min3.partia1l.c rename to src/exercises/min3/min3.partial1.c diff --git a/src/exercises/read.broken.c b/src/exercises/read.broken.c index 3da42b9e..d08ee184 100644 --- a/src/exercises/read.broken.c +++ b/src/exercises/read.broken.c @@ -1,5 +1,5 @@ -unsigned read (unsigned *p) -/*@ requires take v1 = Owned(p); @*/ +unsigned int read (unsigned int *p) +/*@ requires take v1 = Owned(p); @*/ { return *p; } diff --git a/src/exercises/read.c b/src/exercises/read.c index 40caf7a7..6441a695 100644 --- a/src/exercises/read.c +++ b/src/exercises/read.c @@ -1,7 +1,7 @@ -unsigned read (unsigned *p) +unsigned int read (unsigned int *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = Owned(p); + ensures take P_post = Owned(p); @*/ /* --END-- */ { diff --git a/src/exercises/read2.c b/src/exercises/read2.c index a39dbdf7..4f8b4502 100644 --- a/src/exercises/read2.c +++ b/src/exercises/read2.c @@ -1,6 +1,6 @@ -unsigned read (unsigned *p) -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +unsigned int read (unsigned int *p) +/*@ requires take P = Owned(p); + ensures take P_post = Owned(p); return == P; P_post == P; @*/ diff --git a/src/exercises/transpose.broken.c b/src/exercises/transpose.broken.c index 33cf20b4..8e4c9075 100644 --- a/src/exercises/transpose.broken.c +++ b/src/exercises/transpose.broken.c @@ -1,4 +1,4 @@ -struct point { unsigned x; unsigned y; }; +struct point { unsigned int x; unsigned int y; }; void transpose (struct point *p) /*@ requires take P = Owned(p); @@ -7,8 +7,8 @@ void transpose (struct point *p) P_post.y == P.x; @*/ { - unsigned temp_x = p->x; - unsigned temp_y = p->y; + unsigned int temp_x = p->x; + unsigned int temp_y = p->y; /*@ assert(false); @*/ p->x = temp_y; p->y = temp_x; diff --git a/src/exercises/transpose.c b/src/exercises/transpose.c index 36b85334..29581e34 100644 --- a/src/exercises/transpose.c +++ b/src/exercises/transpose.c @@ -1,4 +1,4 @@ -struct point { unsigned x; unsigned y; }; +struct point { unsigned int x; unsigned int y; }; void transpose (struct point *p) /*@ requires take P = Owned(p); @@ -7,8 +7,8 @@ void transpose (struct point *p) P_post.y == P.x; @*/ { - unsigned temp_x = p->x; - unsigned temp_y = p->y; + unsigned int temp_x = p->x; + unsigned int temp_y = p->y; p->x = temp_y; p->y = temp_x; } diff --git a/src/exercises/zero.c b/src/exercises/zero.c index 8454b9af..3c767e1c 100644 --- a/src/exercises/zero.c +++ b/src/exercises/zero.c @@ -1,7 +1,7 @@ -void zero (unsigned *p) +void zero (unsigned int *p) /* --BEGIN-- */ -/*@ requires take P = Block(p); - ensures take P_post = Owned(p); +/*@ requires take P = Block(p); + ensures take P_post = Owned(p); P_post == 0u32; @*/ /* --END-- */ diff --git a/src/old/tutorial.md b/src/old/tutorial.md index 6c62e1ea..fca86309 100644 --- a/src/old/tutorial.md +++ b/src/old/tutorial.md @@ -593,7 +593,9 @@ exercises/add_read.c --8<-- ``` -This time we use C’s `unsigned int` type. In C, over- and underflow of unsigned integers is not undefined behaviour, so we do not need any special preconditions to rule this out. Instead, when an arithmetic operation at unsigned type goes outside the representable range, the value "`wraps around`". +OUTDATED: + +This time we use C’s `unsigned int` type. In C, over- and underflow of unsigned integers is not undefined behaviour, so we do not need any special preconditions to rule this out. Instead, when an arithmetic operation at `unsigned int` type goes outside the representable range, the value "`wraps around`". The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. @@ -709,6 +711,8 @@ _Init point._ Insert CN `assert(false)` statements in different statement positi _Transpose (again)._ Recreate the transpose function from before, now using the swap function verified earlier (for `struct upoint`, with unsigned member values). +BCP: FIX!! + ```c title="exercises/transpose2.c" --8<-- exercises/transpose2.c From 29696556c9579e238e02d52aa6c1a2bdffd58931 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 10 Mar 2025 16:00:15 -0400 Subject: [PATCH 051/158] More work all over tutorial --- Makefile | 6 +- docs/getting-started/tutorials/README.md | 7 +- docs/getting-started/tutorials/arrays.md | 257 +---------------- docs/getting-started/tutorials/compound.md | 78 +----- docs/getting-started/tutorials/pointers.md | 57 +++- docs/getting-started/tutorials/todo.md | 3 + .../getting-started/tutorials/verif-arrays.md | 258 ++++++++++++++++++ ...ray_load.broken.c => array_load.noverif.c} | 4 +- src/exercises/transpose2.c | 8 +- 9 files changed, 335 insertions(+), 343 deletions(-) create mode 100644 docs/getting-started/tutorials/verif-arrays.md rename src/exercises/{array_load.broken.c => array_load.noverif.c} (72%) diff --git a/Makefile b/Makefile index 827ea666..9f47e6eb 100644 --- a/Makefile +++ b/Makefile @@ -22,9 +22,13 @@ ALL = $(H) $(C) BROKEN = $(shell find src/exercises -type f -name *broken*) NOTBROKEN = $(filter-out $(BROKEN), $(C)) +NOVERIF = $(shell find src/exercises -type f -name *noverif*) \ + $(BROKEN) +VERIF = $(filter-out $(NOVERIF), $(C)) + SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(ALL)) EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(ALL)) -VERIFIED=$(patsubst src/exercises/%, _temp/verified/%, $(NOTBROKEN)) +VERIFIED=$(patsubst src/exercises/%, _temp/verified/%, $(VERIF)) #TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(NOTBROKEN)) # TEMPORARY: diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index ed682753..6118468b 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -7,8 +7,9 @@ - [Preconditions](preconditions.md) - [V: A first taste of verification](basics-with-verification.md) - [Working with pointers](pointers.md) -- [Ownership of structured objects](compound.md) +- [V: Verification with pointers to structured objects](compound.md) - [Arrays and Loops](arrays.md) +- [V: Verifying Programs with Arrays and Loops](verif-arrays.md) - [Dynamic storage allocation](dynamic.md) - [More on numeric types](numeric.md) @@ -18,20 +19,16 @@ - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) - [Airport Simulation](../case-studies/the-runway.md) - ## TODOs - [TODO list and discussion](todo.md) ## OLD STUFF -- [Ownership of compound objects](verification/ownership-of-compound-objects.md) -- [Arrays and loops](verification/arrays-and-loops.md) - [Defining predicates](verification/defining-predicates.md) - [Allocating and deallocating memory](verification/allocating-and-deallocating-memory.md) - [Lists](verification/lists.md) - [Working with external lemmas](verification/external-lemmas.md) - diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index 0a683eb9..f85aa9b0 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -31,6 +31,10 @@ comprising three parts: - `BT Q`, for some CN type `BT` and name `Q`, introduces the quantifier `Q` of basetype `BT`, which is bound in `GUARD` and `RESOURCE`; + BCP: What is a CN type? What is a basetype? + + + - `GUARD` is a boolean-typed expression delimiting the instances of `Q` for which ownership is asserted; and - `RESOURCE` is any non-iterated CN resource. @@ -39,7 +43,7 @@ comprising three parts: Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. -```c title="exercises/array_load.broken.c" +```c title="exercises/array_load.noverif.c" --8<-- exercises/array_load.broken.c --8<-- @@ -52,256 +56,7 @@ The CN precondition requires On exit the array ownership is returned again. - -BCP: Split the file here. In the testing variant, do several more + BCP: Do several more examples (e.g., maybe working up to sorting?). -This specification, in principle, should ensure that the access `p[i]` is safe. However, running CN on the example produces an error: CN is unable to find the required ownership for reading `p[i]`. - - -BCP: Update it - -``` -cn verify solutions/array_load.broken.c -[1/1]: read -build/solutions/array_load.broken.c:5:10: error: Missing resource for reading -return p[i]; -^~~~ -Resource needed: Owned(array_shift(p, (u64)i)) -``` - -The reason is that, when searching for a required resource, such as the `Owned` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. - - -BCP: This is more verification-relevant - - -To make the `Owned` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`extract`" ownership for index `i` out of the iterated resource. - -```c title="exercises/array_load.c" ---8<-- -exercises/array_load.c ---8<-- -``` - -Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: - -```c -each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } -``` - -is split into - -1. the instantiation of the iterated resource at `i` - -```c -Owned(array_shift(p,i)) -``` - -2. the remainder of the iterated resource, the ownership for all indices except `i` - -```c - each(i32 j; 0i32 <= j && j < n && j != i) - { Owned(array_shift(p,j)) } -``` - -After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. - -Following an `extract` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. - -So far the specification only guarantees safe execution but does not -specify the behaviour of `read`. To address this, let’s return to -the iterated resources in the function specification. When we specify -`take A = each ...` here, what is `A`? In CN, the output of an -iterated resource is a _map_ from indices to resource outputs. In this -example, where index `j` has CN type `i32` and the iterated -resource is `Owned`, the output `A` is a map from `i32` -indices to `i32` values — CN type `map`. If the type of -`j` was `i64` and the resource `Owned`, `A` would have -type `map`. - -We can use this to refine our specification with information about the functional behaviour of `read`. - -```c title="exercises/array_load2.c" ---8<-- -exercises/array_load2.c ---8<-- -``` - -We specify that `read` does not change the array — the outputs of `Owned`, -`A` and `A_post`, taken before and after running the function, are -the same — and that the value returned is `A[i]`. - -### Exercises - -_Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. - - -BCP: When we get around to renaming files in the examples directory, -we should call this one array_swap or something else beginning with -"array". Or put it in a subdirectory. - - -```c title="exercises/add_two_array.c" ---8<-- -exercises/add_two_array.c ---8<-- -``` - - -BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the extract declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) - - - -Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints - - -_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. - -```c title="exercises/swap_array.c" ---8<-- -exercises/swap_array.c ---8<-- -``` - - - -TODO: BCP: I wrote this, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfecdt understanding of how the numeric stuff works. - - void swap_array (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) - /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; - 0i32 <= i && i < n; - 0i32 <= j && j < n; - j != i; - take xi = Owned(array_shift(p,i)); - take xj = Owned(array_shift(p,j)) - ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; - a1[i:xj][j:xi] == a2 - @*/ - { - extract Owned, i; - extract Owned, j; - unsigned int tmp = p[i]; - p[i] = p[j]; - p[j] = tmp; - } - - - - -### Loops - -The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. - -In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all owned resources and the constraints required to verify each iteration of the loop. - -Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. - - -BCP: Rename to array_init.c - - -```c title="exercises/init_array.c" ---8<-- -exercises/init_array.c ---8<-- -``` - -If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `Owned` resource -- one `Owned` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. - -To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). - -```c title="solutions/init_array.c" ---8<-- -solutions/init_array.c ---8<-- -``` - - - -TODO: BCP: Concrete syntax: Why not write something like "unchanged {p,n}" or "unchanged: p,n"? - - - -The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. - -The second thing we need to do, however, is less straightforward. Recall that, as discussed at the start of the tutorial, function arguments in C are mutable. Although, in this example, it is obvious that `p` and `n` do not change, CN currently requires the loop invariant to explicitly state this, using special notation `{p} unchanged` (and similarly for `n`). - -**Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. - - - -TODO: BCP: This seems like a good idea! - - - -The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. - -With the `inv` and `extract` statements in place, CN accepts the function. - -### Second loop example - -The specification of `init_array` is overly strong: it requires an iterated `Owned` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `Block` resource for the array should also be sufficient. The modified specification is then as follows. - -```c title="exercises/init_array2.c" ---8<-- -exercises/init_array2.c ---8<-- -``` - -This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `Block` to `Owned` "`state`", so that on function return the full array is initialised. (Recall that stores only require `Block` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) - -To verify this modified example we again need a loop Invariant. But -this time the loop invariant is more involved: since each iteration of -the loop initialises one more array cell, the loop invariant has to do -precise book-keeping of the initialisation status of the different -sections of the array. - -To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `Owned` resource, for all other array indices we have the (unchanged) `Block` ownership. - -```c title="solutions/init_array2.c" ---8<-- -solutions/init_array2.c ---8<-- -``` - -Let's go through this line-by-line: - -- We assert ownership of an iterated `Owned` resource, one for each index `i` strictly smaller than loop variable `j`. - -- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `Block` resource. - -- As in the previous example, we assert `p` and `n` are unchanged. - -- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `Owned` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. - -As before, we also have to instruct CN to `extract` ownership of individual array cells out of the iterated resources: - -- to allow CN to extract the individual `Block` to be written, we use `extract Block, j;`; - -- the store returns a matching `Owned` resource for index `j`; - -- finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. - - -BCP: That last bit is mysterious. - - -Dhruv: See long explanation and issue here: rems-project/cerberus#498 - - -### Exercises - -**Init array reverse.** Verify the function `init_array_rev`, which has the same specification as `init_array2`, but initializes the array in decreasing index order (from right to left). - -```c title="exercises/init_array_rev.c" ---8<-- -exercises/init_array_rev.c ---8<-- -``` - - -A potential case study (involving nested iteration): - https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128 - diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index 28530032..319ceff2 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -1,55 +1,9 @@ -# Ownership of Structured Objects +# Verification with Pointers to Structured Objects -So far, our examples have worked with just integers and pointers, but -larger programs typically also manipulate compound values, often -represented using C `struct`s. Specifying functions manipulating -structs works in much the same way as with basic types. +Verifying CN programs involving structured objects raises a number +of new issues. -For instance, the following example uses a `struct` `point` to represent a point in two-dimensional space. The function `transpose` swaps a point’s `x` and `y` coordinates. - -```c title="exercises/transpose.c" ---8<-- -exercises/transpose.c ---8<-- -``` - - -BCP: This talks about "CN types," which haven't really been -introduced. It also talks about i32, whereas (a) we are using u32 and -(b) I don't know if this has been introduced anyway. - -Here the precondition asserts ownership for `p`, at type `struct -point`; the output `P_post` is a value of CN type `struct point`, -i.e. a record with members `i32` `x` and `i32` `y`. The -postcondition similarly asserts ownership of `p`, with output -`P_post`, and asserts the coordinates have been swapped, by referring to -the members of `P` and `P_post` individually. - - -BCP: This paragraph is quite confusing if read carefully: it seems to say that the "take" in the requires clause returns a different type than the "tajke" in the "ensures" clause. Moreover, even if the reader decides that this cannot be the case and they have to return the same type, they may wonder whether this type is a C type (which is what it looks like, since there is only one struct declaration, and it is not in a magic comment) or a CN type (which might be expected, since it is the result of a "take"). I _guess_ what's going on here is that every C type is automatically reflected as a CN type with the same name. But this story is also not 100% satisfying, since the basic numeric types don't work this way: each C numeric type has an _analog_ in CN, but with a different name. - - - -Dhruv: -C supports strong updates in certain situations and so take _ = Owned(p) in the requires clause could very well have a different C type than take _ = Owned(p) in the ensures clause. - - - -The reason `Owned` needs a C-type annotation is so that it can (a) -figure out the size of the sub-heap being claimed and (b) figure out -how one may need to destructure the type (unions, struct fields and -padding, arrays). The relationship is that for `take x = -Owned(expr)` we have `expr : pointer, x : to_basetype(ct)`. - - -There is a design decision to consider here rems-project/cerberus#349 - - -### Compound Owned and Block resources - - -BCP: The rest fo the chapter is probably just for verification. - +## Compound Owned and Block resources While one might like to think of a struct as a single (compound) object that is manipulated as a whole, C permits more flexible struct manipulation: given a struct pointer, programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. @@ -57,9 +11,6 @@ CN therefore cannot treat resources for compound C types like structs as primiti For struct types `T`, the `Owned` resource is defined as the collection of `Owned` resources for its members (as well as `Block` resources for any padding bytes in-between them). The resource `Block`, similarly, is made up of `Block` resources for all members (and padding bytes). - -BCP: Is this relevant to testing? - To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. Recall the function `zero` from our earlier exercise. It takes an `unsigned int` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. @@ -76,7 +27,7 @@ As stated in its precondition, `init_point` receives ownership `Blockx` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. -### Resource inference +## Resource inference To handle the required resource inference, CN "`eagerly`" decomposes all `struct` resources into resources for the struct members, and "`lazily`" re-composes them as needed. @@ -109,15 +60,9 @@ When the function returns, the two member resources are recombined "`on demand`" ### Exercises _Init point._ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. - -BCP: That's just for verification. - - -_Transpose (again)._ Recreate the transpose function from before, now using the swap function verified earlier (for `struct upoint`, with unsigned int member values). - -BCP: No need for upoint now... - +_Transpose (again)._ Recreate the `transpose` function from before, +using the `swap` function verified earlier. ```c title="exercises/transpose2.c" @@ -127,11 +72,12 @@ exercises/transpose2.c ``` -BCP: Some more things to think about including... - Something about CN's version of the frame rule (see -bcp_framerule.c, though the example is arguably a bit -unnatural). - Examples from Basic.v with allocation - there are lots of +BCP: Some more things to think about including... +- Something about CN's version of the frame rule (see +bcp_framerule.c, though the example is arguably a bit unnatural). +- Examples from Basic.v with allocation - there are lots of interesting ones! -CP: Agreed. For now continuing with arrays, but will return to this later. + CP: Agreed. For now continuing with arrays, but will return to this later. diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 35092d95..503d5c5b 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,25 +1,23 @@ # Pointers and Simple Ownership - -Things to do: - + Rough notes / updated outline: - read.c - unannotated version fails tests - need to explain how to figure out WHY testing fails! - explain ownership (copy/move from verification tutorial) - version with proper spec works better! - - (lots of useful text) - read.broken.c demonstrates linearity of resource usage - exercises: - quadruple_mem - - abs_mem (doesn't work, but we can use the other examples - from the previous section) + - abs_mem (this doesn't work with unsigned ints, but we can + use the other examples from the previous section) - slf0_basic_incr_signed.c shows the difference between Block and Owned - exercises - zero.c - - basic_inplace_double.c involves UB, so skip? + - basic_inplace_double.c involves UB, so skip it or (maybe + better) replace with something that doesn't - maybe something about swapping pointers? - add_read (but changing it to swapping or something, to avoid UB @@ -67,12 +65,6 @@ cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. This permission is represented by a _resource_ `Owned(p)`. - -BCP: Is that right?? Should it be just Owned(p)? Or just -Owned(p)?? (I think just Owned(p) is OK, and we should use that -everywhere it's OK! We'll need a bit of explanation when we reach the -first place where it is _not_ OK.) - ## Owned resources @@ -80,7 +72,9 @@ Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type `T`. If `T` is a single-word type, then `` can be omitted. - + In this example, we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as @@ -415,3 +409,38 @@ _Transfer._ Write a specification for the function `transfer`, shown below. exercises/slf8_basic_transfer.c --8<-- ``` + +## Ownership of Structured Objects + +So far, our examples have worked with just integers and pointers, but +larger programs typically also manipulate compound values, often +represented using C `struct`s. Specifying functions manipulating +structs works in much the same way as with basic types. + +For instance, the following example uses a `struct` `point` to +represent a point in two-dimensional space. The function `transpose` +swaps a point’s `x` and `y` coordinates. + +```c title="exercises/transpose.c" +--8<-- +exercises/transpose.c +--8<-- +``` + +Here the precondition asserts ownership for `p`, at type `struct +point`; the output `P_post` is a value of type `struct point`, i.e. a +record with members `x` and `y`. The postcondition similarly asserts +ownership of `p`, with output `P_post`, and asserts the coordinates +have been swapped, by referring to the members of `P` and `P_post` +individually. + +The reason `Owned` needs a C-type annotation is so that it can (a) +figure out the size of the sub-heap being claimed and (b) figure out +how one may need to destructure the type (unions, struct fields and +padding, arrays). The relationship is that for `take x = +Owned(expr)` we have `expr : pointer, x : to_basetype(ct)`. + + +There is a design decision to consider here rems-project/cerberus#349 + + diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 120f942d..8b3dac6f 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -15,6 +15,9 @@ - (but even if we do this, we need to name the verification chapters so that people can distinguish them from specification chapters) +- rename `unsigned int` to `unsigned` globally? +- rewrite `Owned` to `Owned` globally (and similar for + other single-word types) ## General notes diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md new file mode 100644 index 00000000..0ebe666b --- /dev/null +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -0,0 +1,258 @@ +# Verifying Programs with Arrays and Loops + +Recall this specification for a simple function that reads from an array: + +```c title="exercises/array_load.broken.c" +--8<-- +exercises/array_load.broken.c +--8<-- +``` + +This specification, in principle, should ensure that the access `p[i]` +is safe. However, running `cn verify` on the example produces an +error: CN is unable to find the required ownership for reading `p[i]`. + +``` +cn verify solutions/array_load.broken.c +[1/1]: read +build/solutions/array_load.broken.c:5:10: error: Missing resource for reading +return p[i]; +^~~~ +Resource needed: Owned(array_shift(p, (u64)i)) +``` + +The reason is that, when searching for a required resource, such as the `Owned` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. + + +BCP: This is more verification-relevant + + +To make the `Owned` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`extract`" ownership for index `i` out of the iterated resource. + +```c title="exercises/array_load.c" +--8<-- +exercises/array_load.c +--8<-- +``` + +Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: + +```c +each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } +``` + +is split into + +1. the instantiation of the iterated resource at `i` + +```c +Owned(array_shift(p,i)) +``` + +2. the remainder of the iterated resource, the ownership for all indices except `i` + +```c + each(i32 j; 0i32 <= j && j < n && j != i) + { Owned(array_shift(p,j)) } +``` + +After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. + +Following an `extract` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. + +So far the specification only guarantees safe execution but does not +specify the behaviour of `read`. To address this, let’s return to +the iterated resources in the function specification. When we specify +`take A = each ...` here, what is `A`? In CN, the output of an +iterated resource is a _map_ from indices to resource outputs. In this +example, where index `j` has CN type `i32` and the iterated +resource is `Owned`, the output `A` is a map from `i32` +indices to `i32` values — CN type `map`. If the type of +`j` was `i64` and the resource `Owned`, `A` would have +type `map`. + +We can use this to refine our specification with information about the functional behaviour of `read`. + +```c title="exercises/array_load2.c" +--8<-- +exercises/array_load2.c +--8<-- +``` + +We specify that `read` does not change the array — the outputs of `Owned`, +`A` and `A_post`, taken before and after running the function, are +the same — and that the value returned is `A[i]`. + +### Exercises + +_Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. + + +BCP: When we get around to renaming files in the examples directory, +we should call this one array_swap or something else beginning with +"array". Or put it in a subdirectory. + + +```c title="exercises/add_two_array.c" +--8<-- +exercises/add_two_array.c +--8<-- +``` + + +BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the extract declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) + + + +Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints + + +_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. + +```c title="exercises/swap_array.c" +--8<-- +exercises/swap_array.c +--8<-- +``` + + +TODO: BCP: I wrote the following, which seemed natural but did not +work -- I still don't fully understand why. I think this section will +need some more examples / exercises to be fully digestible, or perhaps +this is just yet another symptom of my imperfecdt understanding of how +the numeric stuff works. + + void swap_array (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) + /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + 0i32 <= i && i < n; + 0i32 <= j && j < n; + j != i; + take xi = Owned(array_shift(p,i)); + take xj = Owned(array_shift(p,j)) + ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + a1[i:xj][j:xi] == a2 + @*/ + { + extract Owned, i; + extract Owned, j; + unsigned int tmp = p[i]; + p[i] = p[j]; + p[j] = tmp; + } + + +### Loops + +The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. + +In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all owned resources and the constraints required to verify each iteration of the loop. + +Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. + + +BCP: Rename to array_init.c + + +```c title="exercises/init_array.c" +--8<-- +exercises/init_array.c +--8<-- +``` + +If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `Owned` resource -- one `Owned` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. + +To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). + +```c title="solutions/init_array.c" +--8<-- +solutions/init_array.c +--8<-- +``` + + + +TODO: BCP: Concrete syntax: Why not write something like "unchanged {p,n}" or "unchanged: p,n"? + + + +The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. + +The second thing we need to do, however, is less straightforward. Recall that, as discussed at the start of the tutorial, function arguments in C are mutable. Although, in this example, it is obvious that `p` and `n` do not change, CN currently requires the loop invariant to explicitly state this, using special notation `{p} unchanged` (and similarly for `n`). + +**Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. + + + +TODO: BCP: This seems like a good idea! + + + +The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. + +With the `inv` and `extract` statements in place, CN accepts the function. + +### Second loop example + +The specification of `init_array` is overly strong: it requires an iterated `Owned` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `Block` resource for the array should also be sufficient. The modified specification is then as follows. + +```c title="exercises/init_array2.c" +--8<-- +exercises/init_array2.c +--8<-- +``` + +This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `Block` to `Owned` "`state`", so that on function return the full array is initialised. (Recall that stores only require `Block` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) + +To verify this modified example we again need a loop Invariant. But +this time the loop invariant is more involved: since each iteration of +the loop initialises one more array cell, the loop invariant has to do +precise book-keeping of the initialisation status of the different +sections of the array. + +To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `Owned` resource, for all other array indices we have the (unchanged) `Block` ownership. + +```c title="solutions/init_array2.c" +--8<-- +solutions/init_array2.c +--8<-- +``` + +Let's go through this line-by-line: + +- We assert ownership of an iterated `Owned` resource, one for each index `i` strictly smaller than loop variable `j`. + +- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `Block` resource. + +- As in the previous example, we assert `p` and `n` are unchanged. + +- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `Owned` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. + +As before, we also have to instruct CN to `extract` ownership of individual array cells out of the iterated resources: + +- to allow CN to extract the individual `Block` to be written, we use `extract Block, j;`; + +- the store returns a matching `Owned` resource for index `j`; + +- finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. + + +BCP: That last bit is mysterious. + + +Dhruv: See long explanation and issue here: rems-project/cerberus#498 + + +### Exercises + +**Init array reverse.** Verify the function `init_array_rev`, which has the same specification as `init_array2`, but initializes the array in decreasing index order (from right to left). + +```c title="exercises/init_array_rev.c" +--8<-- +exercises/init_array_rev.c +--8<-- +``` + + +A potential case study (involving nested iteration): + https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128 + diff --git a/src/exercises/array_load.broken.c b/src/exercises/array_load.noverif.c similarity index 72% rename from src/exercises/array_load.broken.c rename to src/exercises/array_load.noverif.c index 866c701b..f440a434 100644 --- a/src/exercises/array_load.broken.c +++ b/src/exercises/array_load.noverif.c @@ -1,9 +1,9 @@ int read (unsigned int *p, unsigned int n, unsigned int i) /*@ requires take A = each(u32 j; 0u32 <= j && j < n) { Owned(array_shift(p,j)) }; - 0u32 <= i && i < n; + i < n; ensures take A_post = each(u32 j; 0u32 <= j && j < n) { - Owned(array_shift(p,j)) }; + Owned(array_shift(p,j)) }; @*/ { return p[i]; diff --git a/src/exercises/transpose2.c b/src/exercises/transpose2.c index 31b390fd..535e25ce 100644 --- a/src/exercises/transpose2.c +++ b/src/exercises/transpose2.c @@ -12,12 +12,12 @@ void swap (unsigned int *p, unsigned int *q) *q = m; } -struct upoint { unsigned int x; unsigned int y; }; +struct point { unsigned int x; unsigned int y; }; -void transpose2 (struct upoint *p) +void transpose2 (struct point *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = Owned(p); + ensures take P_post = Owned(p); P_post.x == P.y; P_post.y == P.x; @*/ From e56da289c25aa199cd4bfd6659cd45f3e15a0925 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 10 Mar 2025 23:12:49 -0400 Subject: [PATCH 052/158] make dramatic suggestions to pointers.md --- docs/getting-started/tutorials/pointers.md | 115 +++++++++++++-------- 1 file changed, 74 insertions(+), 41 deletions(-) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 503d5c5b..3b74313f 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -33,10 +33,10 @@ taken into account. CN uses _separation logic resources_ and the concept of _ownership_ to reason about memory accesses. A _resource_, intuitively, represents -the permission to access a region of memory. +the permission to access a region of memory. Let’s look at a simple example. The function `read` takes an integer -pointer `p` and returns the pointee value. +pointer `p` and returns the pointee value. ```c title="exercises/read.c" --8<-- @@ -44,36 +44,43 @@ exercises/read.c --8<-- ``` -Running CN on this example produces the following error: +Running `cn test` on this example produces an error that looks like this: + +JWS: I propose a stylistic convention where we omit the `$ cn test filename` +and just include the output excerpt, but do say Running `cn test` intead of +running CN. I just think that achieves the same effect of avoiding ambiguity +about what is run without having to worry about filename syncing etc. + ``` -cn test read.c -Compiled 'read_test.c'. -Compiled 'read-exec.c'. -Compiled 'cn.c'. - -Linked C *.o files. - -Using seed: 65a9c0d1f79889a9 Testing read::read: FAILED - -Testing Summary: -cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 +function read, file ./read-exec.c, line 18 +************************************************************ +function read, file ./read-exec.c, line 18 +Load failed. + ==> 0x122592a09[0] (0x122592a09) not owned ``` -For the read `*p` to be safe, we need to know that the function has -permission to access the memory pointed to by `p`. This permission is -represented by a _resource_ `Owned(p)`. +For the read `*p` to be safe, we need to know that the function has permission +to access the memory pointed to by `p`. We next explain how to represent this +permission. ## Owned resources Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type -`T`. If `T` is a single-word type, then `` can be omitted. +`T`. + + + + - In this example, we can ensure the safe execution of `read` by adding @@ -92,18 +99,36 @@ solutions/read.c This specification can be read as follows: - any function calling `read` has to be able to provide a resource - `Owned(p)` to pass into `read`, and + `Owned(p)` to pass into `read`, and - the caller will receive back a resource `Owned(p)` when - `read` returns. + `read` returns. BCP: Is this going slowly enough for "real-world -engineers"? Where do we need more detail? +engineers"? Where do we need more detail? + + +JWS: I think this is plenty slow... ## Resource outputs + JWS: Is it actually necessary to explain all this? To +me in this section a super intuitive thing is being explained in very complicated +terms. I think `take ...` is super intuitive: we want to be able to write +conditions on the acutal value at the pointer. I understand there might be some +technical nuances, but naively I would expect the next few paragraphs to be +reducable to two sentences, e.g. I propose to replace everything until "JWS: +continue here" with: + + + +In addition to reasoning about memory accesed by pointers, we likely also want +to reason about the actual values that the pointers point to. The `take P =` in +the precondition assigns the name `P` to the pointee value of `p`. + + BCP: The idea that "resources have outputs" is very mind-boggling to many new users, _especially_ folks with some separation logic background. Needs to be explained very @@ -129,10 +154,10 @@ have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. -BCP: ... in a given heap! (The real problem here is that "and the associated ownership" is pretty vague.) +BCP: ... in a given heap! (The real problem here is that "and the associated ownership" is pretty vague.) -Dhruv: Perhaps mentioning sub-heaps will help? +Dhruv: Perhaps mentioning sub-heaps will help? CN uses the `take` notation seen in the example above to bind the @@ -154,7 +179,11 @@ something like this in the last round of syntax changes...) BCP: This might be a good place for a comment on naming -conventions. Plus a pointer to a longer discussion if needed. +conventions. Plus a pointer to a longer discussion if needed. + + + +JWS: continue here That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying @@ -172,11 +201,11 @@ exercises/read2.c _Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): - Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. + Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. - Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? + Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? ``` @@ -193,7 +222,7 @@ exercises/read2.c In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. -Let’s try the `read` example from earlier again, but with a postcondition that does not return the ownership: +Let’s try the `read` example from earlier again, but without such a postcondition: ```c title="exercises/read.broken.c" --8<-- @@ -202,7 +231,6 @@ exercises/read.broken.c ``` CN rejects this program with the following message: - ``` > cn test exercises/read.broken.c ... @@ -215,22 +243,27 @@ Postcondition leak check failed, ownership leaked for pointer 0x1243d8a82 BCP: Explain what that means. Update if the output format changes. -CN has typechecked the function and verified (1) that it is safe to + + -CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "forgotten". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). +Given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. +CN’s resources are _linear_. +Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). CN’s motivation for linear tracking of resources is its focus on low-level systems software in which memory is managed manually; in -this context, memory leaks are typically very undesirable. As a -consequence, function specifications have to do precise bookkeeping of -their resource footprint and, in particular, return any unused -resources back to the caller. +this context, memory leaks are typically very undesirable. + + + +JWS notes to self that I stopped here + ## Exercises @@ -279,7 +312,7 @@ value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. -BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. +BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. Since `Owned` carries the same ownership as `Block`, just with the @@ -361,7 +394,7 @@ exercises/slf3_basic_inplace_double.c ## Multiple owned pointers -When functions manipulate multiple pointers, we can assert +When functions manipulate multiple pointers, we can assert ownership of each one, just like before. But there is an additional twist: pointer ownership in CN is _unique_ -- that is, simultaneously owning resources for two pointers implies that these From bfe308f5555f6907bd7dd1e45618d1be2854cac5 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 11 Mar 2025 07:38:19 -0400 Subject: [PATCH 053/158] Some responses to Jessica --- docs/getting-started/tutorials/pointers.md | 34 +++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 3b74313f..ca4e922d 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -51,6 +51,9 @@ and just include the output excerpt, but do say Running `cn test` intead of running CN. I just think that achieves the same effect of avoiding ambiguity about what is run without having to worry about filename syncing etc. + +BCP: That's fine. I've also asked Zain to streamline the CN outputs. + ``` Testing read::read: @@ -78,14 +81,33 @@ I don't know what a "single-word type" is and I think type annotations that are sometimes optional and sometimes not are less confusingly presented as always required? --> + + In this example, we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as -shown below. (For now ignore the `take ... =` part.) Since reading the pointer does not disturb its value, +shown below. (The `take ... =` part will be explained shortly.) Since +reading the pointer does not disturb its value, we can also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. @@ -104,14 +126,6 @@ This specification can be read as follows: - the caller will receive back a resource `Owned(p)` when `read` returns. - -BCP: Is this going slowly enough for "real-world -engineers"? Where do we need more detail? - - -JWS: I think this is plenty slow... - - ## Resource outputs JWS: Is it actually necessary to explain all this? To From d4e061cad7af7fc21f0688fd27f2deea2a834dfc Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 11 Mar 2025 09:40:25 -0400 Subject: [PATCH 054/158] Tidying --- Makefile | 11 ++++++----- docs/getting-started/tutorials/README.md | 7 ++++--- ...allocating-and-deallocating-memory.md => alloc.md} | 0 docs/getting-started/tutorials/dynamic.md | 2 -- 4 files changed, 10 insertions(+), 10 deletions(-) rename docs/getting-started/tutorials/{verification/allocating-and-deallocating-memory.md => alloc.md} (100%) delete mode 100644 docs/getting-started/tutorials/dynamic.md diff --git a/Makefile b/Makefile index 9f47e6eb..5fe7eb31 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -.PHONY: default check-archive check-tutorial check clean exercises +.PHONY: default check-archive check-tutorial check clean tidy \ + exercises rebuild tutorial MAKEFILE_DIR:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) @@ -160,14 +161,14 @@ check: check-tutorial check-archive ############################################################################## # Tutorial document -# BCP: This runs mkdocs every time we run make, which is a little -# noisy -- would be nicer to run it only when other things change -tutorial: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) +tutorial: rebuild mkdocs build --strict -serve: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) +serve: rebuild mkdocs serve +rebuild: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) + ############################################################################## # Misc diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 6118468b..97f00a08 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -8,8 +8,10 @@ - [V: A first taste of verification](basics-with-verification.md) - [Working with pointers](pointers.md) - [V: Verification with pointers to structured objects](compound.md) -- [Arrays and Loops](arrays.md) -- [V: Verifying Programs with Arrays and Loops](verif-arrays.md) +- [Arrays and loops](arrays.md) +- [V: Verifying programs with arrays and loops](verif-arrays.md) +- [Allocating and deallocating + memory](alloc.md) - [Dynamic storage allocation](dynamic.md) - [More on numeric types](numeric.md) @@ -26,7 +28,6 @@ ## OLD STUFF - [Defining predicates](verification/defining-predicates.md) -- [Allocating and deallocating memory](verification/allocating-and-deallocating-memory.md) - [Lists](verification/lists.md) - [Working with external lemmas](verification/external-lemmas.md) diff --git a/docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md b/docs/getting-started/tutorials/alloc.md similarity index 100% rename from docs/getting-started/tutorials/verification/allocating-and-deallocating-memory.md rename to docs/getting-started/tutorials/alloc.md diff --git a/docs/getting-started/tutorials/dynamic.md b/docs/getting-started/tutorials/dynamic.md deleted file mode 100644 index ea011382..00000000 --- a/docs/getting-started/tutorials/dynamic.md +++ /dev/null @@ -1,2 +0,0 @@ -# Dynamic Heap Structures - From 12afcfe2ac62bc7027005658bff42bc45b7fa6c7 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 11 Mar 2025 11:27:20 -0400 Subject: [PATCH 055/158] More progress on the testing tutorial --- Makefile | 69 +++++++++++-------- docs/getting-started/tutorials/README.md | 24 ++++--- docs/getting-started/tutorials/alloc.md | 12 ++-- .../tutorials/{verification => }/lists.md | 0 .../tutorials/overview-fulminate.md | 7 +- .../getting-started/tutorials/overview-pbt.md | 3 + .../defining-predicates.md => predicates.md} | 39 +++++------ docs/getting-started/tutorials/todo.md | 7 ++ ...s-with-verification.md => verif-basics.md} | 0 .../external-lemmas.md => verif-external.md} | 0 .../tutorials/verif-splitcase.md | 18 +++++ src/exercises/slf_incr2.noverif.c | 43 ++++++++++++ 12 files changed, 150 insertions(+), 72 deletions(-) rename docs/getting-started/tutorials/{verification => }/lists.md (100%) rename docs/getting-started/tutorials/{verification/defining-predicates.md => predicates.md} (71%) rename docs/getting-started/tutorials/{basics-with-verification.md => verif-basics.md} (100%) rename docs/getting-started/tutorials/{verification/external-lemmas.md => verif-external.md} (100%) create mode 100644 docs/getting-started/tutorials/verif-splitcase.md create mode 100644 src/exercises/slf_incr2.noverif.c diff --git a/Makefile b/Makefile index 5fe7eb31..a27d3c48 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ .PHONY: default check-archive check-tutorial check clean tidy \ - exercises rebuild tutorial + exercises rebuild tutorial MAKEFILE_DIR:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) @@ -23,9 +23,8 @@ ALL = $(H) $(C) BROKEN = $(shell find src/exercises -type f -name *broken*) NOTBROKEN = $(filter-out $(BROKEN), $(C)) -NOVERIF = $(shell find src/exercises -type f -name *noverif*) \ - $(BROKEN) -VERIF = $(filter-out $(NOVERIF), $(C)) +NOVERIF = $(shell find src/exercises -type f -name *noverif*) +VERIF = $(filter-out $(BROKEN) $(NOVERIF), $(C)) SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(ALL)) EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(ALL)) @@ -33,7 +32,7 @@ VERIFIED=$(patsubst src/exercises/%, _temp/verified/%, $(VERIF)) #TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(NOTBROKEN)) # TEMPORARY: -TESTED = \ +TESTED = $(NOVERIF) \ _temp/tested/abs_mem_struct.c \ _temp/tested/bcp_framerule.c \ _temp/tested/slf_quadruple_mem.c \ @@ -76,12 +75,12 @@ TESTED = \ _temp/tested/add_0.c \ _temp/tested/abs.c \ _temp/tested/slf0_basic_incr.signed.c \ - _temp/tested/slf15_basic_succ_using_incr_attempt_.c + _temp/tested/slf15_basic_succ_using_incr_attempt_.c -temp: - @echo $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) +temp: + @echo $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) -exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) +exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) CN=cn verify CNTEST=cn test --output _temp @@ -89,18 +88,34 @@ CNTEST=cn test --output _temp # Control verbosity (run make with V= to show everything that's happening) V=@ +# BCP: This is a temporary hack to use gcc to preprocess #includes +# because CN doesn't handle them right. _temp/tested/% : src/exercises/% $(V)echo Testing $< $(V)-mkdir -p $(dir $@) - $(V)$(CNTEST) $< 2>&1 | tee $@.test.out - $(V)-grep PASSED $@.test.out || true - $(V)-grep FAILED $@.test.out || true + $(V)-mkdir -p $(dir _temp/$<.combined.c) + $(V)gcc -E -CC -P $< > _temp/$<.combined.c + $(V)$(CNTEST) _temp/$<.combined.c 2>&1 | tee $@.test.out + $(V)-grep "PASSED\\|FAILED" $@.test.out || true @# Next line should not be needed! $(V)if grep -q "fatal error\\|Failed to compile" $@.test.out; then \ - exit 1; \ + exit 1; \ fi $(V)touch $@ +## BCP: Better version... +# +# _temp/tested/% : src/exercises/% +# $(V)echo Testing $< +# $(V)-mkdir -p $(dir $@) +# $(V)$(CNTEST) $< 2>&1 | tee $@.test.out +# $(V)-grep "PASSED\\|FAILED" $@.test.out || true +# @# Next line should not be needed! +# $(V)if grep -q "fatal error\\|Failed to compile" $@.test.out; then \ +# exit 1; \ +# fi +# $(V)touch $@ + _temp/verified/% : src/exercises/% $(V)echo Verifying $< $(V)-mkdir -p $(dir $@) @@ -123,25 +138,25 @@ docs/exercises.zip: $(EXERCISES) WORKING=$(wildcard src/exercises/list_*.c) WORKING_AUX=$(patsubst src/exercises/%, docs/solutions/%, $(WORKING)) -# cn test --output-dir=$(HOME)/tmp read.broken.c +# cn test --output-dir=$(HOME)/tmp read.broken.c # OLD # docs/solutions/%: src/exercises/% -# @-mkdir -p $(dir $@) -# @-mkdir -p _tests -# @if [ `which cn` ]; then \ -# if [[ "$<" = *".c"* ]]; then \ -# if [[ "$<" != *"broken"* && "$<" != *"partial"* && "$<" != *".DS_Store"* ]]; then \ -# if [[ "$<" = *".test."*c ]]; then \ -# echo $(CNTEST) $< && $(CNTEST) $< --output _tests; \ +# @-mkdir -p $(dir $@) +# @-mkdir -p _tests +# @if [ `which cn` ]; then \ +# if [[ "$<" = *".c"* ]]; then \ +# if [[ "$<" != *"broken"* && "$<" != *"partial"* && "$<" != *".DS_Store"* ]]; then \ +# if [[ "$<" = *".test."*c ]]; then \ +# echo $(CNTEST) $< && $(CNTEST) $< --output _tests; \ # else \ -# echo $(CN) $< && $(CN) $<; \ -# fi; \ +# echo $(CN) $< && $(CN) $<; \ +# fi; \ # fi; \ -# fi \ -# fi -# @echo Rebuild $@ -# @cat $< | sed '\|^.*--BEGIN--.*$$|d' | sed '\|^.*--END--.*$$|d' > $@ +# fi \ +# fi +# @echo Rebuild $@ +# @cat $< | sed '\|^.*--BEGIN--.*$$|d' | sed '\|^.*--END--.*$$|d' > $@ ############################################################################## # Check that the examples all run correctly diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 97f00a08..0cea2506 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -3,17 +3,24 @@ - [Welcome](welcome.md) ## A Tour of CN -- [A first taste of CN](first-taste.md) +- [Specifications](first-taste.md) - [Preconditions](preconditions.md) -- [V: A first taste of verification](basics-with-verification.md) +- [(Verification) + A first taste of verification](verif-basics.md) - [Working with pointers](pointers.md) -- [V: Verification with pointers to structured objects](compound.md) +- [(Verification) + Pointers to structured objects, verified](compound.md) - [Arrays and loops](arrays.md) -- [V: Verifying programs with arrays and loops](verif-arrays.md) -- [Allocating and deallocating - memory](alloc.md) -- [Dynamic storage allocation](dynamic.md) +- [(Verification) + Arrays and loops, verified](verif-arrays.md) +- [Allocating and deallocating memory](alloc.md) - [More on numeric types](numeric.md) +- [Defining predicates](predicates.md) +- [Lists](lists.md) +- [(Verification) + Case analysis](verif-splitcase.md) +- [(Verification) + Working with external lemmas](verif-external.md) ## Case studies @@ -27,9 +34,6 @@ ## OLD STUFF -- [Defining predicates](verification/defining-predicates.md) -- [Lists](verification/lists.md) -- [Working with external lemmas](verification/external-lemmas.md) diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index caf90644..1d9dbfbc 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -52,9 +52,7 @@ exercises/ref.h ``` - TODO: BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does... - ```c title="exercises/slf16_basic_succ_using_incr.c" @@ -81,15 +79,13 @@ exercises/slf_ref_greater.c ### Side note -Here is another syntax for external / unknown -functions, together with an example of a loose specification: - - -TODO: BCP: This is a bit random -- it's not clear people need to know about this alternate syntax, and it's awkwardly mixed with a semi-interesting example that's not relevant to this section. Also awkwardly placed, right here. - +TODO: BCP: This is a bit random -- it's not clear people need to know about this alternate syntax, and it's awkwardly mixed with a semi-interesting example that's not relevant to this section. +Here is another syntax for external / unknown +functions, together with an example of a loose specification: + ```c title="exercises/slf18_two_dice.c" --8<-- exercises/slf18_two_dice.c diff --git a/docs/getting-started/tutorials/verification/lists.md b/docs/getting-started/tutorials/lists.md similarity index 100% rename from docs/getting-started/tutorials/verification/lists.md rename to docs/getting-started/tutorials/lists.md diff --git a/docs/getting-started/tutorials/overview-fulminate.md b/docs/getting-started/tutorials/overview-fulminate.md index 39d3751f..30de92a7 100644 --- a/docs/getting-started/tutorials/overview-fulminate.md +++ b/docs/getting-started/tutorials/overview-fulminate.md @@ -2,9 +2,9 @@ Fulminate is a tool for translating CN specifications into C runtime assertions, which can then be checked using concrete test inputs. -## Installation +## Installation -Fulminate is installed as part of the CN toolchain - see [README.md](../../installation.md) for instructions. +Fulminate is installed as part of the CN toolchain - see the [README.md](../installation.md) for instructions. ## Running Fulminate @@ -16,7 +16,7 @@ To produce a file instrumented with CN runtime assertions, run: cn instrument .c ``` -This will produce three files: +This will produce three files: * `-exec.c`, the instrumented source * `cn.h`, a header file containing various definitions and prototypes, including C struct definitions representing CN datatypes, structs and records, as well as function prototypes for the various translated top-level CN functions and predicates. @@ -44,4 +44,3 @@ $CHECK_SCRIPT .c This runs the `cn-runtime-single-file.sh` script from the CN runtime library on `.c`, which generates the executable specification files, compiles and links these, and then runs the produced binary. This script is configurable with the `-n` option for disabling dynamic ownership checking and/or the `-q` option for running the script in quiet mode. This script can be found in `runtime/libcn/libexec` if you are interested in seeing the compile and link commands. The compile command includes the `-g` flag for collecting debug information, which means gdb or lldb can be run on the produced binary for setting breakpoints, stepping in and out of functions in a given run, printing concrete variable values at specific points in the program run, etc. gdb can cause problems on Mac due to some certification-related issues, so for Mac users we recommend you use lldb. - diff --git a/docs/getting-started/tutorials/overview-pbt.md b/docs/getting-started/tutorials/overview-pbt.md index 119893b0..81f0f785 100644 --- a/docs/getting-started/tutorials/overview-pbt.md +++ b/docs/getting-started/tutorials/overview-pbt.md @@ -32,6 +32,9 @@ It calls the function with this input and uses [Fulminate](overview-fulminate.md #### Understanding errors + +BCP: This is out of date: + Currently, the tool does not print out counterexamples, but this is [planned](https://github.com/rems-project/cerberus/issues/841). Until then, `tests.out` can be run with the `--trap` flag in a debugger. Since seeds are printed each time the tool runs, `--seed ` can be used to reproduce the test case. diff --git a/docs/getting-started/tutorials/verification/defining-predicates.md b/docs/getting-started/tutorials/predicates.md similarity index 71% rename from docs/getting-started/tutorials/verification/defining-predicates.md rename to docs/getting-started/tutorials/predicates.md index 8a8b298a..d9a5d3e1 100644 --- a/docs/getting-started/tutorials/verification/defining-predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -1,17 +1,13 @@ # Defining Predicates - We should show how to define predicates earlier -- - - - - e.g., with numeric ranges!! + Maybe we should show how to define predicates earlier -- + e.g., with numeric ranges... - TODO: BCP: The text becomes a bit sketchy from here on! But hopefully there's still enough structure here to make sense of the examples... - Suppose we want to write a function that takes _two_ pointers to @@ -51,33 +47,30 @@ A better way is to define a _predicate_ that captures both the aliased and the non-aliased cases together and use it in the pre- and postconditions: - -Sainati: I think it would be useful here to add an explanation for how CN's type checking works. - - - For example, in the definition of BothOwned here, how is CN able to prove that `take pv = Owned(p);` - - - type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? - + Sainati: I think it would be useful here to +add an explanation for how CN's type checking works. For example, in +the definition of BothOwned here, how is CN able to prove that `take +pv = Owned(p);` type checks, since all we know about `p` +in the definition of the predicate is that it's a pointer? -```c title="exercises/slf_incr2.c" +```c title="exercises/slf_incr2.noverif.c" --8<-- -exercises/slf_incr2.c +exercises/slf_incr2.noverif.c --8<-- ``` -BCP: "BothOwned" is a pretty awkward name. - - -BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types. +BCP: Needs quite a few more words. + -BCP: the annotation on incr2 needs some unpacking for readers!! +BCP: "BothOwned" is a pretty awkward name. + -BCP: first use of the "split_case" annotation +BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types. + + diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 8b3dac6f..3b79e70d 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -18,6 +18,13 @@ - rename `unsigned int` to `unsigned` globally? - rewrite `Owned` to `Owned` globally (and similar for other single-word types) +- Write a section on how to do unit testing, once the process is a + little more user-friendly (see `overview-fulminate.md`). Make sure + this is also reflected in the reference manual (or that the manual + links back to here). +- The file `overview-pbt.md` is mostly subsumed by other text here, + but there are some more specific instructions that probably belong + in the reference manual. ## General notes diff --git a/docs/getting-started/tutorials/basics-with-verification.md b/docs/getting-started/tutorials/verif-basics.md similarity index 100% rename from docs/getting-started/tutorials/basics-with-verification.md rename to docs/getting-started/tutorials/verif-basics.md diff --git a/docs/getting-started/tutorials/verification/external-lemmas.md b/docs/getting-started/tutorials/verif-external.md similarity index 100% rename from docs/getting-started/tutorials/verification/external-lemmas.md rename to docs/getting-started/tutorials/verif-external.md diff --git a/docs/getting-started/tutorials/verif-splitcase.md b/docs/getting-started/tutorials/verif-splitcase.md new file mode 100644 index 00000000..b128bc01 --- /dev/null +++ b/docs/getting-started/tutorials/verif-splitcase.md @@ -0,0 +1,18 @@ +# (Verification) Case Analysis + + +This section needs writing... + + +To verify the `slf_incr2` example, we need one more CN annotation in +the body of the + +```c title="exercises/slf_incr2.noverif.c" +--8<-- +exercises/slf_incr2.noverif.c +--8<-- +``` + + +Explain `split-case` in detail and give more examples... + diff --git a/src/exercises/slf_incr2.noverif.c b/src/exercises/slf_incr2.noverif.c new file mode 100644 index 00000000..ab324639 --- /dev/null +++ b/src/exercises/slf_incr2.noverif.c @@ -0,0 +1,43 @@ +/*@ +predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) +{ + if (ptr_eq(p,q)) { + take PX = Owned(p); + return {P: PX, Q: PX}; + } + else { + take PX = Owned(p); + take QX = Owned(q); + return {P: PX, Q: QX}; + } +} +@*/ + +void incr2(unsigned int *p, unsigned int *q) +/*@ requires take PQ = BothOwned(p,q); + ensures take PQ_post = BothOwned(p,q); + PQ_post.P == (!ptr_eq(p,q) ? (PQ.P + 1u32) : (PQ.P + 2u32)); + PQ_post.Q == (!ptr_eq(p,q) ? (PQ.Q + 1u32) : PQ_post.P); +@*/ +{ + unsigned int n = *p; + unsigned int m = n + 1; + *p = m; + n = *q; + m = n + 1; + *q = m; +} + +void call_both_better(unsigned int *p, unsigned int *q) +/*@ requires take P = Owned(p); + take Q = Owned(q); + !ptr_eq(p,q); + ensures take P_post = Owned(p); + take Q_post = Owned(q); + P_post == P + 3u32; + Q_post == Q + 1u32; +@*/ +{ + incr2(p, q); + incr2(p, p); +} From 5b53f3d30b9e33bf8474f3493a417d02453c65b9 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Wed, 12 Mar 2025 01:04:14 -0400 Subject: [PATCH 056/158] work in progress refactoring of pointers.md --- docs/getting-started/tutorials/pointers.md | 321 ++++----------------- 1 file changed, 62 insertions(+), 259 deletions(-) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index ca4e922d..2647d268 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,5 +1,8 @@ # Pointers and Simple Ownership +JWS is in the middle of editing this section + + So far we’ve only considered functions manipulating numeric values. Specifications become more interesting when _pointers_ are @@ -45,15 +48,6 @@ exercises/read.c ``` Running `cn test` on this example produces an error that looks like this: - -JWS: I propose a stylistic convention where we omit the `$ cn test filename` -and just include the output excerpt, but do say Running `cn test` intead of -running CN. I just think that achieves the same effect of avoiding ambiguity -about what is run without having to worry about filename syncing etc. - - -BCP: That's fine. I've also asked Zain to streamline the CN outputs. - ``` Testing read::read: @@ -90,10 +84,10 @@ are less confusingly presented as always required? --> do agree that there is *some* overhead to telling people that the annotation can be omitted. I can see a couple stable alternatives: - Keep the annotations everywhere - - Delete them everywhere they can be deleted (i.e., for + - Delete them everywhere they can be deleted (i.e., for one-word types) and explain, either here or when we get to the first multi-word pointer target, that we need the annotation - there. + there. I mildly prefer the second. But I wonder whether the decision should be informed by some data about whether pointers to single words are common in real C code... @@ -107,7 +101,7 @@ are less confusingly presented as always required? --> In this example, we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as shown below. (The `take ... =` part will be explained shortly.) Since -reading the pointer does not disturb its value, +reading the pointer does not disturb its value, we can also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. @@ -126,83 +120,16 @@ This specification can be read as follows: - the caller will receive back a resource `Owned(p)` when `read` returns. -## Resource outputs +## Pointee values - JWS: Is it actually necessary to explain all this? To -me in this section a super intuitive thing is being explained in very complicated -terms. I think `take ...` is super intuitive: we want to be able to write -conditions on the acutal value at the pointer. I understand there might be some -technical nuances, but naively I would expect the next few paragraphs to be -reducable to two sentences, e.g. I propose to replace everything until "JWS: -continue here" with: - - - In addition to reasoning about memory accesed by pointers, we likely also want to reason about the actual values that the pointers point to. The `take P =` in the precondition assigns the name `P` to the pointee value of `p`. - - BCP: The idea that "resources have outputs" -is very mind-boggling to many new users, _especially_ folks with some -separation logic background. Needs to be explained very -carefully. Also, there's some semantic muddle in the terminology: Is a -resource (1) a thing in the heap, (2) a thing in the heap that one is -currently holding, or (3) the act of holding a thing in the heap? -These are definitely not at all the same thing, but our language at -different points suggests all three! To me, (1) is the natural sense -of the word "resource"; (2) is somewhat awkward, and (3) is extremely -awkward. - -A caller of `read` may also wish to know that `read` actually returns -the correct value (i.e., the thing that `p` points to), and also that -it does not change memory at location `p`. To phrase both we need a -way to refer to the pointee of `p`. - -In CN, resources have _outputs_. Each resource outputs the information -that can be derived from ownership of the resource. What information -is returned is specific to the type of resource. A resource -`Owned(p)` (for some C-type `T`) outputs the _pointee value_ of -`p`, since that can be derived from the resource ownership: assume you -have a pointer `p` and the associated ownership, then this uniquely -determines the pointee value of `p`. +That means we can use the pointee values from the pre- and postcondition to +strengthen the specification of `read`. We add two new postconditions specifying - -BCP: ... in a given heap! (The real problem here is that "and the associated ownership" is pretty vague.) - - -Dhruv: Perhaps mentioning sub-heaps will help? - - -CN uses the `take` notation seen in the example above to bind the -output of a resource to a new name. The precondition `take P = -Owned(p)` does two things: (1) it assert ownership of resource -`Owned(p)`, and (2) it binds the name `P` to the resource output, -here the pointee value of `p` at the start of the function. Similarly, -the postcondition introduces the name `P_post` for the pointee value -on function return. - - -BCP: But, as we've discussed, the word "take" in the postcondition is -quite confusing: What it's doing is precisely the _opposite_ of -"taking" the resournce, not taking it but giving it back!! It would be -much better if we could choose a more neutral word that doesn't imply -either taking or giving. E.g. "resource". (I forget if we decided on -something like this in the last round of syntax changes...) - - - -BCP: This might be a good place for a comment on naming -conventions. Plus a pointer to a longer discussion if needed. - - - -JWS: continue here - - -That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying - -1. that `read` returns `P` (the initial pointee value of `p`), and +1. that `read` returns `P`, the initial pointee value of `p`, and 1. that the pointee values `P` and `P_post` before and after execution of `read` (respectively) are the same. ```c title="exercises/read2.c" @@ -232,117 +159,13 @@ exercises/read2.c CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. -## Linear resource ownership - -In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. - -Let’s try the `read` example from earlier again, but without such a postcondition: - -```c title="exercises/read.broken.c" ---8<-- -exercises/read.broken.c ---8<-- -``` - -CN rejects this program with the following message: -``` -> cn test exercises/read.broken.c -... -FAILED -... -Postcondition leak check failed, ownership leaked for pointer 0x1243d8a82 -... -``` - -BCP: Explain what that means. Update if the output format changes. - - - - - -Given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. - -CN’s resources are _linear_. -Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). -CN’s motivation for linear tracking of resources is its focus on -low-level systems software in which memory is managed manually; in -this context, memory leaks are typically very undesirable. - - - -JWS notes to self that I stopped here - - -## Exercises - -_Quadruple_. Specify the function `quadruple_mem`, which is similar to -the earlier `quadruple` function, except that the input is passed as a -pointer to an `unsigned int`. Write a specification that takes ownership -of this pointer on entry and returns this ownership on exit, leaving -the pointee value unchanged. - -```c title="exercises/slf_quadruple_mem.c" ---8<-- -exercises/slf_quadruple_mem.c ---8<-- -``` - -_Abs_. Give a specification to the function `abs_mem`, which computes -the absolute value of a number passed as an `int` pointer. -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Fix - -```c title="exercises/abs_mem.c" ---8<-- -exercises/abs_mem.c ---8<-- -``` - -## Block resources - -Aside from the `Owned` resources seen so far, CN has another -built-in type of resource called `Block`. Given a C-type `T` and -pointer `p`, `Block(p)` asserts the same ownership as -`Owned(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `Owned`, `Block` memory is not assumed -to be initialised. - -CN uses this distinction to prevent reads from uninitialised memory: - -- A read at C-type `T` and pointer `p` requires a resource - `Owned(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `Owned` resource unchanged. - -- A write at C-type `T` and pointer `p` needs only a -`Block(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `Block` resource -(it destroys it) and returns a new resource `Owned(p)` with the -value written as the output. This means the resource returned from a -write records the fact that this memory cell is now initialised and -can be read from. - -BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. - - -Since `Owned` carries the same ownership as `Block`, just with the -additional information that the `Owned` memory is initalised, a -resource `Owned(p)` is "at least as good" as `Block(p)` — -an `Owned(p)` resource can be used whenever `Block(p)` is -needed. For instance CN’s type checking of a write to `p` requires a -`Block(p)`, but if an `Owned(p)` resource is what is -available, this can be used just the same. This allows an -already-initialised memory cell to be over-written again. - -Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. +_Exercise._ JWS: TODO, probably double ## Writing through pointers -Let’s explore resources and their outputs in another example. The C function `incr` takes an `unsigned int` pointer `p` and increments the value in the memory cell that it poinbts to. +Let’s explore resources and their outputs in another example. The C function +`incr` takes an `unsigned int` pointer `p` and increments the value in the +memory cell that it points to. BCP: unsigned! (there are both signed and unsigned versions at the @@ -362,94 +185,73 @@ asserts ownership of `p` with output `P_post`, as before, and uses this to express that the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. -If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. - - -BCP: change it to unsigned... - +_Exercise._ Write a specification for `inplace_double`, which takes a pointer +`p` and doubles the pointee value. Make sure your postcondition captures the +function's intended behavior. +JWS: TODO make these unsigned int -```c title="exercises/slf0_basic_incr.signed.broken.c" +```c title="exercises/slf3_basic_inplace_double.c" --8<-- -exercises/slf0_basic_incr.signed.broken.c +exercises/slf3_basic_inplace_double.c --8<-- ``` -CN reports: - -BCP: fix it... - - -``` -build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading -int n = \*p; -^~ -Resource needed: Owned(p) -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html -``` +## No memory leaks -## Exercises +In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. -_Zero._ Write a specification for the function `zero`, which takes a pointer to _uninitialised_ memory and initialises it to `0`. +Let’s try the `read` example from earlier again, but without such a postcondition: -```c title="exercises/zero.c" +```c title="exercises/read.broken.c" --8<-- -exercises/zero.c +exercises/read.broken.c --8<-- ``` -_In-place double._ Give a specification for the function `inplace_double`, which takes an `unsigned int` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. - -```c title="exercises/slf3_basic_inplace_double.c" ---8<-- -exercises/slf3_basic_inplace_double.c ---8<-- +CN rejects this program with the following message: +``` +> cn test exercises/read.broken.c +... +FAILED +... +Postcondition leak check failed, ownership leaked for pointer 0x1243d8a82 +... ``` - -## Multiple owned pointers - -When functions manipulate multiple pointers, we can assert -ownership of each one, just like before. But there is an additional -twist: pointer ownership in CN is _unique_ -- that is, simultaneously owning -resources for two pointers implies that these -pointers refer to _disjoint_ regions of memory. - -The following example shows the use of two `Owned` resources for -accessing two different pointers by a function `add`, which reads -two `unsigned int` values in memory, at locations `p` and `q`, and -returns their sum. - -BCP: The way I've been naming things is not working that well -here. The problem is that in examples like this we compute "thing -pointed to by p" at both C and CN levels. At the C level, the thing -pointed to by p obviously cannot also be called p, so it doesn't make -sense for it to be called P at the CN level, right? +BCP: Explain what that means. Update if the output format changes. -```c title="exercises/add_read.c" ---8<-- -exercises/add_read.c ---8<-- -``` + + - -BCP: Does this belong here? Could it go in the later section on numeric types? - -The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. -Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. +Given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. -## Exercises +CN requires that every resource passed into a function has to be either +_returned_ to the caller or else _destroyed_ by deallocating the owned area of +memory (as we shall see later). CN’s motivation for this choice is its focus on +low-level systems software in which memory is managed manually; in this context, +memory leaks are typically very undesirable. + -_Swap._ Specify the function `swap`, which takes two owned `unsigned int` pointers and swaps their values. +_Exercise._ JWS: TODO -```c title="exercises/swap.c" ---8<-- -exercises/swap.c ---8<-- -``` +## Disjoint memory regions + +When functions manipulate multiple pointers, we can assert ownership of each +one, just like before. But there is an additional twist: simultaneously owning +resources for two pointers implies that these pointers refer to _disjoint_ +regions of memory. + +JWS: TODO five/six example -_Transfer._ Write a specification for the function `transfer`, shown below. +_Exercise._ Write a specification for the function `transfer`, shown below. ```c title="exercises/slf8_basic_transfer.c" --8<-- @@ -457,7 +259,7 @@ exercises/slf8_basic_transfer.c --8<-- ``` -## Ownership of Structured Objects +## Ownership of structured objects So far, our examples have worked with just integers and pointers, but larger programs typically also manipulate compound values, often @@ -491,3 +293,4 @@ Owned(expr)` we have `expr : pointer, x : to_basetype(ct)`. There is a design decision to consider here rems-project/cerberus#349 +_Exercise._ JWS: TODO \ No newline at end of file From 7da7aa2f222fe19e8b763ed841d5691f5b5f3c5c Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 12 Mar 2025 08:08:48 -0400 Subject: [PATCH 057/158] More polishing --- Makefile | 22 ++++++++++++--- docs/getting-started/tutorials/arrays.md | 5 ++-- docs/getting-started/tutorials/first-taste.md | 27 ++++++++++--------- docs/getting-started/tutorials/pointers.md | 10 ------- docs/getting-started/tutorials/todo.md | 20 +++++++++----- 5 files changed, 48 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index a27d3c48..4f02bb20 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,9 @@ SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(ALL)) EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(ALL)) VERIFIED=$(patsubst src/exercises/%, _temp/verified/%, $(VERIF)) +MD = $(shell find docs -type f -name "*.md") +CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) + #TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(NOTBROKEN)) # TEMPORARY: TESTED = $(NOVERIF) \ @@ -77,10 +80,7 @@ TESTED = $(NOVERIF) \ _temp/tested/slf0_basic_incr.signed.c \ _temp/tested/slf15_basic_succ_using_incr_attempt_.c -temp: - @echo $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) - -exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) +exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) $(CONSISTENT) CN=cn verify CNTEST=cn test --output _temp @@ -173,6 +173,20 @@ check-tutorial: check: check-tutorial check-archive +############################################################################## +# Check for inconsistent exercise names / paths + +_temp/consistent/% : % + $(V)perl -0777 -ne \ + 'while (/c title=\"(.+)\"\n.+\n(.+)\n/g) { \ + if ($$1 ne $$2) { \ + print "Bad .md file ($<): $$1 does not match $$2\n"; \ + exit 1; \ + } }' \ + $< + $(V)-mkdir -p $(dir $@) + $(V)touch $@ + ############################################################################## # Tutorial document diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index f85aa9b0..cb0ae48c 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -45,7 +45,7 @@ Let’s see how this applies to a simple array-manipulating function. Function ` ```c title="exercises/array_load.noverif.c" --8<-- -exercises/array_load.broken.c +exercises/array_load.noverif.c --8<-- ``` @@ -57,6 +57,5 @@ The CN precondition requires On exit the array ownership is returned again. BCP: Do several more -examples (e.g., maybe working up to sorting?). +examples (e.g., maybe working up to sorting?). - diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 75ed39f7..92376d06 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,6 +1,6 @@ # Specifications -Suppose we are writing a function `min3`, which takes three `int` arguments. +Suppose we are writing a function `min3`, which takes three `unsigned int` arguments. ```c title="exercises/min3/min3.partial.c" --8<-- @@ -10,11 +10,11 @@ exercises/min3/min3.partial.c The desired behavior of `min3` is to return the smallest of the three inputs. We expect, then, that the return value should be less -than or equal to `x` and to `y` and to `z`. More formally: +than or equal to `x` and to `y` and to `z`. More formally: ```c title="exercises/min3/min3.partial1.c" --8<-- -exercises/min3/min3.test.partial.c +exercises/min3/min3.partial1.c --8<-- ``` @@ -25,9 +25,11 @@ In more detail... body. - The keyword `ensures` introduces the function's _postcondition_ -- - that is, a logical statement that should be true when the function returns. + that is, a logical statement that we expect should be true when the + function returns. -- The keyword `return` refers to the return value. +- The keyword `return` refers to the function's return value in the + postcondition. - CN provides a variety of arithmetic and logical operators, which we use here to state that the return value should be less than or equal @@ -35,8 +37,8 @@ In more detail... - Each clause of the specification concludes with a semicolon. -Next, suppose we have implemented `min3` (not quite correctly) as -shown below. +Next, suppose we have implemented `min3` (a little incorrectly) as +shown below. ```c title="exercises/min3/min3.broken.c" --8<-- @@ -44,9 +46,11 @@ exercises/min3/min3.broken.c --8<-- ``` -How can we figure out if our implementation satisfies our -specification? We can test it! Run the command `cn test ` to -produce an output along these lines: +How can we find out whether our implementation satisfies our +specification? We can test it! + +Running the command `cn test ` will produce an output along +these lines: BCP: Refresh this: @@ -153,7 +157,7 @@ _Exercise._ Practice the workflow of specifying and testing the function `add`. - Write a specification with the postcondition that `add` should return the sum of its inputs. Remember that CN supports standard - arithmetic and boolean operators such as `+` and `==`. + arithmetic and boolean operators such as `+` and `==`. - Write an _incorrect_ implementation of `add` and check that `cn test` fails. - Write a _correct_ implementation and check that `cn test` succeeds. @@ -162,4 +166,3 @@ _Exercise._ Practice the workflow of specifying and testing the function `add`. exercises/add.partial.c --8<-- ``` - diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index ca4e922d..7f640233 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -419,20 +419,10 @@ accessing two different pointers by a function `add`, which reads two `unsigned int` values in memory, at locations `p` and `q`, and returns their sum. - -BCP: The way I've been naming things is not working that well -here. The problem is that in examples like this we compute "thing -pointed to by p" at both C and CN levels. At the C level, the thing -pointed to by p obviously cannot also be called p, so it doesn't make -sense for it to be called P at the CN level, right? - - -```c title="exercises/add_read.c" --8<-- exercises/add_read.c --8<-- ``` - BCP: Does this belong here? Could it go in the later section on numeric types? diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 3b79e70d..25d1540b 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -2,19 +2,25 @@ ## Things to clean up later (but before releasing to newbies!) +- Figure out how to separate specification stuff from verification + stuff + - e.g., make a whole separate TOC for the verification flow, with + extra chapters as appropriate + - (but even if we do this, we need to name the verification + chapters so that people can distinguish them from specification + chapters) + - Maybe the simple color scheme that is used at the moment is + fine? + - Make a pass through the whole document and refresh all the displayed outputs from the system - Format exercises consistently throughout - Rename exercise files sensibly / consistently and organize them into subdirectories + - Someplace early on, we should explain the naming conventions + (for exercise names, but especially for extensions) - Fix the top-level README.md with correct names for chapters -- Figure out how to separate specification stuff from verification - stuff - - e.g., make a whole separate TOC for the verification flow, with - extra chapters as appropriate - - (but even if we do this, we need to name the verification - chapters so that people can distinguish them from specification - chapters) + - And add chapters to the top-level nav file - rename `unsigned int` to `unsigned` globally? - rewrite `Owned` to `Owned` globally (and similar for other single-word types) From a58cf88aa59110abece486cb379312cd98fa0a3e Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 12 Mar 2025 08:24:34 -0400 Subject: [PATCH 058/158] Save some useful text --- docs/getting-started/tutorials/alloc.md | 44 ++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index 1d9dbfbc..7632d507 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -1,7 +1,49 @@ # Allocating and Deallocating Memory +XXXXXXXXXXXXXXXXXXX intro needed + +## Block resources + +Aside from the `Owned` resources seen so far, CN has another +built-in type of resource called `Block`. Given a C-type `T` and +pointer `p`, `Block(p)` asserts the same ownership as +`Owned(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `Owned`, `Block` memory is not assumed +to be initialised. + +CN uses this distinction to prevent reads from uninitialised memory: + +- A read at C-type `T` and pointer `p` requires a resource + `Owned(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `Owned` resource unchanged. + +- A write at C-type `T` and pointer `p` needs only a +`Block(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `Block` resource +(it destroys it) and returns a new resource `Owned(p)` with the +value written as the output. This means the resource returned from a +write records the fact that this memory cell is now initialised and +can be read from. -BCP: Again, more text is needed to set up this discussion. +BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. + + +Since `Owned` carries the same ownership as `Block`, just with the +additional information that the `Owned` memory is initalised, a +resource `Owned(p)` is "at least as good" as `Block(p)` — +an `Owned(p)` resource can be used whenever `Block(p)` is +needed. For instance CN’s type checking of a write to `p` requires a +`Block(p)`, but if an `Owned(p)` resource is what is +available, this can be used just the same. This allows an +already-initialised memory cell to be over-written again. + +Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. + +## Allocation + + +BCP: Again, more text is needed to set up this discussion. Maybe the +first para should move up? At the moment, CN does not understand the `malloc` and `free` From 4d27187153030a1e2abd76719e089041a402024f Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 12 Mar 2025 11:46:29 -0400 Subject: [PATCH 059/158] File renaming (in poreparation for making .test versions) --- .../case-studies/doubly-linked-lists.md | 4 ++-- .../case-studies/imperative-queues.md | 4 ++-- docs/getting-started/tutorials/lists.md | 4 ++-- src/exercises/dll/add.c | 2 +- src/exercises/dll/add_orig.broken.c | 2 +- src/exercises/dll/{headers.h => headers.verif.h} | 2 +- src/exercises/dll/remove.c | 2 +- src/exercises/dll/remove_orig.broken.c | 2 +- src/exercises/dll/singleton.c | 2 +- src/exercises/list/append.c | 2 +- src/exercises/list/append2.c | 2 +- src/exercises/list/copy.c | 2 +- src/exercises/list/free.c | 2 +- src/exercises/list/{headers.h => headers.verif.h} | 0 src/exercises/list/length.c | 2 +- src/exercises/list/mergesort.c | 2 +- src/exercises/list/rev.c | 2 +- src/exercises/list/rev_alt.c | 2 +- .../queue/{allocation.h => allocation.verif.h} | 0 src/exercises/queue/empty.c | 2 +- src/exercises/queue/{headers.h => headers.verif.h} | 2 +- src/exercises/queue/pop.c | 2 +- src/exercises/queue/pop_orig.broken.c | 2 +- src/exercises/queue/pop_unified.c | 2 +- src/exercises/queue/push.c | 2 +- src/exercises/queue/push_induction.c | 2 +- src/exercises/queue/push_orig.broken.c | 2 +- src/exercises/slf_length_acc.c | 2 +- src/exercises/slf_sized_stack.c | 2 +- src/old/tutorial.md | 12 ++++++------ src/underconstruction/bst/contains.c | 2 +- src/underconstruction/bst/copy.c | 2 +- src/underconstruction/bst/create_node.c | 2 +- src/underconstruction/bst/depth.c | 2 +- src/underconstruction/bst/free.c | 2 +- src/underconstruction/bst/getter.c | 2 +- .../bst/{headers.h => headers.verif.h} | 0 src/underconstruction/bst/insert.c | 2 +- src/underconstruction/bst/length.c | 2 +- src/underconstruction/bst/search.c | 2 +- src/underconstruction/bst/sum.c | 2 +- 41 files changed, 46 insertions(+), 46 deletions(-) rename src/exercises/dll/{headers.h => headers.verif.h} (83%) rename src/exercises/list/{headers.h => headers.verif.h} (100%) rename src/exercises/queue/{allocation.h => allocation.verif.h} (100%) rename src/exercises/queue/{headers.h => headers.verif.h} (86%) rename src/underconstruction/bst/{headers.h => headers.verif.h} (100%) diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 78d94433..4d09ed7b 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -80,9 +80,9 @@ exercises/dll/malloc_free.h For convenience, we gather all of these files into a single header file. -```c title="exercises/dll/headers.h" +```c title="exercises/dll/headers.verif.h" --8<-- -exercises/dll/headers.h +exercises/dll/headers.verif.h --8<-- ``` diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 043fcad9..2f2fe71c 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -102,9 +102,9 @@ Now we need a bit of boilerplate: just as with linked lists, we need to be able to allocate and deallocate queues and queue cells. There are no interesting novelties here. -```c title="exercises/queue/allocation.h" +```c title="exercises/queue/allocation.verif.h" --8<-- -exercises/queue/allocation.h +exercises/queue/allocation.verif.h --8<-- ``` diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index 9b558697..a33d794b 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -67,9 +67,9 @@ Finally, we can collect all this stuff into a single header file. (We add the usual C `#ifndef` gorp to avoid complaints from the compiler if it happens to get included twice from the same source file later.) -```c title="exercises/list/headers.h" +```c title="exercises/list/headers.verif.h" --8<-- -exercises/list/headers.h +exercises/list/headers.verif.h --8<-- ``` diff --git a/src/exercises/dll/add.c b/src/exercises/dll/add.c index 2962a820..d76122b9 100644 --- a/src/exercises/dll/add.c +++ b/src/exercises/dll/add.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Adds after the given node and returns a pointer to the new node struct dllist *add(int element, struct dllist *n) diff --git a/src/exercises/dll/add_orig.broken.c b/src/exercises/dll/add_orig.broken.c index 8d23ea48..d454709d 100644 --- a/src/exercises/dll/add_orig.broken.c +++ b/src/exercises/dll/add_orig.broken.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Adds after the given node and returns a pointer to the new node struct dllist *add(int element, struct dllist *n) diff --git a/src/exercises/dll/headers.h b/src/exercises/dll/headers.verif.h similarity index 83% rename from src/exercises/dll/headers.h rename to src/exercises/dll/headers.verif.h index 2a029dde..0fa29dc0 100644 --- a/src/exercises/dll/headers.h +++ b/src/exercises/dll/headers.verif.h @@ -1,4 +1,4 @@ -#include "../list/headers.h" +#include "../list/headers.verif.h" #include "../list/append.h" #include "../list/rev.h" #include "./c_types.h" diff --git a/src/exercises/dll/remove.c b/src/exercises/dll/remove.c index 7c87360c..5169007c 100644 --- a/src/exercises/dll/remove.c +++ b/src/exercises/dll/remove.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./dllist_and_int.h" // Remove the given node from the list and returns another pointer diff --git a/src/exercises/dll/remove_orig.broken.c b/src/exercises/dll/remove_orig.broken.c index ba1ff586..0879a7fe 100644 --- a/src/exercises/dll/remove_orig.broken.c +++ b/src/exercises/dll/remove_orig.broken.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./dllist_and_int.h" // removes the given node from the list and returns another pointer diff --git a/src/exercises/dll/singleton.c b/src/exercises/dll/singleton.c index 31679c9f..16ee28dc 100644 --- a/src/exercises/dll/singleton.c +++ b/src/exercises/dll/singleton.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" struct dllist *singleton(int element) /*@ ensures take Ret = Dll_at(return); diff --git a/src/exercises/list/append.c b/src/exercises/list/append.c index 18f516c7..132555b6 100644 --- a/src/exercises/list/append.c +++ b/src/exercises/list/append.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./append.h" struct sllist* IntList_append(struct sllist* xs, struct sllist* ys) diff --git a/src/exercises/list/append2.c b/src/exercises/list/append2.c index 5b6979dd..07d56606 100644 --- a/src/exercises/list/append2.c +++ b/src/exercises/list/append2.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./append.h" struct sllist* IntList_copy (struct sllist *xs) diff --git a/src/exercises/list/copy.c b/src/exercises/list/copy.c index f76e9a98..96ce023c 100644 --- a/src/exercises/list/copy.c +++ b/src/exercises/list/copy.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" struct sllist* slcopy (struct sllist *l) /*@ requires take L = SLList_At(l); diff --git a/src/exercises/list/free.c b/src/exercises/list/free.c index 92e1037a..1315c4bf 100644 --- a/src/exercises/list/free.c +++ b/src/exercises/list/free.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" void free__rec_sllist(struct sllist* l) // You fill in the rest... diff --git a/src/exercises/list/headers.h b/src/exercises/list/headers.verif.h similarity index 100% rename from src/exercises/list/headers.h rename to src/exercises/list/headers.verif.h diff --git a/src/exercises/list/length.c b/src/exercises/list/length.c index 0dc195cf..e7844ae0 100644 --- a/src/exercises/list/length.c +++ b/src/exercises/list/length.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" /* --BEGIN-- */ /*@ diff --git a/src/exercises/list/mergesort.c b/src/exercises/list/mergesort.c index 8a36b63b..604ed454 100644 --- a/src/exercises/list/mergesort.c +++ b/src/exercises/list/mergesort.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" /*@ function [rec] ({datatype List fst, datatype List snd}) diff --git a/src/exercises/list/rev.c b/src/exercises/list/rev.c index ee1b4eed..ed22410b 100644 --- a/src/exercises/list/rev.c +++ b/src/exercises/list/rev.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./append.h" #include "./rev.h" #include "./rev_lemmas.h" diff --git a/src/exercises/list/rev_alt.c b/src/exercises/list/rev_alt.c index 6a651f32..54a2373e 100644 --- a/src/exercises/list/rev_alt.c +++ b/src/exercises/list/rev_alt.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./append.h" #include "./rev.h" #include "./rev_lemmas.h" diff --git a/src/exercises/queue/allocation.h b/src/exercises/queue/allocation.verif.h similarity index 100% rename from src/exercises/queue/allocation.h rename to src/exercises/queue/allocation.verif.h diff --git a/src/exercises/queue/empty.c b/src/exercises/queue/empty.c index ccbd8119..ab38e5f6 100644 --- a/src/exercises/queue/empty.c +++ b/src/exercises/queue/empty.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" struct queue* empty_queue () /* --BEGIN-- */ diff --git a/src/exercises/queue/headers.h b/src/exercises/queue/headers.verif.h similarity index 86% rename from src/exercises/queue/headers.h rename to src/exercises/queue/headers.verif.h index 87fbffc7..cf41f233 100644 --- a/src/exercises/queue/headers.h +++ b/src/exercises/queue/headers.verif.h @@ -8,4 +8,4 @@ #include "./cn_types_2.h" #include "./cn_types_3.h" -#include "./allocation.h" +#include "./allocation.verif.h" diff --git a/src/exercises/queue/pop.c b/src/exercises/queue/pop.c index e840be00..42b91ef3 100644 --- a/src/exercises/queue/pop.c +++ b/src/exercises/queue/pop.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./pop_lemma.h" int pop_queue (struct queue *q) diff --git a/src/exercises/queue/pop_orig.broken.c b/src/exercises/queue/pop_orig.broken.c index f6d28084..5203c30d 100644 --- a/src/exercises/queue/pop_orig.broken.c +++ b/src/exercises/queue/pop_orig.broken.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" int pop_queue (struct queue *q) { diff --git a/src/exercises/queue/pop_unified.c b/src/exercises/queue/pop_unified.c index cecaa39b..06f0a91f 100644 --- a/src/exercises/queue/pop_unified.c +++ b/src/exercises/queue/pop_unified.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" /*@ type_synonym result = { datatype List after, datatype List before } diff --git a/src/exercises/queue/push.c b/src/exercises/queue/push.c index 19e27637..6a125ae4 100644 --- a/src/exercises/queue/push.c +++ b/src/exercises/queue/push.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./push_lemma.h" void push_queue (int x, struct queue *q) diff --git a/src/exercises/queue/push_induction.c b/src/exercises/queue/push_induction.c index 06c0117f..e62f52cb 100644 --- a/src/exercises/queue/push_induction.c +++ b/src/exercises/queue/push_induction.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" void push_induction(struct queue_cell* front , struct queue_cell* second_last diff --git a/src/exercises/queue/push_orig.broken.c b/src/exercises/queue/push_orig.broken.c index 97116c4a..0b235582 100644 --- a/src/exercises/queue/push_orig.broken.c +++ b/src/exercises/queue/push_orig.broken.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" void push_queue (int x, struct queue *q) { diff --git a/src/exercises/slf_length_acc.c b/src/exercises/slf_length_acc.c index f3fa4389..d53f5c2c 100644 --- a/src/exercises/slf_length_acc.c +++ b/src/exercises/slf_length_acc.c @@ -1,4 +1,4 @@ -#include "list/headers.h" +#include "list/headers.verif.h" #include "ref.h" #include "free.h" diff --git a/src/exercises/slf_sized_stack.c b/src/exercises/slf_sized_stack.c index 929d6bef..669dc813 100644 --- a/src/exercises/slf_sized_stack.c +++ b/src/exercises/slf_sized_stack.c @@ -1,4 +1,4 @@ -#include "list/headers.h" +#include "list/headers.verif.h" #include "list/length.c" struct sized_stack diff --git a/src/old/tutorial.md b/src/old/tutorial.md index fca86309..0fa1bb5f 100644 --- a/src/old/tutorial.md +++ b/src/old/tutorial.md @@ -1224,9 +1224,9 @@ Finally, we can collect all this stuff into a single header file. (We add the usual C `#ifndef` gorp to avoid complaints from the compiler if it happens to get included twice from the same source file later.) -```c title="exercises/list/headers.h" +```c title="exercises/list/headers.verif.h" --8<-- -exercises/list/headers.h +exercises/list/headers.verif.h --8<-- ``` @@ -1603,9 +1603,9 @@ Now we need a bit of boilerplate: just as with linked lists, we need to be able to allocate and deallocate queues and queue cells. There are no interesting novelties here. -```c title="exercises/queue/allocation.h" +```c title="exercises/queue/allocation.verif.h" --8<-- -exercises/queue/allocation.h +exercises/queue/allocation.verif.h --8<-- ``` @@ -1907,9 +1907,9 @@ exercises/dll/malloc_free.h For convenience, we gather all of these files into a single header file. -```c title="exercises/dll/headers.h" +```c title="exercises/dll/headers.verif.h" --8<-- -exercises/dll/headers.h +exercises/dll/headers.verif.h --8<-- ``` diff --git a/src/underconstruction/bst/contains.c b/src/underconstruction/bst/contains.c index aee1293e..eb7acab5 100644 --- a/src/underconstruction/bst/contains.c +++ b/src/underconstruction/bst/contains.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // returns true (1u32) or false (u32), if value is an node in the binary Tree /* FILL IN CN FUNCTION SPEC DEFINTION HERE */ diff --git a/src/underconstruction/bst/copy.c b/src/underconstruction/bst/copy.c index 4b80c7a0..bde65aba 100644 --- a/src/underconstruction/bst/copy.c +++ b/src/underconstruction/bst/copy.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "./constructors.h" // takes in binary tree, Returns copy of it diff --git a/src/underconstruction/bst/create_node.c b/src/underconstruction/bst/create_node.c index 075ba82e..b173c1ed 100644 --- a/src/underconstruction/bst/create_node.c +++ b/src/underconstruction/bst/create_node.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Initializes new node with value given as its argument struct node* node_create_node(int value) diff --git a/src/underconstruction/bst/depth.c b/src/underconstruction/bst/depth.c index 2798cc0f..866f9bc3 100644 --- a/src/underconstruction/bst/depth.c +++ b/src/underconstruction/bst/depth.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // counts the furthest distance from the root to the leaf node /* FILL IN CN FUNCTION SPEC DEFINTION HERE */ diff --git a/src/underconstruction/bst/free.c b/src/underconstruction/bst/free.c index 84f3204c..e452ae26 100644 --- a/src/underconstruction/bst/free.c +++ b/src/underconstruction/bst/free.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // deallocates all the nodes in the binary tree void node_free_tree (struct node* t) diff --git a/src/underconstruction/bst/getter.c b/src/underconstruction/bst/getter.c index f3983af8..a6a04a66 100644 --- a/src/underconstruction/bst/getter.c +++ b/src/underconstruction/bst/getter.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Extracts the members of a given Tree node int get_Tree_Data (struct node *t) diff --git a/src/underconstruction/bst/headers.h b/src/underconstruction/bst/headers.verif.h similarity index 100% rename from src/underconstruction/bst/headers.h rename to src/underconstruction/bst/headers.verif.h diff --git a/src/underconstruction/bst/insert.c b/src/underconstruction/bst/insert.c index 8b67415c..0d2b3ddf 100644 --- a/src/underconstruction/bst/insert.c +++ b/src/underconstruction/bst/insert.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" #include "create_node.c" // inserts a new node into binary tree diff --git a/src/underconstruction/bst/length.c b/src/underconstruction/bst/length.c index 9b90b129..2a89abbb 100644 --- a/src/underconstruction/bst/length.c +++ b/src/underconstruction/bst/length.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Function which counts all the nodes in the tree /* FILL IN CN FUNCTION SPEC DEFINTION HERE */ diff --git a/src/underconstruction/bst/search.c b/src/underconstruction/bst/search.c index 1e8653ac..fdb083ee 100644 --- a/src/underconstruction/bst/search.c +++ b/src/underconstruction/bst/search.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Searches for a node with the given value in the binary Tree /* FILL IN CN FUNCTION SPEC DEFINTION HERE */ diff --git a/src/underconstruction/bst/sum.c b/src/underconstruction/bst/sum.c index 70fb6393..968ce8de 100644 --- a/src/underconstruction/bst/sum.c +++ b/src/underconstruction/bst/sum.c @@ -1,4 +1,4 @@ -#include "./headers.h" +#include "./headers.verif.h" // Sums up the data values of the nodes of the binary tree /* FILL IN CN FUNCTION SPEC DEFINTION HERE */ From a8198cdebb995d26007fdb7336c85a721feab8c4 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 12 Mar 2025 14:43:05 -0400 Subject: [PATCH 060/158] Working on splitting out testing / verification versions of list and queue examples --- Makefile | 32 +- .../case-studies/doubly-linked-lists.md | 8 +- .../case-studies/imperative-queues.md | 27 +- .../case-studies/the-runway.md | 4 +- .../case-studies/verif-imperative-queues.md | 327 ++++++++++++++++++ docs/getting-started/style-guide/README.md | 2 +- docs/getting-started/tutorials/README.md | 4 + docs/getting-started/tutorials/arrays.md | 4 +- docs/getting-started/tutorials/lists.md | 74 ++-- docs/getting-started/tutorials/pointers.md | 2 +- docs/getting-started/tutorials/predicates.md | 4 +- .../getting-started/tutorials/verif-arrays.md | 4 - .../tutorials/verif-external.md | 11 +- docs/getting-started/tutorials/verif-lists.md | 207 +++++++++++ .../tutorials/verif-splitcase.md | 4 +- ...array_load.noverif.c => array_load.test.c} | 0 src/exercises/cn_malloc.h | 4 + src/exercises/list/append.test.c | 17 + .../list/{append.c => append.verif.c} | 0 src/exercises/list/c_types.test.h | 20 ++ .../list/{c_types.h => c_types.verif.h} | 0 src/exercises/list/headers.test.h | 9 + src/exercises/list/headers.verif.h | 2 +- src/exercises/list/mergesort.brokentest.c | 124 +++++++ .../list/{mergesort.c => mergesort.verif.c} | 0 .../queue/{cn_types_3.h => cn_types_3.test.h} | 0 src/exercises/queue/cn_types_3.verif.h | 13 + src/exercises/queue/headers.test.h | 11 + src/exercises/queue/headers.verif.h | 8 +- .../{slf_incr2.noverif.c => slf_incr2.test.c} | 0 30 files changed, 819 insertions(+), 103 deletions(-) create mode 100644 docs/getting-started/case-studies/verif-imperative-queues.md create mode 100644 docs/getting-started/tutorials/verif-lists.md rename src/exercises/{array_load.noverif.c => array_load.test.c} (100%) create mode 100644 src/exercises/cn_malloc.h create mode 100644 src/exercises/list/append.test.c rename src/exercises/list/{append.c => append.verif.c} (100%) create mode 100644 src/exercises/list/c_types.test.h rename src/exercises/list/{c_types.h => c_types.verif.h} (100%) create mode 100644 src/exercises/list/headers.test.h create mode 100644 src/exercises/list/mergesort.brokentest.c rename src/exercises/list/{mergesort.c => mergesort.verif.c} (100%) rename src/exercises/queue/{cn_types_3.h => cn_types_3.test.h} (100%) create mode 100644 src/exercises/queue/cn_types_3.verif.h create mode 100644 src/exercises/queue/headers.test.h rename src/exercises/{slf_incr2.noverif.c => slf_incr2.test.c} (100%) diff --git a/Makefile b/Makefile index 4f02bb20..f9b70143 100644 --- a/Makefile +++ b/Makefile @@ -20,22 +20,21 @@ tidy: H = $(shell find src/exercises -type f -name *.h) C = $(shell find src/exercises -type f -name *.c) ALL = $(H) $(C) -BROKEN = $(shell find src/exercises -type f -name *broken*) -NOTBROKEN = $(filter-out $(BROKEN), $(C)) -NOVERIF = $(shell find src/exercises -type f -name *noverif*) -VERIF = $(filter-out $(BROKEN) $(NOVERIF), $(C)) +TESTONLY = $(shell find src/exercises -type f -name *.test*.c) +VERIFONLY = $(shell find src/exercises -type f -name *.verif*.c) + +BROKEN = $(shell find src/exercises -type f -name *broken* -or -name *partial*) +VERIF = $(filter-out $(BROKEN) $(TESTONLY), $(C)) +TEST = $(filter-out $(BROKEN) $(VERIFONLY), $(C)) SOLUTIONS=$(patsubst src/exercises/%, docs/solutions/%, $(ALL)) EXERCISES=$(patsubst src/exercises/%, docs/exercises/%, $(ALL)) VERIFIED=$(patsubst src/exercises/%, _temp/verified/%, $(VERIF)) -MD = $(shell find docs -type f -name "*.md") -CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) - -#TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(NOTBROKEN)) +#TESTED=$(patsubst src/exercises/%, _temp/tested/%, $(TEST)) # TEMPORARY: -TESTED = $(NOVERIF) \ +TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/abs_mem_struct.c \ _temp/tested/bcp_framerule.c \ _temp/tested/slf_quadruple_mem.c \ @@ -70,7 +69,6 @@ TESTED = $(NOVERIF) \ _temp/tested/slf_incr2.c \ _temp/tested/id_by_div/id_by_div.fixed.c \ _temp/tested/slf2_basic_quadruple.c \ - _temp/tested/slf18_two_dice.c \ _temp/tested/swap.c \ _temp/tested/slf1_basic_example_let.signed.c \ _temp/tested/slf9_basic_transfer_aliased.c \ @@ -80,7 +78,14 @@ TESTED = $(NOVERIF) \ _temp/tested/slf0_basic_incr.signed.c \ _temp/tested/slf15_basic_succ_using_incr_attempt_.c -exercises: $(TESTED) $(VERIFIED) $(SOLUTIONS) $(EXERCISES) $(CONSISTENT) +# NOT WORKING? +# _temp/tested/slf18_two_dice.c \ + + +MD = $(shell find docs -type f -name "*.md") +CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) + +exercises: $(EXERCISES) $(SOLUTIONS) $(TESTED) $(VERIFIED) $(CONSISTENT) CN=cn verify CNTEST=cn test --output _temp @@ -98,7 +103,7 @@ _temp/tested/% : src/exercises/% $(V)$(CNTEST) _temp/$<.combined.c 2>&1 | tee $@.test.out $(V)-grep "PASSED\\|FAILED" $@.test.out || true @# Next line should not be needed! - $(V)if grep -q "fatal error\\|Failed to compile" $@.test.out; then \ + $(V)if grep -q "fatal error\\|Failed to compile\\|Failed to link\\|: error:" $@.test.out; then \ exit 1; \ fi $(V)touch $@ @@ -120,6 +125,9 @@ _temp/verified/% : src/exercises/% $(V)echo Verifying $< $(V)-mkdir -p $(dir $@) $(V)$(CN) $< 2>&1 | tee $@.verif.out + $(V)if grep -q "fatal error\\|Failed to compile\\|Failed to link\\|: error:" $@.verif.out; then \ + exit 1; \ + fi $(V)touch $@ docs/exercises/%: src/exercises/% diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 4d09ed7b..dbd592e8 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -1,6 +1,6 @@ # Doubly-linked Lists - +BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. A doubly linked list is a linked list where each node has a pointer to both the next node and the previous node. This allows for O(1) @@ -38,7 +38,7 @@ we first own the node that is passed in. Then we follow all of the all the `next` pointers to own everything forwards from the node, to construct the `left` and `right` fields. - +BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? ```c title="exercises/dll/predicates.h" --8<-- @@ -112,7 +112,7 @@ exercises/dll/add_orig.broken.c _Exercise_: Before reading on, see if you can figure out what specification is appropriate and what other are needed. - +BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. Now, here is the annotated version of the `add` operation: @@ -173,7 +173,7 @@ exercises/dll/remove_orig.broken.c _Exercise_: Before reading on, see if you can figure out what specification is appropriate and what annotations are needed. - +BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. Now, here is the fully annotated version of the `remove` operation: diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 2f2fe71c..c023d7f1 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -24,6 +24,8 @@ exercises/queue/cn_types_1.h --8<-- ``` +BCP: Explain the asserts if needed. + Given a pointer to a `queue` struct, this predicate grabs ownership of the struct, asserts that the `front` and `back` pointers must either both be NULL or both be non-NULL, and then hands off to an @@ -34,7 +36,7 @@ between a queue and a singly or doubly linked list is simply one of concrete representation. `QueueFB` is where the interesting part starts. (Conceptually, -`QueueFB` is part of `QueuePTR`, but CN currently allows +it is part of `QueuePTR`, but CN currently allows conditional expressions only at the beginning of predicate definitions, not after a `take`, so we need to make a separate auxiliary predicate.) @@ -58,7 +60,7 @@ get to it at the end of the recursion starting from the `front`. Second, and relatedly, there will be two pointers to this final list cell -- one from the `back` field and one from the `next` field of the second to last cell (or the `front` pointer, if there is only -one cell in the list), so we need to be careful not to `take` this +one cell in the list), and we need to be careful not to `take` this cell twice. Accordingly, we begin by `take`-ing the tail cell and passing it @@ -67,19 +69,12 @@ walking down the cells from the front and gathering all the rest of them into a sequence. We take the result from `QueueAux` and `snoc` on the very last element. -The `assert (is_null(B.next))` here gives the CN verifier a crucial -piece of information about an invariant of the representation: The -`back` pointer always points to the very last cell in the list, so -its `next` field will always be NULL. - - - Finally, the `QueueAux` predicate recurses down the list of cells and returns a list of their contents. -```c title="exercises/queue/cn_types_3.h" +```c title="exercises/queue/cn_types_3.test.h" --8<-- -exercises/queue/cn_types_3.h +exercises/queue/cn_types_3.test.h --8<-- ``` @@ -163,7 +158,7 @@ elements, so we should expect that validating `push` is going to require some reasoning about this sequence. Here, in fact, is the lemma we need. - +BCP: Not sure I can explain what "pointer" means here, or why we don't need to declare more specific types for these arguments to the lemma. ```c title="exercises/queue/push_lemma.h" @@ -229,7 +224,7 @@ CN which of the branches of the `if` at the beginning of the unpacked immediately because it is unconditional, but `QueueFB` cannot.) - +BCP: the word "unpack" is mysterious here. The guard/condition for `QueueFB` is `is_null(front)`, which is why we need to do a `split_case` on this value. On one branch of the @@ -274,14 +269,14 @@ clauses. (Taking them just in the `requires` clause would imply that they are consumed and deallocated when the lemma is applied -- not what we want!) - +BCP: The thing about ghost values is mysterious. (The only reason we can't currently prove this lemma in CN is that we don't have `take`s in CN statements, because this is just a simple unfolding.) - +BCP: Ugh. _Exercise_: Investigate what happens when you make each of the following changes @@ -319,5 +314,3 @@ lemma before the `return` will be a bit more complicated. _Note_: Again, this has not been shown to be possible, but Dhruv believes it should be! - - diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 7450e313..0bdb7442 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -1,6 +1,6 @@ # Airport Simulation - +BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... Suppose we have been tasked with writing a program that simulates a runway at an airport. This airport is very small, so it only has one @@ -11,7 +11,7 @@ following informal specification: 1. The runway has two modes: departure mode and arrival mode. The two modes can never be active at the same time. Neither mode is active at the beginning of the day. - +BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) 2. At any given moment, there is a waiting list of planes that need to land at the airport and planes that need to leave the diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md new file mode 100644 index 00000000..1f7b62f9 --- /dev/null +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -0,0 +1,327 @@ +# Verifying Imperative Queues + +A queue is a linked list with O(1) operations for adding things to one +end (the "back") and removing them from the other (the "front"). Here +are the C type definitions: + +```c title="exercises/queue/c_types.h" +--8<-- +exercises/queue/c_types.h +--8<-- +``` + +A queue consists of a pair of pointers, one pointing to the front +element, which is the first in a linked list of `queue_cell`s, +the other pointing directly to the last cell in this list. If the +queue is empty, both pointers are NULL. + +Abstractly, a queue just represents a list, so we can reuse the `List` +type from the list examples earlier in the tutorial. + +```c title="exercises/queue/cn_types_1.h" +--8<-- +exercises/queue/cn_types_1.h +--8<-- +``` + +Given a pointer to a `queue` struct, this predicate grabs ownership +of the struct, asserts that the `front` and `back` pointers must +either both be NULL or both be non-NULL, and then hands off to an +auxiliary predicate `QueueFB`. Note that `QueuePtr_At` returns a +`List` -- that is, the abstract view of a queue heap structure is +simply the sequence of elements that it contains. The difference +between a queue and a singly or doubly linked list is simply one of +concrete representation. + +`QueueFB` is where the interesting part starts. (Conceptually, +`QueueFB` is part of `QueuePTR`, but CN currently allows +conditional expressions only at the beginning of predicate +definitions, not after a `take`, so we need to make a separate +auxiliary predicate.) + +```c title="exercises/queue/cn_types_2.h" +--8<-- +exercises/queue/cn_types_2.h +--8<-- +``` + +First, we case on whether the `front` of the queue is NULL. If so, +then the queue is empty and we return the empty sequence. + +If the queue is not empty, we need to walk down the linked list of +elements and gather up all their values into a sequence. But we must +treat the last element of the queue specially, for two reasons. +First, since the `push` operation is going to follow the `back` +pointer directly to the last list cell without traversing all the +others, we need to `take` that element now rather than waiting to +get to it at the end of the recursion starting from the `front`. +Second, and relatedly, there will be two pointers to this final list +cell -- one from the `back` field and one from the `next` field of +the second to last cell (or the `front` pointer, if there is only +one cell in the list), so we need to be careful not to `take` this +cell twice. + +Accordingly, we begin by `take`-ing the tail cell and passing it +separately to the `QueueAux` predicate, which has the job of +walking down the cells from the front and gathering all the rest of +them into a sequence. We take the result from `QueueAux` and +`snoc` on the very last element. + +The `assert (is_null(B.next))` here gives the CN verifier a crucial +piece of information about an invariant of the representation: The +`back` pointer always points to the very last cell in the list, so +its `next` field will always be NULL. + +BCP: First point where testing and +verification split. Remove most of the material above here. + +BCP: What about the second assert? + +BCP: How to help people guess that these are +needed?? + +Finally, the `QueueAux` predicate recurses down the list of +cells and returns a list of their contents. + +```c title="exercises/queue/cn_types_3.verif.h" +--8<-- +exercises/queue/cn_types_3.verif.h +--8<-- +``` + +Its first argument (`f`) starts out at `front` and progresses +through the queue on recursive calls; its `b` argument is always a +pointer to the very last cell. + +When `f` and `b` are equal, we have reached the last cell and +there is nothing to do. We don't even have to build a singleton +list: that's going to happen one level up, in `QueueFB`. + +Otherwise, we `take` the fields of the `f`, make a recurive +call to `QueueAux` to process the rest of the cells, and cons the +`first` field of this cell onto the resulting sequence before +returning it. Again, we need to help the CN verifier by explicitly +informing it of the invariant that we know, that `C.next` cannot be +null if `f` and `b` are different. + +Now we need a bit of boilerplate: just as with linked lists, we need +to be able to allocate and deallocate queues and queue cells. There +are no interesting novelties here. + +```c title="exercises/queue/allocation.verif.h" +--8<-- +exercises/queue/allocation.verif.h +--8<-- +``` + + + +_Exercise_: The function for creating an empty queue just needs to set +both of its fields to NULL. See if you can fill in its specification. + +```c title="exercises/queue/empty.c" +--8<-- +exercises/queue/empty.c +--8<-- +``` + + + +The push and pop operations are more involved. Let's look at `push` +first. + +Here's the unannotated C code -- make sure you understand it. + +```c title="exercises/queue/push_orig.broken.c" +--8<-- +exercises/queue/push_orig.broken.c +--8<-- +``` + +_Exercise_: Before reading on, see if you can write down a reasonable +top-level specification for this operation. + +One thing you might find odd about this code is that there's a +`return` statement at the end of each branch of the conditional, +rather than a single `return` at the bottom. The reason for this is +that, when CN analyzes a function body containing a conditional, it +effectively _copies_ all the code after the conditional into each of +the branches. Then, if verification encounters an error related to +this code -- e.g., "you didn't establish the `ensures` conditions at +the point of returning -- the error message will be confusing because +it will not be clear which branch of the conditional it is associated +with. + +Now, here is the annotated version of the `push` operation. + +```c title="exercises/queue/push.c" +--8<-- +exercises/queue/push.c +--8<-- +``` + +The case where the queue starts out empty (`q->back == 0`) is easy. +CN can work it out all by itself. + +The case where the starting queue is nonempty is more interesting. +The `push` operation messes with the end of the sequence of queue +elements, so we should expect that validating `push` is going to +require some reasoning about this sequence. Here, in fact, is the +lemma we need. + +BCP: Not sure I can explain what "pointer" means here, or why we don't need to declare more specific types for these arguments to the lemma. + + +```c title="exercises/queue/push_lemma.h" +--8<-- +exercises/queue/push_lemma.h +--8<-- +``` + +This says, in effect, that we have two choices for how to read out the +values in some chain of queue cells of length at least 2, starting +with the cell `front` and terminating when we get to the next cell +_following_ some given cell `p` -- call it `c`. We can either +gather up all the cells from `front` to `c`, or we can gather up +just the cells from `front` to `p` and then `snoc` on the single +value from `c`. + +When we apply this lemma, `p` will be the old `back` cell and +`c` will be the new one. But to prove it (by induction, of course), +we need to state it more generally, allowing `p` to be any internal +cell in the list starting at `front` and `c` its successor. + +The reason we need this lemma is that, to add a new cell at the end of +the queue, we need to reassign ownership of the old `back` cell. +In the precondition of `push`, we took ownership of this cell +separately from the rest; in the postcondition, it needs to be treated +as part of the rest (so that the new `back` cell can now be treated +specially). + +One interesting technicality is worth noting: After the assignment +`q->back = c`, we can no longer prove `QueueFB(q->front, +oldback)`, but we don't care about this, since we want to prove +`QueueFB(q->front, q->back)`. However, crucially, +`QueueAux(q->front, oldback)` is still true. + + + +Now let's look at the `pop` operation. Here is the un-annotated +version: + +```c title="exercises/queue/pop_orig.broken.c" +--8<-- +exercises/queue/pop_orig.broken.c +--8<-- +``` + +_Exercise_: Again, before reading on, see if you can write down a +plausible top-level specification. (For extra credit, see how far you +can get with verifying it!) + +Here is the fully annotated `pop` code: + +```c title="exercises/queue/pop.c" +--8<-- +exercises/queue/pop.c +--8<-- +``` + +There are three annotations to explain. Let's consider them in order. + +First, the `split_case` on `is_null(q->front)` is needed to tell +CN which of the branches of the `if` at the beginning of the +`QueueFB` predicate it can "unpack". (`QueuePtr_At` can be +unpacked immediately because it is unconditional, but `QueueFB` +cannot.) + +BCP: the word "unpack" is mysterious here. + +The guard/condition for `QueueFB` is `is_null(front)`, which is +why we need to do a `split_case` on this value. On one branch of the +`split_case` we have a contradiction: the fact that `before == +Nil{}` (from `QueueFB`) conflicts with `before != Nil` +from the precondition, so that case is immediate. On the other +branch, CN now knows that the queue is non-empty, as required, and type +checking proceeds. + +When `h == q->back`, we are in the case where the queue contains +just a single element, so we just need to NULL out its `front` and +`back` fields and deallocate the dead cell. The `unfold` +annotation is needed because the `snoc` function is recursive, so CN +doesn't do the unfolding automatically. + +Finally, when the queue contains two or more elements, we need to +deallocate the front cell, return its `first` field, and redirect +the `front` field of the queue structure to point to the next cell. +To push the verification through, we need a simple lemma about the +`snoc` function: + +```c title="exercises/queue/pop_lemma.h" +--8<-- +exercises/queue/pop_lemma.h +--8<-- +``` + +The crucial part of this lemma is the last three lines, which express +a simple, general fact about `snoc`: +if we form a sequence by calling `snoc` to add a final element +`B.first` to a sequence with head element `x` and tail `Q`, then the +head of the resulting sequence is still `x`, and its tail is `snoc +(Q, B.first)`. + +The `requires` clause and the first three lines of the `ensures` +clause simply set things up so that we can name the various values we +are talking about. Since these values come from structures in the +heap, we need to take ownership of them. And since lemmas in CN are +effectively just trusted functions that can also take in ghost values, +we need to take ownership in both the `requires` and `ensures` +clauses. (Taking them just in the `requires` clause would imply +that they are consumed and deallocated when the lemma is applied -- +not what we want!) + +BCP: The thing about ghost values is mysterious. + + +(The only reason we can't currently prove this lemma in CN is that we +don't have `take`s in CN statements, because this is just a simple +unfolding.) + +BCP: Ugh. + +## Exercises + +_Exercise_: +Investigate what happens when you make each of the following changes +to the queue definitions. What error does CN report? Where are the +telltale clues in the error report that suggest what the problem was? + +- Remove `assert (is_null(B.next));` from `InqQueueFB`. +- Remove `assert (is_null(B.next));` from `InqQueueAux`. +- Remove one or both of occurrences of `free_queue_cell(f)` in + `pop_queue`. +- Remove, in turn, each of the CN annotations in the bodies of + `pop_queue` and `push_queue`. + +_Exercise_: The conditional in the `pop` function tests whether or +not `f == b` to find out whether we have reached the last element of +the queue. Another way to get the same information would be to test +whether `f->next == 0`. Can you verify this version? +_Note_: I (BCP) have not worked out the details, so am not sure how hard +this is (or if it is even not possible, though I'd be surprised). +Please let me know if you get it working! + +_Exercise_: Looking at the code for the `pop` operation, +it might seem reasonable to move the identical assignments to `x` in both +branches to above the `if`. This doesn't "just work" because the +ownership reasoning is different. In the first case, ownership of +`h` comes from `QueueFB` (because `h == q->back`). In the +second case, it comes from `QueueAux` (because `h != +q->back`). + +Can you generalize the `snoc_facts` lemma to handle both cases? You +can get past the dereference with a `split_case` but formulating the +lemma before the `return` will be a bit more complicated. + +BCP: Again, this has not been shown to be +possible, but Dhruv believes it should be! diff --git a/docs/getting-started/style-guide/README.md b/docs/getting-started/style-guide/README.md index 2cf0e3a4..69e804fb 100644 --- a/docs/getting-started/style-guide/README.md +++ b/docs/getting-started/style-guide/README.md @@ -1,6 +1,6 @@ # Style Guide - +BCP: If we are agreed on the naming conventions suggested in /NAMING-CONVENTIONS.md, we could move that material here. !!! warning diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 0cea2506..a6f2d4b2 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -17,6 +17,8 @@ - [More on numeric types](numeric.md) - [Defining predicates](predicates.md) - [Lists](lists.md) +- [(Verification) + Lists](verif-lists.md) - [(Verification) Case analysis](verif-splitcase.md) - [(Verification) @@ -25,6 +27,8 @@ ## Case studies - [Imperative queues](../case-studies/imperative-queues.md) +- [(Verification) + Verifying imperative queues](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) - [Airport Simulation](../case-studies/the-runway.md) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index cb0ae48c..ec3228ea 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -43,9 +43,9 @@ comprising three parts: Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. -```c title="exercises/array_load.noverif.c" +```c title="exercises/array_load.test.c" --8<-- -exercises/array_load.noverif.c +exercises/array_load.test.c --8<-- ``` diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index a33d794b..3e79cdb7 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -1,7 +1,11 @@ # Lists -BCP: Better intro needed +BCP: Maybe this should be a case study? + + + +BCP: Better intro needed Now it's time to look at some more interesting heap structures. @@ -10,25 +14,15 @@ To begin with, here is a C definition for linked list cells, together with allocation and deallocation functions: -BCP: Here and in several other places, we should use the "take \_ = ..." syntax when the owned value is not used. And we should explain it the first time we use it. +BCP: break sllist out into its own separate .h file and look at it first -```c title="exercises/list/c_types.h" +```c title="exercises/list/c_types.test.h" --8<-- -exercises/list/c_types.h +exercises/list/c_types.test.h --8<-- ``` - -BCP: Per discussion with Christopher, Cassia, and Daniel, the word "predicate" is quite confusing for newcomers (in logic, predicates do not return things!). A more neutral word might make for significantly easier onboarding. - - -Dhruv: Or no keyword? rems-project/cerberus#304 How about traversal? - - - BCP: No keyword sounds even better. But "traversal" in the interim is not bad. Or maybe "extractor" or something like that? - - To write specifications for C functions that manipulate lists, we need to define a CN "predicate" that describes specification-level list structures, as one would do in ML, Haskell, or Coq. We use the @@ -47,6 +41,10 @@ exercises/list/cn_types.h We can also write _functions_ on CN-level lists by ordinary functional programming (in a slightly strange, unholy-union-of-C-and-Rust syntax): + +BCP: Surely we've made that point already? + + ```c title="exercises/list/hdtl.h" --8<-- @@ -67,18 +65,16 @@ Finally, we can collect all this stuff into a single header file. (We add the usual C `#ifndef` gorp to avoid complaints from the compiler if it happens to get included twice from the same source file later.) -```c title="exercises/list/headers.verif.h" +```c title="exercises/list/headers.test.h" --8<-- -exercises/list/headers.verif.h +exercises/list/headers.test.h --8<-- ``` - TODO: BCP: The 'return != NULL' should not be needed, but to remove it we need to change the callers of all the allocation functions to check for NULL and exit (which requires adding a spec for exit). - ### Append @@ -95,25 +91,21 @@ exercises/list/append.h --8<-- ``` -Here is a simple destructive `append` function. Note the two uses -of the `unfold` annotation in the body, which are needed to help the -CN typechecker. The `unfold` annotation is an instruction to CN to replace a call to a recursive (CN) function (in this case `append`) -with its definition, and is necessary because CN is unable to automatically determine when and where to expand recursive definitions on its own. - - -BCP: Can someone add a more technical explanation of why they are needed and exactly what they do? - +Here is a simple destructive `append` function. -```c title="exercises/list/append.c" +```c title="exercises/list/append.test.c" --8<-- -exercises/list/append.c +exercises/list/append.test.c --8<-- ``` ### List copy -Here is an allocating list copy function with a pleasantly light -annotation burden. +Here is an allocating list copy function. + + +BCP: `L_` should probably be `L_post` + ```c title="exercises/list/copy.c" --8<-- @@ -124,7 +116,7 @@ exercises/list/copy.c ### Merge sort -BCP: This could use a gentler explanation (probably in pieces) +BCP: This could use a gentler explanation (probably in pieces) Finally, here is a slightly tricky in-place version of merge sort that @@ -133,16 +125,16 @@ alternate cells from the original list and linking them together into two new lists of roughly equal lengths. -BCP: We've heard from more than one reader that this example is particularly hard to digest without some additional help +BCP: We've heard from more than one reader that this example is particularly hard to digest without some additional help -BCP: Nit: Merge multiple requires and ensures clauses into one +BCP: Nit: Merge multiple requires and ensures clauses into one -```c title="exercises/list/mergesort.c" +```c title="exercises/list/mergesort.test.c" --8<-- -exercises/list/mergesort.c +exercises/list/mergesort.test.c --8<-- ``` @@ -181,20 +173,20 @@ exercises/list/free.c _Length with an accumulator_. Add annotations as appropriate: -BCP: Removing / forgetting the unfold in this one gives a truly +BCP: Removing / forgetting the unfold in this one gives a truly - bizarre error message saying that the constraint "n == (n + length(L1))" + bizarre error message saying that the constraint "n == (n + length(L1))" - is unsatisfiable... + is unsatisfiable... -Sainati: when I went through the tutorial, the file provided for this exercise was already "complete" in that +Sainati: when I went through the tutorial, the file provided for this exercise was already "complete" in that - it already had all the necessary annotations present for CN to verify it + it already had all the necessary annotations present for CN to verify it ```c title="exercises/slf_length_acc.c" @@ -202,5 +194,3 @@ Sainati: when I went through the tutorial, the file provided for this exercise w exercises/slf_length_acc.c --8<-- ``` - - diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 3270006c..6c6487e7 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -93,7 +93,7 @@ are less confusingly presented as always required? --> words are common in real C code... --> - +BCP: Do we mean 32-bit word here?? diff --git a/docs/getting-started/tutorials/predicates.md b/docs/getting-started/tutorials/predicates.md index d9a5d3e1..47fcf99a 100644 --- a/docs/getting-started/tutorials/predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -53,9 +53,9 @@ the definition of BothOwned here, how is CN able to prove that `take pv = Owned(p);` type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? -```c title="exercises/slf_incr2.noverif.c" +```c title="exercises/slf_incr2.test.c" --8<-- -exercises/slf_incr2.noverif.c +exercises/slf_incr2.test.c --8<-- ``` diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 0ebe666b..13847f2d 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -170,9 +170,7 @@ solutions/init_array.c ``` - TODO: BCP: Concrete syntax: Why not write something like "unchanged {p,n}" or "unchanged: p,n"? - The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. @@ -182,9 +180,7 @@ The second thing we need to do, however, is less straightforward. Recall that, a **Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. - TODO: BCP: This seems like a good idea! - The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. diff --git a/docs/getting-started/tutorials/verif-external.md b/docs/getting-started/tutorials/verif-external.md index a12bfcaa..d118d876 100644 --- a/docs/getting-started/tutorials/verif-external.md +++ b/docs/getting-started/tutorials/verif-external.md @@ -13,13 +13,11 @@ BCP: This needs to be filled in urgently!! - TODO: BCP: think about capitalization, etc., for lemma names push_lemma should be Push_lemma, I guess? Or lemma_push? snoc_facts should be lemma_Snoc or something others? - ### List reverse @@ -55,12 +53,10 @@ proof of `IntList_rev`. Note the two places where `apply` is used to tell the SMT solver where to pay attention to the lemmas. - TODO: BCP: Why can't it always pay attention to them? (I guess "performance", but at least it would be nice to be able to declare a general scope where a given set of lemmas might be needed, rather than specifying exactly where to use them.) - ```c title="exercises/list/rev.c" @@ -100,16 +96,13 @@ exercises/slf_sized_stack.c ====================================================================== - ## More on CN Annotations -_TODO_: - -- Introduce all the different sorts of CN annotations (e.g., + +TODO: Introduce all the different sorts of CN annotations (e.g., `split_case`) individually with small examples and exercises. - diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md new file mode 100644 index 00000000..ec3891ab --- /dev/null +++ b/docs/getting-started/tutorials/verif-lists.md @@ -0,0 +1,207 @@ +# Lists + + +BCP: Maybe this should be a case study? + + + +BCP: Better intro needed + + +Now it's time to look at some more interesting heap structures. + +To begin with, here is a C definition for linked list cells, together +with allocation and deallocation functions: + +```c title="exercises/list/c_types.verif.h" +--8<-- +exercises/list/c_types.verif.h +--8<-- +``` + + +BCP: Per discussion with Christopher, Cassia, and Daniel, the word "predicate" is quite confusing for newcomers (in logic, predicates do not return things!). A more neutral word might make for significantly easier onboarding. + + +Dhruv: Or no keyword? rems-project/cerberus#304 How about traversal? + + + BCP: No keyword sounds even better. But "traversal" in the interim is not bad. Or maybe "extractor" or something like that? + + +To write specifications for C functions that manipulate lists, we need +to define a CN "predicate" that describes specification-level list +structures, as one would do in ML, Haskell, or Coq. We use the +datatype `List` for CN-level lists. + +Intuitively, the `SLList_At` predicate walks over a singly-linked +pointer structure in the C heap and extracts an `Owned` version of +the CN-level list that it represents. + +```c title="exercises/list/cn_types.h" +--8<-- +exercises/list/cn_types.h +--8<-- +``` + +We can also write _functions_ on CN-level lists by ordinary functional +programming (in a slightly strange, unholy-union-of-C-and-Rust +syntax): + +```c title="exercises/list/hdtl.h" +--8<-- +exercises/list/hdtl.h +--8<-- +``` + +We use the `SLList_At` predicate to specify functions returning the +empty list and the cons of a number and a list. + +```c title="exercises/list/constructors.h" +--8<-- +exercises/list/constructors.h +--8<-- +``` + +Finally, we can collect all this stuff into a single header file. (We +add the usual C `#ifndef` gorp to avoid complaints from the compiler +if it happens to get included twice from the same source file later.) + +```c title="exercises/list/headers.verif.h" +--8<-- +exercises/list/headers.verif.h +--8<-- +``` + + +TODO: BCP: The 'return != NULL' should not be needed, but to remove it +we need to change the callers of all the allocation functions to check +for NULL and exit (which requires adding a spec for exit). + + +### Append + +With this basic infrastructure in place, we can start specifying and +verifying list-manipulating functions. First, `append`. + +Here is its specification (in a separate file, because we'll want to +use it multiple times below.) + +```c title="exercises/list/append.h" +--8<-- +exercises/list/append.h +--8<-- +``` + + +BCP: Here's the first place where the verification version differs. +Tidy the file above and below! + + +Here is a simple destructive `append` function. Note the two uses +of the `unfold` annotation in the body, which are needed to help the +CN typechecker. The `unfold` annotation is an instruction to CN to replace a call to a recursive (CN) function (in this case `append`) +with its definition, and is necessary because CN is unable to automatically determine when and where to expand recursive definitions on its own. + + +BCP: Can someone add a more technical explanation of why they are needed and exactly what they do? + + +```c title="exercises/list/append.verif.c" +--8<-- +exercises/list/append.verif.c +--8<-- +``` + +### List copy + +Here is an allocating list copy function with a pleasantly light +annotation burden. + +```c title="exercises/list/copy.c" +--8<-- +exercises/list/copy.c +--8<-- +``` + +### Merge sort + + +BCP: This could use a gentler explanation (probably in pieces) + + +Finally, here is a slightly tricky in-place version of merge sort that +avoids allocating any new list cells in the splitting step by taking +alternate cells from the original list and linking them together into +two new lists of roughly equal lengths. + + +BCP: We've heard from more than one reader that this example is particularly hard to digest without some additional help + + + +BCP: Nit: Merge multiple requires and ensures clauses into one + + +```c title="exercises/list/mergesort.c" +--8<-- +exercises/list/mergesort.c +--8<-- +``` + +### Exercises + +_Allocating append_. Fill in the CN annotations on +`IntList_append2`. (You will need some in the body as well as at +the top.) + +```c title="exercises/list/append2.c" +--8<-- +exercises/list/append2.c +--8<-- +``` + +Note that it would not make sense to do the usual +functional-programming trick of copying xs but sharing ys. (Why?) + +_Length_. Add annotations as appropriate: + +```c title="exercises/list/length.c" +--8<-- +exercises/list/length.c +--8<-- +``` + +_List deallocation_. Fill in the body of the following procedure and +add annotations as appropriate: + +```c title="exercises/list/free.c" +--8<-- +exercises/list/free.c +--8<-- +``` + +_Length with an accumulator_. Add annotations as appropriate: + + +BCP: Removing / forgetting the unfold in this one gives a truly + + + bizarre error message saying that the constraint "n == (n + length(L1))" + + + is unsatisfiable... + + + +Sainati: when I went through the tutorial, the file provided for this exercise was already "complete" in that + + + it already had all the necessary annotations present for CN to verify it + + +```c title="exercises/slf_length_acc.c" +--8<-- +exercises/slf_length_acc.c +--8<-- +``` diff --git a/docs/getting-started/tutorials/verif-splitcase.md b/docs/getting-started/tutorials/verif-splitcase.md index b128bc01..87c4ab66 100644 --- a/docs/getting-started/tutorials/verif-splitcase.md +++ b/docs/getting-started/tutorials/verif-splitcase.md @@ -7,9 +7,9 @@ This section needs writing... To verify the `slf_incr2` example, we need one more CN annotation in the body of the -```c title="exercises/slf_incr2.noverif.c" +```c title="exercises/slf_incr2.verif.c" --8<-- -exercises/slf_incr2.noverif.c +exercises/slf_incr2.verif.c --8<-- ``` diff --git a/src/exercises/array_load.noverif.c b/src/exercises/array_load.test.c similarity index 100% rename from src/exercises/array_load.noverif.c rename to src/exercises/array_load.test.c diff --git a/src/exercises/cn_malloc.h b/src/exercises/cn_malloc.h new file mode 100644 index 00000000..65048287 --- /dev/null +++ b/src/exercises/cn_malloc.h @@ -0,0 +1,4 @@ +#include + +extern void* cn_malloc(size_t size); +extern void cn_free_sized(void *ptr, size_t size); diff --git a/src/exercises/list/append.test.c b/src/exercises/list/append.test.c new file mode 100644 index 00000000..dd28c08e --- /dev/null +++ b/src/exercises/list/append.test.c @@ -0,0 +1,17 @@ +#include "./headers.test.h" +#include "./append.h" + +struct sllist* IntList_append(struct sllist* xs, struct sllist* ys) +/*@ requires take L1 = SLList_At(xs); + take L2 = SLList_At(ys); @*/ +/*@ ensures take L3 = SLList_At(return); + L3 == Append(L1, L2); @*/ +{ + if (xs == 0) { + return ys; + } else { + struct sllist *new_tail = IntList_append(xs->tail, ys); + xs->tail = new_tail; + return xs; + } +} diff --git a/src/exercises/list/append.c b/src/exercises/list/append.verif.c similarity index 100% rename from src/exercises/list/append.c rename to src/exercises/list/append.verif.c diff --git a/src/exercises/list/c_types.test.h b/src/exercises/list/c_types.test.h new file mode 100644 index 00000000..8cd0ded2 --- /dev/null +++ b/src/exercises/list/c_types.test.h @@ -0,0 +1,20 @@ +#include "../cn_malloc.h" + +struct sllist { + int head; + struct sllist* tail; +}; + +struct sllist *malloc__sllist() +/*@ ensures take R = Block(return); +@*/ +{ + return cn_malloc(sizeof(struct sllist)); +} + +void free__sllist (struct sllist *p) +/*@ requires take P = Block(p); +@*/ +{ + cn_free_sized(p, sizeof(struct sllist)); +} diff --git a/src/exercises/list/c_types.h b/src/exercises/list/c_types.verif.h similarity index 100% rename from src/exercises/list/c_types.h rename to src/exercises/list/c_types.verif.h diff --git a/src/exercises/list/headers.test.h b/src/exercises/list/headers.test.h new file mode 100644 index 00000000..828baf0d --- /dev/null +++ b/src/exercises/list/headers.test.h @@ -0,0 +1,9 @@ +#ifndef _LIST_H +#define _LIST_H + +#include "./c_types.test.h" +#include "./cn_types.h" +#include "./hdtl.h" +#include "./constructors.h" + +#endif //_LIST_H diff --git a/src/exercises/list/headers.verif.h b/src/exercises/list/headers.verif.h index 5f787e85..6bc5f478 100644 --- a/src/exercises/list/headers.verif.h +++ b/src/exercises/list/headers.verif.h @@ -1,7 +1,7 @@ #ifndef _LIST_H #define _LIST_H -#include "./c_types.h" +#include "./c_types.verif.h" #include "./cn_types.h" #include "./hdtl.h" #include "./constructors.h" diff --git a/src/exercises/list/mergesort.brokentest.c b/src/exercises/list/mergesort.brokentest.c new file mode 100644 index 00000000..b382c6f1 --- /dev/null +++ b/src/exercises/list/mergesort.brokentest.c @@ -0,0 +1,124 @@ +#include "./headers.test.h" + +/*@ +function [rec] ({datatype List fst, datatype List snd}) + split (datatype List xs) +{ + match xs { + Nil {} => { + {fst: Nil{}, snd: Nil{}} + } + Cons {Head: h1, Tail: Nil{}} => { + {fst: Nil{}, snd: xs} + } + Cons {Head: h1, Tail: Cons {Head : h2, Tail : tl2 }} => { + let P = split(tl2); + {fst: Cons { Head: h1, Tail: P.fst}, + snd: Cons { Head: h2, Tail: P.snd}} + } + } +} + +function [rec] (datatype List) merge(datatype List xs, datatype List ys) { + match xs { + Nil {} => { ys } + Cons {Head: x, Tail: xs1} => { + match ys { + Nil {} => { xs } + Cons{ Head: y, Tail: ys1} => { + (x < y) ? + (Cons{ Head: x, Tail: merge(xs1, ys) }) + : (Cons{ Head: y, Tail: merge(xs, ys1) }) + } + } + } + } +} + +function [rec] (datatype List) Mergesort(datatype List xs) { + match xs { + Nil{} => { xs } + Cons{Head: x, Tail: Nil{}} => { xs } + Cons{Head: x, Tail: Cons{Head: y, Tail: zs}} => { + let P = split(xs); + let L1 = Mergesort(P.fst); + let L2 = Mergesort(P.snd); + merge(L1, L2) + } + } +} +@*/ + +struct sllist_pair { + struct sllist* fst; + struct sllist* snd; +}; + +struct sllist_pair split(struct sllist *xs) +/*@ requires take Xs = SLList_At(xs); + ensures take Ys = SLList_At(return.fst); + take Zs = SLList_At(return.snd); + {fst: Ys, snd: Zs} == split(Xs); @*/ +{ + if (xs == 0) { + struct sllist_pair r = {.fst = 0, .snd = 0}; + return r; + } else { + struct sllist *cdr = xs -> tail; + if (cdr == 0) { + struct sllist_pair r = {.fst = 0, .snd = xs}; + return r; + } else { + struct sllist_pair p = split(cdr->tail); + xs->tail = p.fst; + cdr->tail = p.snd; + struct sllist_pair r = {.fst = xs, .snd = cdr}; + return r; + } + } +} + +struct sllist* merge(struct sllist *xs, struct sllist *ys) +/*@ requires take Xs = SLList_At(xs); + take Ys = SLList_At(ys); + ensures take Zs = SLList_At(return); + Zs == merge(Xs, Ys); @*/ +{ + if (xs == 0) { + return ys; + } else { + if (ys == 0) { + return xs; + } else { + if (xs->head < ys->head) { + struct sllist *zs = merge(xs->tail, ys); + xs->tail = zs; + return xs; + } else { + struct sllist *zs = merge(xs, ys->tail); + ys->tail = zs; + return ys; + } + } + } +} + +struct sllist* mergesort(struct sllist *xs) +/*@ requires take Xs = SLList_At(xs); + ensures take Ys = SLList_At(return); + Ys == Mergesort(Xs); @*/ +{ + if (xs == 0) { + return xs; + } else { + struct sllist *tail = xs->tail; + if (tail == 0) { + return xs; + } else { + struct sllist_pair p = split(xs); + p.fst = mergesort(p.fst); + p.snd = mergesort(p.snd); + return merge(p.fst, p.snd); + } + } +} diff --git a/src/exercises/list/mergesort.c b/src/exercises/list/mergesort.verif.c similarity index 100% rename from src/exercises/list/mergesort.c rename to src/exercises/list/mergesort.verif.c diff --git a/src/exercises/queue/cn_types_3.h b/src/exercises/queue/cn_types_3.test.h similarity index 100% rename from src/exercises/queue/cn_types_3.h rename to src/exercises/queue/cn_types_3.test.h diff --git a/src/exercises/queue/cn_types_3.verif.h b/src/exercises/queue/cn_types_3.verif.h new file mode 100644 index 00000000..73bfca7f --- /dev/null +++ b/src/exercises/queue/cn_types_3.verif.h @@ -0,0 +1,13 @@ +/*@ +predicate (datatype List) QueueAux (pointer f, pointer b) { + if (ptr_eq(f,b)) { + return Nil{}; + } else { + take F = Owned(f); + assert (!is_null(F.next)); + assert (ptr_eq(F.next, b) || !addr_eq(F.next, b)); + take B = QueueAux(F.next, b); + return Cons{Head: F.first, Tail: B}; + } +} +@*/ diff --git a/src/exercises/queue/headers.test.h b/src/exercises/queue/headers.test.h new file mode 100644 index 00000000..00fca88f --- /dev/null +++ b/src/exercises/queue/headers.test.h @@ -0,0 +1,11 @@ +#include "../list/c_types.h" +#include "../list/cn_types.h" +#include "../list/hdtl.h" +#include "../list/snoc.h" + +#include "./c_types.h" +#include "./cn_types_1.h" +#include "./cn_types_2.test.h" +#include "./cn_types_3.test.h" + +#include "./allocation.verif.h" diff --git a/src/exercises/queue/headers.verif.h b/src/exercises/queue/headers.verif.h index cf41f233..c6934c4e 100644 --- a/src/exercises/queue/headers.verif.h +++ b/src/exercises/queue/headers.verif.h @@ -1,11 +1,11 @@ -#include "../list/c_types.h" +#include "../list/c_types.verif.h" #include "../list/cn_types.h" #include "../list/hdtl.h" #include "../list/snoc.h" #include "./c_types.h" #include "./cn_types_1.h" -#include "./cn_types_2.h" -#include "./cn_types_3.h" +#include "./cn_types_2.h" +#include "./cn_types_3.verif.h" -#include "./allocation.verif.h" +#include "./allocation.verif.h" diff --git a/src/exercises/slf_incr2.noverif.c b/src/exercises/slf_incr2.test.c similarity index 100% rename from src/exercises/slf_incr2.noverif.c rename to src/exercises/slf_incr2.test.c From 5a65e9b046e93714907d3e5af2e437e4c21be2c3 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 08:32:44 -0400 Subject: [PATCH 061/158] Renaming CN keywords --- NAMING-CONVENTIONS.md | 4 +- .../case-studies/doubly-linked-lists.md | 2 +- .../case-studies/the-runway.md | 2 +- docs/getting-started/tutorials/alloc.md | 36 ++-- docs/getting-started/tutorials/arrays.md | 8 +- docs/getting-started/tutorials/block.md | 36 ++-- docs/getting-started/tutorials/compound.md | 20 +- docs/getting-started/tutorials/lists.md | 2 +- docs/getting-started/tutorials/numeric.md | 4 +- docs/getting-started/tutorials/pointers.md | 28 +-- docs/getting-started/tutorials/predicates.md | 4 +- docs/getting-started/tutorials/todo.md | 2 +- .../getting-started/tutorials/verif-arrays.md | 66 +++--- docs/getting-started/tutorials/verif-lists.md | 2 +- docs/reference/README.md | 4 +- docs/specifications/conditions.md | 12 +- .../specifications/function-specifications.md | 20 +- docs/specifications/loop-invariants.md | 8 +- .../error-proof/00004-simple-lifetimes.c | 4 +- .../error-proof/00006-lifetimes-broken.c | 4 +- .../SAW/broken/error-cerberus/00001.swap.c | 30 +-- .../SAW/broken/error-cerberus/00008.salsa20.c | 22 +- .../SAW/broken/error-proof/00003.point.c | 32 +-- .../error-proof/00004.tutorial-dotprod.c | 14 +- .../broken/error-proof/00077.err1.c | 6 +- .../broken/error-timeout/00182.timeout.c | 2 +- .../c-testsuite/working/00015.working.c | 4 +- .../c-testsuite/working/00016.working.c | 2 +- .../c-testsuite/working/00032.c | 4 +- .../c-testsuite/working/00033.working.c | 8 +- .../c-testsuite/working/00037.working.c | 2 +- .../c-testsuite/working/00072.working.c | 2 +- .../c-testsuite/working/00078.working.c | 4 +- .../c-testsuite/working/00090.working.c | 6 +- src/example-archive/coq-lemmas/README.md | 2 +- .../dafny-tutorial/working/binary_search.c | 8 +- .../dafny-tutorial/working/linear_search.c | 8 +- .../dafny-tutorial/working/multiple_returns.c | 4 +- .../00008_overload_dyn_method.c | 6 +- .../broken/error-proof/00002_side_effects.c | 8 +- .../broken/error-proof/00003_break.c | 6 +- .../broken/error-proof/00006_callbacks.c | 8 +- .../broken/error-proof/00007_static_init.c | 8 +- .../working/00004_exceptions.c | 12 +- src/example-archive/open-sut/working/mps_1.c | 16 +- .../broken/error-proof/ownership_neg_1.c | 4 +- .../broken/error-proof/ownership_neg_2.c | 4 +- .../broken/error-proof/ownership_neg_3.c | 8 +- .../should-fail/working/c_sequencing_race.c | 4 +- .../broken/error-cerberus/pred_1.c | 4 +- .../broken/error-proof/ownership_1.c | 6 +- .../error-timeout/overflow_timeout_3var.c | 8 +- .../error-timeout/overflow_timeout_4var.c | 8 +- .../simple-examples/working/array_1.c | 6 +- .../simple-examples/working/array_2.c | 6 +- .../simple-examples/working/array_3.c | 8 +- .../simple-examples/working/array_read.c | 8 +- .../simple-examples/working/assert_2.c | 8 +- .../simple-examples/working/assert_3.c | 12 +- .../simple-examples/working/cast_4.c | 4 +- .../simple-examples/working/effect_1.c | 8 +- .../simple-examples/working/free_1.c | 8 +- .../simple-examples/working/list_2.c | 2 +- .../simple-examples/working/list_3.c | 4 +- .../simple-examples/working/list_preds.h | 2 +- .../simple-examples/working/malloc_1.c | 6 +- .../simple-examples/working/pred_2.c | 12 +- .../simple-examples/working/struct_1.c | 4 +- .../simple-examples/working/swap_1.c | 8 +- .../simple-examples/working/write_1.c | 4 +- .../simple-examples/working/write_2.c | 8 +- .../simple-examples/working/write_3.c | 4 +- .../simple-examples/working/write_4.c | 8 +- .../simple-examples/working/write_5.c | 16 +- src/exercises/abs_mem.c | 4 +- src/exercises/abs_mem_struct.c | 8 +- src/exercises/add_read.c | 8 +- src/exercises/add_two_array.c | 8 +- src/exercises/array_load.c | 6 +- src/exercises/array_load.test.c | 4 +- src/exercises/array_load2.c | 6 +- src/exercises/bcp_framerule.c | 12 +- src/exercises/dll/dllist_and_int.h | 4 +- src/exercises/dll/malloc_free.h | 4 +- src/exercises/dll/predicates.h | 6 +- src/exercises/dll/remove.c | 2 +- src/exercises/free.h | 4 +- src/exercises/init_array.c | 8 +- src/exercises/init_array2.c | 12 +- src/exercises/init_array_rev.c | 12 +- src/exercises/init_point.c | 8 +- src/exercises/list/c_types.test.h | 4 +- src/exercises/list/c_types.verif.h | 4 +- src/exercises/list/cn_types.h | 2 +- src/exercises/malloc.h | 4 +- src/exercises/malloc_alt.h | 4 +- src/exercises/queue/allocation.verif.h | 8 +- src/exercises/queue/cn_types_1.h | 2 +- src/exercises/queue/cn_types_2.h | 2 +- src/exercises/queue/cn_types_3.test.h | 2 +- src/exercises/queue/cn_types_3.verif.h | 2 +- src/exercises/queue/pop_lemma.h | 4 +- src/exercises/queue/pop_unified.c | 6 +- src/exercises/queue/push_induction.c | 6 +- src/exercises/queue/push_lemma.h | 2 +- src/exercises/read.broken.c | 2 +- src/exercises/read.c | 4 +- src/exercises/read2.c | 4 +- src/exercises/ref.h | 4 +- src/exercises/slf0_basic_incr.c | 4 +- src/exercises/slf0_basic_incr.signed.broken.c | 4 +- src/exercises/slf0_basic_incr.signed.c | 4 +- src/exercises/slf0_incr.broken.c | 4 +- src/exercises/slf10_basic_ref.c | 2 +- src/exercises/slf11_basic_ref_greater.c | 6 +- .../slf12_basic_ref_greater_abstract.c | 6 +- src/exercises/slf13_basic_ref_with_frame.c | 6 +- src/exercises/slf17_get_and_free.c | 2 +- src/exercises/slf3_basic_inplace_double.c | 4 +- src/exercises/slf4_basic_incr_two.c | 8 +- .../slf5_basic_aliased_call.broken.c | 4 +- .../slf6_basic_incr_two_aliased_call.c | 8 +- src/exercises/slf7_basic_incr_first.c | 12 +- src/exercises/slf8_basic_transfer.c | 8 +- src/exercises/slf9_basic_transfer_aliased.c | 4 +- src/exercises/slf_incr2.c | 14 +- src/exercises/slf_incr2.test.c | 14 +- src/exercises/slf_incr2_alias.c | 20 +- src/exercises/slf_incr2_noalias.c | 8 +- src/exercises/slf_length_acc.c | 4 +- src/exercises/slf_quadruple_mem.c | 4 +- src/exercises/slf_ref_greater.c | 6 +- src/exercises/slf_sized_stack.c | 6 +- src/exercises/swap.c | 8 +- src/exercises/swap_array.c | 8 +- src/exercises/transpose.broken.c | 4 +- src/exercises/transpose.c | 4 +- src/exercises/transpose2.c | 12 +- src/exercises/zero.c | 4 +- src/old/asciidoc_to_md.md | 2 +- src/old/asciidoctor.css | 42 ++-- src/old/tutorial.md | 204 +++++++++--------- src/underconstruction/bst/c_types.h | 4 +- src/underconstruction/bst/cn_getters.h | 2 +- src/underconstruction/bst/cn_types.h | 2 +- src/underconstruction/bst/getter.c | 16 +- 146 files changed, 670 insertions(+), 670 deletions(-) diff --git a/NAMING-CONVENTIONS.md b/NAMING-CONVENTIONS.md index 55051066..6e0f2233 100644 --- a/NAMING-CONVENTIONS.md +++ b/NAMING-CONVENTIONS.md @@ -40,8 +40,8 @@ aim for maximal correspondence between to a final sequence `L_post` such that `L == L_post`. (Moreover, it returns a new sequence `Ret` with `L == Ret`.) -- Predicates that extract some structure from the heap should be named - the same as the structure they extract, plus the suffix `_At`. +- Predicates that focus some structure from the heap should be named + the same as the structure they focus, plus the suffix `_At`. E.g., the result type of the `Queue` predicate is also called `Queue_At`. diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index dbd592e8..b57a683d 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -148,7 +148,7 @@ list before we return, and will claim we are missing a resource for returning. The `split_case` on `is_null(n->next->next)` is similar, but for unpacking the `Own_Forwards` predicate. Note that we have to go one more node forward to make sure that everything past `n->next` -is still owned at the end of the function. +is still RW at the end of the function. Now let's look at the `remove` operation. Traditionally, a `remove` operation for a list returns the integer that was removed. However we diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 0bdb7442..5fe1e8a1 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -205,5 +205,5 @@ alternative: [](https://www.sphinx-doc.org/en/master/index.html) Misc notes: -- Nb: take V = Owned(p) === p |-t-> V +- Nb: take V = RW(p) === p |-t-> V --> diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index 7632d507..5e279f2e 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -2,42 +2,42 @@ XXXXXXXXXXXXXXXXXXX intro needed -## Block resources +## W resources -Aside from the `Owned` resources seen so far, CN has another -built-in type of resource called `Block`. Given a C-type `T` and -pointer `p`, `Block(p)` asserts the same ownership as -`Owned(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `Owned`, `Block` memory is not assumed +Aside from the `RW` resources seen so far, CN has another +built-in type of resource called `W`. Given a C-type `T` and +pointer `p`, `W(p)` asserts the same ownership as +`RW(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `RW`, `W` memory is not assumed to be initialised. CN uses this distinction to prevent reads from uninitialised memory: - A read at C-type `T` and pointer `p` requires a resource - `Owned(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `Owned` resource unchanged. + `RW(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `RW` resource unchanged. - A write at C-type `T` and pointer `p` needs only a -`Block(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `Block` resource -(it destroys it) and returns a new resource `Owned(p)` with the +`W(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `W` resource +(it destroys it) and returns a new resource `RW(p)` with the value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. -BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. +BCP: Not sure I understand "returns a new resource `RW(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. -Since `Owned` carries the same ownership as `Block`, just with the -additional information that the `Owned` memory is initalised, a -resource `Owned(p)` is "at least as good" as `Block(p)` — -an `Owned(p)` resource can be used whenever `Block(p)` is +Since `RW` carries the same ownership as `W`, just with the +additional information that the `RW` memory is initalised, a +resource `RW(p)` is "at least as good" as `W(p)` — +an `RW(p)` resource can be used whenever `W(p)` is needed. For instance CN’s type checking of a write to `p` requires a -`Block(p)`, but if an `Owned(p)` resource is what is +`W(p)`, but if an `RW(p)` resource is what is available, this can be used just the same. This allows an already-initialised memory cell to be over-written again. -Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. +Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. ## Allocation diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index ec3228ea..ca34e3b7 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -6,7 +6,7 @@ To support reasoning about code manipulating arrays and computed pointers, CN ha ```c each (i32 i; 0i32 <= i && i < 10i32) -{ Owned(array_shift(p,i)) } +{ RW(array_shift(p,i)) } ``` In detail, this can be read as follows: @@ -15,7 +15,7 @@ In detail, this can be read as follows: - if `i` is between `0` and `10`, … -- assert ownership of a resource `Owned` … +- assert ownership of a resource `RW` … - for cell `i` of the array with base-address `p`. @@ -51,8 +51,8 @@ exercises/array_load.test.c The CN precondition requires -- ownership of the array on entry — one `Owned` resource for each array index between `0` and `n` — and -- that `i` lies within the range of owned indices. +- ownership of the array on entry — one `RW` resource for each array index between `0` and `n` — and +- that `i` lies within the range of RW indices. On exit the array ownership is returned again. diff --git a/docs/getting-started/tutorials/block.md b/docs/getting-started/tutorials/block.md index 5b41e05a..c40740cc 100644 --- a/docs/getting-started/tutorials/block.md +++ b/docs/getting-started/tutorials/block.md @@ -1,37 +1,37 @@ -# Block resources +# W resources -Aside from the `Owned` resources seen so far, CN has another -built-in type of resource called `Block`. Given a C-type `T` and -pointer `p`, `Block(p)` asserts the same ownership as -`Owned(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `Owned`, `Block` memory is not assumed +Aside from the `RW` resources seen so far, CN has another +built-in type of resource called `W`. Given a C-type `T` and +pointer `p`, `W(p)` asserts the same ownership as +`RW(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `RW`, `W` memory is not assumed to be initialised. CN uses this distinction to prevent reads from uninitialised memory: - A read at C-type `T` and pointer `p` requires a resource - `Owned(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `Owned` resource unchanged. + `RW(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `RW` resource unchanged. - A write at C-type `T` and pointer `p` needs only a -`Block(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `Block` resource -(it destroys it) and returns a new resource `Owned(p)` with the +`W(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `W` resource +(it destroys it) and returns a new resource `RW(p)` with the value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. -BCP: Not sure I understand "returns a new resource `Owned(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. +BCP: Not sure I understand "returns a new resource `RW(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. -Since `Owned` carries the same ownership as `Block`, just with the -additional information that the `Owned` memory is initalised, a -resource `Owned(p)` is "at least as good" as `Block(p)` — -an `Owned(p)` resource can be used whenever `Block(p)` is +Since `RW` carries the same ownership as `W`, just with the +additional information that the `RW` memory is initalised, a +resource `RW(p)` is "at least as good" as `W(p)` — +an `RW(p)` resource can be used whenever `W(p)` is needed. For instance CN’s type checking of a write to `p` requires a -`Block(p)`, but if an `Owned(p)` resource is what is +`W(p)`, but if an `RW(p)` resource is what is available, this can be used just the same. This allows an already-initialised memory cell to be over-written again. -Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. +Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index 319ceff2..ed46235d 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -3,17 +3,17 @@ Verifying CN programs involving structured objects raises a number of new issues. -## Compound Owned and Block resources +## Compound RW and W resources While one might like to think of a struct as a single (compound) object that is manipulated as a whole, C permits more flexible struct manipulation: given a struct pointer, programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. -CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `Owned` and `Block` are defined inductively on the structure of the C-type `T`. +CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `RW` and `W` are defined inductively on the structure of the C-type `T`. -For struct types `T`, the `Owned` resource is defined as the collection of `Owned` resources for its members (as well as `Block` resources for any padding bytes in-between them). The resource `Block`, similarly, is made up of `Block` resources for all members (and padding bytes). +For struct types `T`, the `RW` resource is defined as the collection of `RW` resources for its members (as well as `W` resources for any padding bytes in-between them). The resource `W`, similarly, is made up of `W` resources for all members (and padding bytes). To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. -Recall the function `zero` from our earlier exercise. It takes an `unsigned int` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. +Recall the function `zero` from our earlier exercise. It takes an `unsigned int` pointer to uninitialised memory, with `W` ownership, and initialises the value to zero, returning an `RW` resource with output `0`. Now consider the function `init_point`, shown below, which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. @@ -23,9 +23,9 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `Block(p)`. The `zero` function, however, works on `unsigned int` pointers and requires `Block` ownership. +As stated in its precondition, `init_point` receives ownership `W(p)`. The `zero` function, however, works on `unsigned int` pointers and requires `W` ownership. -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. +CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `W(p)` into a `W` for member `x` and a `W` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `RW` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `RW(p)`, CN combines these back into a compound resource. The resulting `RW` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. ## Resource inference @@ -43,11 +43,11 @@ exercises/transpose.broken.c --8<-- ``` -The precondition of `transpose` asserts ownership of an `Owned(p)` resource. The error report now instead lists under "`Available resources`" two resources: +The precondition of `transpose` asserts ownership of an `RW(p)` resource. The error report now instead lists under "`Available resources`" two resources: -- `Owned(member_shift(p, x))` with output `P.x` and +- `RW(member_shift(p, x))` with output `P.x` and -- `Owned(member_shift(p, y))` with output `P.y` +- `RW(member_shift(p, y))` with output `P.y` BCP: We should verify that it really does say this. @@ -55,7 +55,7 @@ BCP: We should verify that it really does say this. Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. -When the function returns, the two member resources are recombined "`on demand`" to satisfy the postcondition `Owned(p)`. +When the function returns, the two member resources are recombined "`on demand`" to satisfy the postcondition `RW(p)`. ### Exercises diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index 3e79cdb7..12385479 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -29,7 +29,7 @@ structures, as one would do in ML, Haskell, or Coq. We use the datatype `List` for CN-level lists. Intuitively, the `SLList_At` predicate walks over a singly-linked -pointer structure in the C heap and extracts an `Owned` version of +pointer structure in the C heap and extracts an `RW` version of the CN-level list that it represents. ```c title="exercises/list/cn_types.h" diff --git a/docs/getting-started/tutorials/numeric.md b/docs/getting-started/tutorials/numeric.md index a65e6fd7..2feb7844 100644 --- a/docs/getting-started/tutorials/numeric.md +++ b/docs/getting-started/tutorials/numeric.md @@ -159,7 +159,7 @@ statement, CN lists the typechecked sub-expressions, and the memory accesses and function calls within these. In our example, there is only one possible control-flow path: entering -the function body (section "`function body`") and executing the block +the function body (section "`function body`") and executing the W from lines 2 to 4, followed by the return statement at line 3. The entry for the latter contains the sequence of sub-expressions in the return statement, including reads of the variables `x` and `y`. @@ -196,7 +196,7 @@ whatever installed on your system.) _Proof context._ The second section, below the error trace, lists the proof context CN has reached along this control-flow path. -"`Available resources`" lists the owned resources, as discussed in later sections. +"`Available resources`" lists the RW resources, as discussed in later sections. "`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 6c6487e7..ce9ed74d 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -16,7 +16,7 @@ - abs_mem (this doesn't work with unsigned ints, but we can use the other examples from the previous section) - slf0_basic_incr_signed.c - shows the difference between Block and Owned + shows the difference between W and RW - exercises - zero.c - basic_inplace_double.c involves UB, so skip it or (maybe @@ -56,16 +56,16 @@ function read, file ./read-exec.c, line 18 ************************************************************ function read, file ./read-exec.c, line 18 Load failed. - ==> 0x122592a09[0] (0x122592a09) not owned + ==> 0x122592a09[0] (0x122592a09) not RW ``` For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. We next explain how to represent this permission. -## Owned resources +## RW resources -Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts +Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type `T`. @@ -99,12 +99,12 @@ are less confusingly presented as always required? --> annotations...? --> In this example, we can ensure the safe execution of `read` by adding -a precondition that requires ownership of `Owned(p)`, as +a precondition that requires ownership of `RW(p)`, as shown below. (The `take ... =` part will be explained shortly.) Since reading the pointer does not disturb its value, we can also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of -another `Owned(p)` resource. +another `RW(p)` resource. ```c title="solutions/read.c" --8<-- @@ -115,9 +115,9 @@ solutions/read.c This specification can be read as follows: - any function calling `read` has to be able to provide a resource - `Owned(p)` to pass into `read`, and + `RW(p)` to pass into `read`, and -- the caller will receive back a resource `Owned(p)` when +- the caller will receive back a resource `RW(p)` when `read` returns. ## Pointee values @@ -177,7 +177,7 @@ exercises/slf0_basic_incr.signed.c --8<-- ``` -In the precondition we assert ownership of resource `Owned(p)`, +In the precondition we assert ownership of resource `RW(p)`, binding its output/pointee value to `P`, and use `P` to specify that `p` must point to a sufficiently small value at the start of the function so as not to overflow when incremented. The postcondition @@ -223,16 +223,16 @@ BCP: Explain what that means. Update if the output format changes. -Given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. +Given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the RW memory or otherwise dispose of it. In CN this is a type error. CN requires that every resource passed into a function has to be either -_returned_ to the caller or else _destroyed_ by deallocating the owned area of +_returned_ to the caller or else _destroyed_ by deallocating the RW area of memory (as we shall see later). CN’s motivation for this choice is its focus on low-level systems software in which memory is managed manually; in this context, memory leaks are typically very undesirable. @@ -283,11 +283,11 @@ ownership of `p`, with output `P_post`, and asserts the coordinates have been swapped, by referring to the members of `P` and `P_post` individually. -The reason `Owned` needs a C-type annotation is so that it can (a) +The reason `RW` needs a C-type annotation is so that it can (a) figure out the size of the sub-heap being claimed and (b) figure out how one may need to destructure the type (unions, struct fields and padding, arrays). The relationship is that for `take x = -Owned(expr)` we have `expr : pointer, x : to_basetype(ct)`. +RW(expr)` we have `expr : pointer, x : to_basetype(ct)`. There is a design decision to consider here rems-project/cerberus#349 diff --git a/docs/getting-started/tutorials/predicates.md b/docs/getting-started/tutorials/predicates.md index 47fcf99a..81b3394b 100644 --- a/docs/getting-started/tutorials/predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -37,7 +37,7 @@ This version does correctly state that the final values of `p` and `q` are,m res Sainati: I think it would be useful here to add an explanation for how CN's type checking works. - For example, in the definition of BothOwned here, how is CN able to prove that `take pv = Owned(p);` + For example, in the definition of BothOwned here, how is CN able to prove that `take pv = RW(p);` type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? @@ -50,7 +50,7 @@ postconditions: Sainati: I think it would be useful here to add an explanation for how CN's type checking works. For example, in the definition of BothOwned here, how is CN able to prove that `take -pv = Owned(p);` type checks, since all we know about `p` +pv = RW(p);` type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? ```c title="exercises/slf_incr2.test.c" diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 25d1540b..eeeab28c 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -22,7 +22,7 @@ - Fix the top-level README.md with correct names for chapters - And add chapters to the top-level nav file - rename `unsigned int` to `unsigned` globally? -- rewrite `Owned` to `Owned` globally (and similar for +- rewrite `RW` to `RW` globally (and similar for other single-word types) - Write a section on how to do unit testing, once the process is a little more user-friendly (see `overview-fulminate.md`). Make sure diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 13847f2d..a1c379cd 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -18,16 +18,16 @@ cn verify solutions/array_load.broken.c build/solutions/array_load.broken.c:5:10: error: Missing resource for reading return p[i]; ^~~~ -Resource needed: Owned(array_shift(p, (u64)i)) +Resource needed: RW(array_shift(p, (u64)i)) ``` -The reason is that, when searching for a required resource, such as the `Owned` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. +The reason is that, when searching for a required resource, such as the `RW` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. BCP: This is more verification-relevant -To make the `Owned` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`extract`" ownership for index `i` out of the iterated resource. +To make the `RW` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`focus`" ownership for index `i` out of the iterated resource. ```c title="exercises/array_load.c" --8<-- @@ -35,10 +35,10 @@ exercises/array_load.c --8<-- ``` -Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: +Here the CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits the iterated resource into two: ```c -each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } +each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) } ``` is split into @@ -46,19 +46,19 @@ is split into 1. the instantiation of the iterated resource at `i` ```c -Owned(array_shift(p,i)) +RW(array_shift(p,i)) ``` 2. the remainder of the iterated resource, the ownership for all indices except `i` ```c each(i32 j; 0i32 <= j && j < n && j != i) - { Owned(array_shift(p,j)) } + { RW(array_shift(p,j)) } ``` -After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. +After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `focus` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. -Following an `extract` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. +Following an `focus` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. So far the specification only guarantees safe execution but does not specify the behaviour of `read`. To address this, let’s return to @@ -66,9 +66,9 @@ the iterated resources in the function specification. When we specify `take A = each ...` here, what is `A`? In CN, the output of an iterated resource is a _map_ from indices to resource outputs. In this example, where index `j` has CN type `i32` and the iterated -resource is `Owned`, the output `A` is a map from `i32` +resource is `RW`, the output `A` is a map from `i32` indices to `i32` values — CN type `map`. If the type of -`j` was `i64` and the resource `Owned`, `A` would have +`j` was `i64` and the resource `RW`, `A` would have type `map`. We can use this to refine our specification with information about the functional behaviour of `read`. @@ -79,7 +79,7 @@ exercises/array_load2.c --8<-- ``` -We specify that `read` does not change the array — the outputs of `Owned`, +We specify that `read` does not change the array — the outputs of `RW`, `A` and `A_post`, taken before and after running the function, are the same — and that the value returned is `A[i]`. @@ -100,7 +100,7 @@ exercises/add_two_array.c ``` -BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the extract declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) +BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the focus declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) @@ -123,18 +123,18 @@ this is just yet another symptom of my imperfecdt understanding of how the numeric stuff works. void swap_array (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) - /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; 0i32 <= i && i < n; 0i32 <= j && j < n; j != i; - take xi = Owned(array_shift(p,i)); - take xj = Owned(array_shift(p,j)) - ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + take xi = RW(array_shift(p,i)); + take xj = RW(array_shift(p,j)) + ensures take a2 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; a1[i:xj][j:xi] == a2 @*/ { - extract Owned, i; - extract Owned, j; + focus RW, i; + focus RW, j; unsigned int tmp = p[i]; p[i] = p[j]; p[j] = tmp; @@ -145,7 +145,7 @@ the numeric stuff works. The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. -In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all owned resources and the constraints required to verify each iteration of the loop. +In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all RW resources and the constraints required to verify each iteration of the loop. Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. @@ -159,7 +159,7 @@ exercises/init_array.c --8<-- ``` -If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `Owned` resource -- one `Owned` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. +If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `RW` resource -- one `RW` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). @@ -183,13 +183,13 @@ The second thing we need to do, however, is less straightforward. Recall that, a TODO: BCP: This seems like a good idea! -The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. +The final piece needed in the verification is an `focus` statement, as used in the previous examples: to separate the individual `RW` resource for index `j` out of the iterated `RW` resource and make it available to the resource inference, we specify `focus RW, j;`. -With the `inv` and `extract` statements in place, CN accepts the function. +With the `inv` and `focus` statements in place, CN accepts the function. ### Second loop example -The specification of `init_array` is overly strong: it requires an iterated `Owned` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `Block` resource for the array should also be sufficient. The modified specification is then as follows. +The specification of `init_array` is overly strong: it requires an iterated `RW` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `W` resource for the array should also be sufficient. The modified specification is then as follows. ```c title="exercises/init_array2.c" --8<-- @@ -197,7 +197,7 @@ exercises/init_array2.c --8<-- ``` -This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `Block` to `Owned` "`state`", so that on function return the full array is initialised. (Recall that stores only require `Block` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) +This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `W` to `RW` "`state`", so that on function return the full array is initialised. (Recall that stores only require `W` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) To verify this modified example we again need a loop Invariant. But this time the loop invariant is more involved: since each iteration of @@ -205,7 +205,7 @@ the loop initialises one more array cell, the loop invariant has to do precise book-keeping of the initialisation status of the different sections of the array. -To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `Owned` resource, for all other array indices we have the (unchanged) `Block` ownership. +To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `RW` resource, for all other array indices we have the (unchanged) `W` ownership. ```c title="solutions/init_array2.c" --8<-- @@ -215,21 +215,21 @@ solutions/init_array2.c Let's go through this line-by-line: -- We assert ownership of an iterated `Owned` resource, one for each index `i` strictly smaller than loop variable `j`. +- We assert ownership of an iterated `RW` resource, one for each index `i` strictly smaller than loop variable `j`. -- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `Block` resource. +- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `W` resource. - As in the previous example, we assert `p` and `n` are unchanged. -- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `Owned` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. +- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `RW` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. -As before, we also have to instruct CN to `extract` ownership of individual array cells out of the iterated resources: +As before, we also have to instruct CN to `focus` ownership of individual array cells out of the iterated resources: -- to allow CN to extract the individual `Block` to be written, we use `extract Block, j;`; +- to allow CN to focus the individual `W` to be written, we use `focus W, j;`; -- the store returns a matching `Owned` resource for index `j`; +- the store returns a matching `RW` resource for index `j`; -- finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. +- finally, we add `focus RW, j;` to allow CN to "`attach`" this resource to the iterated `RW` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `focus` only for the "`reverse`" direction. BCP: That last bit is mysterious. diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index ec3891ab..306aabfc 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -35,7 +35,7 @@ structures, as one would do in ML, Haskell, or Coq. We use the datatype `List` for CN-level lists. Intuitively, the `SLList_At` predicate walks over a singly-linked -pointer structure in the C heap and extracts an `Owned` version of +pointer structure in the C heap and extracts an `RW` version of the CN-level list that it represents. ```c title="exercises/list/cn_types.h" diff --git a/docs/reference/README.md b/docs/reference/README.md index fd34cbd6..2f2fefec 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -25,8 +25,8 @@ specification language. | `true` | Boolean true literal. | [Expressions](../specifications/expressions.md) | | `trusted` | Prevents CN from attempting to verify a function. | [Function specifications](../specifications/function-specifications.md) | | `unchanged` | TODO: is this a condition or expression? | | -| `Block` | Resource predicate indicating an uninitialized, non-null memory object. | [Resource predicates](../specifications/resource-predicates.md) | -| `Owned` | Resource predicate indicating an initialized, non-null memory object. | [Resource predicates](../specifications/resource-predicates.md) | +| `W` | Resource predicate indicating an uninitialized, non-null memory object. | [Resource predicates](../specifications/resource-predicates.md) | +| `RW` | Resource predicate indicating an initialized, non-null memory object. | [Resource predicates](../specifications/resource-predicates.md) | | `NULL` | The null value. | [Expressions](../specifications/expressions.md) | ## Operators diff --git a/docs/specifications/conditions.md b/docs/specifications/conditions.md index e143ffc9..5d7bae67 100644 --- a/docs/specifications/conditions.md +++ b/docs/specifications/conditions.md @@ -28,8 +28,8 @@ also return their contents. | Condition | Syntax | Example | | --------- | ------ | ------- | -| Single resource condition | `take = ` | `take v = Owned(p)` | -| Iterated resource condition |

    take <id> = each (<type> <id>; <expr>)
    {
     <resource-predicate>
    }

    |

    take vs = each (u32 i; 0u32 <= i && i < 10i32)
    {
     Owned(p + i)
    }

    | +| Single resource condition | `take = ` | `take v = RW(p)` | +| Iterated resource condition |

    take <id> = each (<type> <id>; <expr>)
    {
     <resource-predicate>
    }

    |

    take vs = each (u32 i; 0u32 <= i && i < 10i32)
    {
     RW(p + i)
    }

    | !!! info See [resource predicates](resource-predicates.md) for more @@ -44,15 +44,15 @@ void add_all(int *p, int arr[], int len) /*@ requires 0i32 <= len; - take v_in = Owned(p); + take v_in = RW(p); take arr_in = each (i32 j; 0i32 <= j && j < len) { - Owned(arr + j) + RW(arr + j) }; ensures - take v_out = Owned(p); + take v_out = RW(p); take arr_out = each (i32 j; 0i32 <= j && j < len) { - Owned(arr + j) + RW(arr + j) }; each (i32 j; 0i32 <= j && j < len) { arr_out[j] = arr_in[j] + v_in; diff --git a/docs/specifications/function-specifications.md b/docs/specifications/function-specifications.md index 7ca59209..fba309c3 100644 --- a/docs/specifications/function-specifications.md +++ b/docs/specifications/function-specifications.md @@ -40,12 +40,12 @@ int f(int *p) /*@ requires // p is not NULL and can be read and written by this function. - Owned(p); + RW(p); ensures // Ownership of p is returned to the caller. p remains non-NULL // and can be read and written by the caller. - take v = Owned(p); + take v = RW(p); // The value returned by this function is equal to the contents of p. return == v; @@ -76,10 +76,10 @@ int f1() int f2() /*@ requires - take glob_in = Owned(&glob); + take glob_in = RW(&glob); ensures - take glob_out = Owned(&glob); + take glob_out = RW(&glob); @*/ { return glob; @@ -122,19 +122,19 @@ int library_function(int *p); /*@ spec library_function(pointer p); requires - take p_in = Owned(p); + take p_in = RW(p); ensures - take p_out = Owned(p); + take p_out = RW(p); return == p_out; @*/ int inc(int *p) /*@ requires - take p_in = Owned(p); + take p_in = RW(p); ensures - take p_out = Owned(p); + take p_out = RW(p); return == p_in + 1; @*/ { @@ -162,10 +162,10 @@ int whoops(int *p) trusted; requires - take p_in = Owned(p); + take p_in = RW(p); ensures - take p_out = Owned(p); + take p_out = RW(p); return == p_out; @*/ { diff --git a/docs/specifications/loop-invariants.md b/docs/specifications/loop-invariants.md index 200ab27f..54e4d9a0 100644 --- a/docs/specifications/loop-invariants.md +++ b/docs/specifications/loop-invariants.md @@ -25,13 +25,13 @@ int find(int k, int arr[], int len) /*@ requires take arr_in = each (i32 j; 0i32 <= j && j < len) { - Owned(arr + j) + RW(arr + j) }; 0i32 <= len; ensures take arr_out = each (i32 j; 0i32 <= j && j < len) { - Owned(arr + j) + RW(arr + j) }; 0i32 <= return && return < len || return == -1i32; @*/ @@ -46,11 +46,11 @@ int find(int k, int arr[], int len) {k} unchanged; take arr_inv = each (i32 j; 0i32 <= j && j < len) { - Owned(arr + j) + RW(arr + j) }; @*/ { - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ if (arr[i] == k) { return i; diff --git a/src/example-archive/Rust/broken/error-proof/00004-simple-lifetimes.c b/src/example-archive/Rust/broken/error-proof/00004-simple-lifetimes.c index 169400d4..a41feb1b 100644 --- a/src/example-archive/Rust/broken/error-proof/00004-simple-lifetimes.c +++ b/src/example-archive/Rust/broken/error-proof/00004-simple-lifetimes.c @@ -30,8 +30,8 @@ fn borrow<'a>(input: &'a i32) -> &'a i32 { // Function to "borrow" an integer pointer int* borrow(int* input) - /*@ requires take v1 = Block(input); - ensures take v2 = Block(input); + /*@ requires take v1 = W(input); + ensures take v2 = W(input); return == input; @*/ { diff --git a/src/example-archive/Rust/broken/error-proof/00006-lifetimes-broken.c b/src/example-archive/Rust/broken/error-proof/00006-lifetimes-broken.c index e6f3b6dc..1b8d8f95 100644 --- a/src/example-archive/Rust/broken/error-proof/00006-lifetimes-broken.c +++ b/src/example-archive/Rust/broken/error-proof/00006-lifetimes-broken.c @@ -32,8 +32,8 @@ fn borrow<'a>(input: &'a i32) -> &'a i32 { int global_int = 0; int* borrow(const int* input) - /*@ requires take v1 = Owned(input); - ensures take v2 = Owned(input); + /*@ requires take v1 = RW(input); + ensures take v2 = RW(input); return == input; @*/ { diff --git a/src/example-archive/SAW/broken/error-cerberus/00001.swap.c b/src/example-archive/SAW/broken/error-cerberus/00001.swap.c index d9ceae6b..19384c19 100644 --- a/src/example-archive/SAW/broken/error-cerberus/00001.swap.c +++ b/src/example-archive/SAW/broken/error-cerberus/00001.swap.c @@ -140,10 +140,10 @@ llvm_verify swapmod "wacky_sort" #include void swap(uint32_t *x, uint32_t *y) -/*@ requires take xv0 = Owned(x); - take yv0 = Owned(y); - ensures take xv1 = Owned(x); - take yv1 = Owned(y); +/*@ requires take xv0 = RW(x); + take yv0 = RW(y); + ensures take xv1 = RW(x); + take yv1 = RW(y); xv1 == yv0; yv1 == xv0; @*/ @@ -154,10 +154,10 @@ void swap(uint32_t *x, uint32_t *y) } void xor_swap(uint32_t *x, uint32_t *y) -/*@ requires take xv0 = Owned(x); - take yv0 = Owned(y); - ensures take xv1 = Owned(x); - take yv1 = Owned(y); +/*@ requires take xv0 = RW(x); + take yv0 = RW(y); + ensures take xv1 = RW(x); + take yv1 = RW(y); xv1 == yv0; yv1 == xv0; @*/ @@ -169,22 +169,22 @@ void xor_swap(uint32_t *x, uint32_t *y) // selection sort void selection_sort(uint32_t *a, size_t len) -/*@ requires take av0 = each(size_t j; 0u64 <= j && j < len) { Owned(array_shift(a,j)) }; - ensures take av1 = each(size_t j; 0u64 <= j && j < len) { Owned(array_shift(a,j)) }; +/*@ requires take av0 = each(size_t j; 0u64 <= j && j < len) { RW(array_shift(a,j)) }; + ensures take av1 = each(size_t j; 0u64 <= j && j < len) { RW(array_shift(a,j)) }; @*/ { for (size_t i = 0; i < len - 1; ++i) - /*@ inv take avl = each(u64 k; 0u64 <= k && k < i) { Owned(array_shift(a,k)) }; - take avr = each(u64 k; i <= k && k < len) { Owned(array_shift(a,k)) } ; + /*@ inv take avl = each(u64 k; 0u64 <= k && k < i) { RW(array_shift(a,k)) }; + take avr = each(u64 k; i <= k && k < len) { RW(array_shift(a,k)) } ; {a} unchanged; {len} unchanged; i <= len; @*/ { size_t j_min = i; for (size_t j = i; j < len; ++j) - /*@ inv take avl = each(u64 k; 0u64 <= k && k < i) { Owned(array_shift(a,k)) }; - take avr = each(u64 k; i <= k && k < j) { Owned(array_shift(a,k)) }; - take avr = each(u64 k; j <= k && k < len) { Owned(array_shift(a,k)) }; + /*@ inv take avl = each(u64 k; 0u64 <= k && k < i) { RW(array_shift(a,k)) }; + take avr = each(u64 k; i <= k && k < j) { RW(array_shift(a,k)) }; + take avr = each(u64 k; j <= k && k < len) { RW(array_shift(a,k)) }; {a} unchanged; {len} unchanged; j <= len; @*/ diff --git a/src/example-archive/SAW/broken/error-cerberus/00008.salsa20.c b/src/example-archive/SAW/broken/error-cerberus/00008.salsa20.c index a3c1bd87..7032baa1 100644 --- a/src/example-archive/SAW/broken/error-cerberus/00008.salsa20.c +++ b/src/example-archive/SAW/broken/error-cerberus/00008.salsa20.c @@ -177,12 +177,12 @@ static void s20_expand16(uint8_t *k, { 't', 'e', ' ', 'k' } }; - // Copy all of 'tau' into the correct spots in our keystream block + // Copy all of 'tau' into the correct spots in our keystream W for (i = 0; i < 64; i += 20) for (j = 0; j < 4; ++j) keystream[i + j] = t[i / 20][j]; - // Copy the key and the nonce into the keystream block + // Copy the key and the nonce into the keystream W for (i = 0; i < 16; ++i) { keystream[4+i] = k[i]; keystream[44+i] = k[i]; @@ -207,12 +207,12 @@ static void s20_expand32(uint8_t *k, { 't', 'e', ' ', 'k' } }; - // Copy all of 'sigma' into the correct spots in our keystream block + // Copy all of 'sigma' into the correct spots in our keystream W for (i = 0; i < 64; i += 20) for (j = 0; j < 4; ++j) keystream[i + j] = o[i / 20][j]; - // Copy the key and the nonce into the keystream block + // Copy the key and the nonce into the keystream W for (i = 0; i < 16; ++i) { keystream[4+i] = k[i]; keystream[44+i] = k[i+16]; @@ -232,7 +232,7 @@ enum s20_status_t s20_crypt32(uint8_t *key, { uint8_t keystream[64]; // 'n' is the 8-byte nonce (unique message number) concatenated - // with the per-block 'counter' value (4 bytes in our case, 8 bytes + // with the per-W 'counter' value (4 bytes in our case, 8 bytes // in the standard). We leave the high 4 bytes set to zero because // we permit only a 32-bit integer for stream index and length. uint8_t n[16] = { 0 }; @@ -246,20 +246,20 @@ enum s20_status_t s20_crypt32(uint8_t *key, for (i = 0; i < 8; ++i) n[i] = nonce[i]; - // If we're not on a block boundary, compute the first keystream - // block. This will make the primary loop (below) cleaner + // If we're not on a W boundary, compute the first keystream + // W. This will make the primary loop (below) cleaner if (si % 64 != 0) { - // Set the second-to-highest 4 bytes of n to the block number + // Set the second-to-highest 4 bytes of n to the W number s20_rev_littleendian(n+8, si / 64); - // Expand the key with n and hash to produce a keystream block + // Expand the key with n and hash to produce a keystream W s20_expand32(key, n, keystream); } // Walk over the plaintext byte-by-byte, xoring the keystream with // the plaintext and producing new keystream blocks as needed for (i = 0; i < buflen; ++i) { - // If we've used up our entire keystream block (or have just begun - // and happen to be on a block boundary), produce keystream block + // If we've used up our entire keystream W (or have just begun + // and happen to be on a W boundary), produce keystream W if ((si + i) % 64 == 0) { s20_rev_littleendian(n+8, ((si + i) / 64)); s20_expand32(key, n, keystream); diff --git a/src/example-archive/SAW/broken/error-proof/00003.point.c b/src/example-archive/SAW/broken/error-proof/00003.point.c index 0ed4341e..7f478dfd 100644 --- a/src/example-archive/SAW/broken/error-proof/00003.point.c +++ b/src/example-archive/SAW/broken/error-proof/00003.point.c @@ -101,10 +101,10 @@ point ZERO = {0, 0}; // Check whether two points are equal bool point_eq(const point *p1, const point *p2) -/*@ requires take vp10 = Owned(p1); - take vp20 = Owned(p2); - ensures take vp11 = Owned(p1); - take vp21 = Owned(p2); +/*@ requires take vp10 = RW(p1); + take vp20 = RW(p2); + ensures take vp11 = RW(p1); + take vp21 = RW(p2); vp10 == vp11 ; vp20 == vp21; if (vp11.x == vp21.x && vp11.y == vp21.x) { return == 1u8 @@ -118,13 +118,13 @@ bool point_eq(const point *p1, const point *p2) /*@ spec malloc(); requires true; - ensures take v = Block(return); + ensures take v = W(return); @*/ // Allocate and return a new point point* point_new(uint32_t x, uint32_t y) /*@ requires true; - ensures take vp1 = Owned(return); + ensures take vp1 = RW(return); vp1.x == x ; vp1.y == y; @*/ { @@ -136,9 +136,9 @@ point* point_new(uint32_t x, uint32_t y) // Return a new point containing a copy of `p` point* point_copy(const point* p) -/*@ requires take vp0 = Owned(p); - ensures take vp1 = Owned(p); - take vr1 = Owned(return); +/*@ requires take vp0 = RW(p); + ensures take vp1 = RW(p); + take vr1 = RW(return); vp0.x == vp1.x ; vp0.y == vp1.y; vr1.x == vp1.x ; vr1.y == vp1.y; @*/ @@ -148,14 +148,14 @@ point* point_copy(const point* p) // Add two points point* point_add(const point *p1, const point *p2) -/*@ requires take vp10 = Owned(p1); - take vp20 = Owned(p2); - take vZ0 = Owned(&ZERO); +/*@ requires take vp10 = RW(p1); + take vp20 = RW(p2); + take vZ0 = RW(&ZERO); vZ0.x == 0u32 ; vZ0.y == 0u32; - ensures take vp11 = Owned(p1); - take vp21 = Owned(p2); - take vZ1 = Owned(&ZERO); - take vr1 = Owned(return); + ensures take vp11 = RW(p1); + take vp21 = RW(p2); + take vZ1 = RW(&ZERO); + take vr1 = RW(return); vr1.x == vp11.x + vp21.x ; vr1.y == vp11.y + vp21.y; @*/ { diff --git a/src/example-archive/SAW/broken/error-proof/00004.tutorial-dotprod.c b/src/example-archive/SAW/broken/error-proof/00004.tutorial-dotprod.c index f275e693..17f8320e 100644 --- a/src/example-archive/SAW/broken/error-proof/00004.tutorial-dotprod.c +++ b/src/example-archive/SAW/broken/error-proof/00004.tutorial-dotprod.c @@ -48,10 +48,10 @@ function [rec] (u32) dotprod_spec(map x,map y, uint32_t size @*/ uint32_t dotprod(uint32_t *x, uint32_t *y, uint32_t size) -/*@ requires take ax0 = each(u32 j; 0u32 <= j && j < size) { Owned(array_shift(x,j)) }; - take ay0 = each(u32 j; 0u32 <= j && j < size) { Owned(array_shift(y,j)) } - ensures take ax1 = each(u32 j; 0u32 <= j && j < size) { Owned(array_shift(x,j)) }; - take ay1 = each(u32 j; 0u32 <= j && j < size) { Owned(array_shift(y,j)) }; +/*@ requires take ax0 = each(u32 j; 0u32 <= j && j < size) { RW(array_shift(x,j)) }; + take ay0 = each(u32 j; 0u32 <= j && j < size) { RW(array_shift(y,j)) } + ensures take ax1 = each(u32 j; 0u32 <= j && j < size) { RW(array_shift(x,j)) }; + take ay1 = each(u32 j; 0u32 <= j && j < size) { RW(array_shift(y,j)) }; return == dotprod_spec(ax1,ay1,size) @*/ { @@ -59,14 +59,14 @@ uint32_t dotprod(uint32_t *x, uint32_t *y, uint32_t size) /*@ unfold dotprod_spec(ax0,ay0,0u32); @*/ /*@ assert(0u32 == dotprod_spec(ax0,ay0,0u32)); @*/ for(size_t i = 0; i < size; i++) - /*@ inv take axi = each(u32 j; 0u32 <= j && j < size) { Owned(array_shift(x,j)) }; - take ayi = each(u32 j; 0u32 <= j && j < size) { Owned(array_shift(y,j)) }; + /*@ inv take axi = each(u32 j; 0u32 <= j && j < size) { RW(array_shift(x,j)) }; + take ayi = each(u32 j; 0u32 <= j && j < size) { RW(array_shift(y,j)) }; {x} unchanged; {y} unchanged; 0u64<=i; res == dotprod_spec(axi,ayi,(u32)i) @*/ { - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ res += x[i] * y[i]; /*@ unfold dotprod_spec(axi,ayi,(u32)i); @*/ } diff --git a/src/example-archive/c-testsuite/broken/error-proof/00077.err1.c b/src/example-archive/c-testsuite/broken/error-proof/00077.err1.c index 9f98f52c..963b79d4 100644 --- a/src/example-archive/c-testsuite/broken/error-proof/00077.err1.c +++ b/src/example-archive/c-testsuite/broken/error-proof/00077.err1.c @@ -3,12 +3,12 @@ int foo(int x[100]) /*@ requires - take PreX = each (u64 j; 0u64 <= j && j < 100u64) {Owned(x + j)}; @*/ + take PreX = each (u64 j; 0u64 <= j && j < 100u64) {RW(x + j)}; @*/ { int y[100]; int *p; - /*@ extract Block, 0u64; @*/ + /*@ focus W, 0u64; @*/ y[0] = 2000; if(x[0] != 1000) @@ -49,7 +49,7 @@ main() { int x[100]; assert(0); - /*@ extract Block, 0u64; @*/ + /*@ focus W, 0u64; @*/ x[0] = 1000; return foo(x); diff --git a/src/example-archive/c-testsuite/broken/error-timeout/00182.timeout.c b/src/example-archive/c-testsuite/broken/error-timeout/00182.timeout.c index 5596cbfd..33cb9ee8 100644 --- a/src/example-archive/c-testsuite/broken/error-timeout/00182.timeout.c +++ b/src/example-archive/c-testsuite/broken/error-timeout/00182.timeout.c @@ -182,7 +182,7 @@ void print_led(unsigned long x, char *buf) static int d[MAX_DIGITS]; - /* extract digits from x */ + /* focus digits from x */ n = ( x == 0L ? 1 : 0 ); /* 0 is a digit, hence a special case */ diff --git a/src/example-archive/c-testsuite/working/00015.working.c b/src/example-archive/c-testsuite/working/00015.working.c index 2259a5ae..20208686 100644 --- a/src/example-archive/c-testsuite/working/00015.working.c +++ b/src/example-archive/c-testsuite/working/00015.working.c @@ -4,9 +4,9 @@ main() { int arr[2]; - /*@ extract Block, 0u64; @*/ + /*@ focus W, 0u64; @*/ arr[0] = 1; - /*@ extract Block, 1u64; @*/ + /*@ focus W, 1u64; @*/ arr[1] = 2; return arr[0] + arr[1] - 3; diff --git a/src/example-archive/c-testsuite/working/00016.working.c b/src/example-archive/c-testsuite/working/00016.working.c index 7d9ae877..c02b8df3 100644 --- a/src/example-archive/c-testsuite/working/00016.working.c +++ b/src/example-archive/c-testsuite/working/00016.working.c @@ -5,7 +5,7 @@ main() int arr[2]; int *p; - /*@ extract Block, 1u64; @*/ + /*@ focus W, 1u64; @*/ p = &arr[1]; *p = 0; return arr[1]; diff --git a/src/example-archive/c-testsuite/working/00032.c b/src/example-archive/c-testsuite/working/00032.c index 1867ba73..6d2462ca 100644 --- a/src/example-archive/c-testsuite/working/00032.c +++ b/src/example-archive/c-testsuite/working/00032.c @@ -7,9 +7,9 @@ main() int arr[2]; int *p; - /*@ extract Block, 0u64; @*/ + /*@ focus W, 0u64; @*/ arr[0] = 2; - /*@ extract Block, 1u64; @*/ + /*@ focus W, 1u64; @*/ arr[1] = 3; p = &arr[0]; if(*(p++) != 2) diff --git a/src/example-archive/c-testsuite/working/00033.working.c b/src/example-archive/c-testsuite/working/00033.working.c index 15f73962..f47f648e 100644 --- a/src/example-archive/c-testsuite/working/00033.working.c +++ b/src/example-archive/c-testsuite/working/00033.working.c @@ -3,9 +3,9 @@ int g; int effect() /*@ requires - take Pre = Owned(&g); @*/ + take Pre = RW(&g); @*/ /*@ ensures - take Post = Owned(&g); + take Post = RW(&g); Post == 1i32; return == 1i32; @*/ { @@ -16,9 +16,9 @@ effect() int main() /*@ requires - take Pre = Owned(&g); @*/ + take Pre = RW(&g); @*/ /*@ ensures - take Post = Owned(&g); @*/ + take Post = RW(&g); @*/ /*@ ensures return == 0i32; @*/ { int x; diff --git a/src/example-archive/c-testsuite/working/00037.working.c b/src/example-archive/c-testsuite/working/00037.working.c index 6a854eea..5840aa47 100644 --- a/src/example-archive/c-testsuite/working/00037.working.c +++ b/src/example-archive/c-testsuite/working/00037.working.c @@ -4,7 +4,7 @@ main() { int x[2]; int *p; - /*@ extract Block, 1u64; @*/ + /*@ focus W, 1u64; @*/ x[1] = 7; p = &x[0]; p = p + 1; diff --git a/src/example-archive/c-testsuite/working/00072.working.c b/src/example-archive/c-testsuite/working/00072.working.c index 998cef86..34ee6500 100644 --- a/src/example-archive/c-testsuite/working/00072.working.c +++ b/src/example-archive/c-testsuite/working/00072.working.c @@ -4,7 +4,7 @@ main() { int arr[2]; int *p; - /*@ extract Block, 1u64; @*/ + /*@ focus W, 1u64; @*/ p = &arr[0]; p += 1; *p = 123; diff --git a/src/example-archive/c-testsuite/working/00078.working.c b/src/example-archive/c-testsuite/working/00078.working.c index 1ffc92c5..90678dea 100644 --- a/src/example-archive/c-testsuite/working/00078.working.c +++ b/src/example-archive/c-testsuite/working/00078.working.c @@ -1,9 +1,9 @@ int f1(char *p) /*@ requires - take PreP = Owned(p); @*/ + take PreP = RW(p); @*/ /*@ ensures - take PostP = Owned(p); + take PostP = RW(p); return == 1i32 + (i32) PreP; @*/ { return *p+1; diff --git a/src/example-archive/c-testsuite/working/00090.working.c b/src/example-archive/c-testsuite/working/00090.working.c index f4ff0a4d..f9e29452 100644 --- a/src/example-archive/c-testsuite/working/00090.working.c +++ b/src/example-archive/c-testsuite/working/00090.working.c @@ -12,9 +12,9 @@ main() @*/ /*@ ensures return == 0i32; @*/ { - /*@ extract Owned, 0u64; @*/ - /*@ extract Owned, 1u64; @*/ - /*@ extract Owned, 2u64; @*/ + /*@ focus RW, 0u64; @*/ + /*@ focus RW, 1u64; @*/ + /*@ focus RW, 2u64; @*/ if (a[0] != 0) return 1; if (a[1] != 1) diff --git a/src/example-archive/coq-lemmas/README.md b/src/example-archive/coq-lemmas/README.md index bde0add4..42b4fb70 100644 --- a/src/example-archive/coq-lemmas/README.md +++ b/src/example-archive/coq-lemmas/README.md @@ -46,7 +46,7 @@ From this folder, to export lemmas from example `path/to/EXAMPLENAME.c`, do the copies a template build folder that conveniently contains a `_CoqProject` file and the CN coq library `CN_Lib.v`. If the folder already exists, `rsync` just updates the files. -2. Extract the lemmas with +2. focus the lemmas with `cn --lemmata=path/to/EXAMPLENAME-build/theories/ExportedLemmas.v path/to/EXAMPLENAME.c` diff --git a/src/example-archive/dafny-tutorial/working/binary_search.c b/src/example-archive/dafny-tutorial/working/binary_search.c index e83786a4..62c3cb74 100644 --- a/src/example-archive/dafny-tutorial/working/binary_search.c +++ b/src/example-archive/dafny-tutorial/working/binary_search.c @@ -8,10 +8,10 @@ int binary_search(int *a, int length, int value) 0i32 <= length; (2i64 * (i64) length) <= MAXi32; take IndexPre = each (i32 j; 0i32 <= j && j < length) - {Owned(a + j)}; @*/ + {RW(a + j)}; @*/ /*@ ensures take IndexPost = each (i32 j; 0i32 <= j && j < length) - {Owned(a + j)}; + {RW(a + j)}; IndexPost == IndexPre; (return < 0i32) || (IndexPost[return] == value); @*/ { @@ -26,11 +26,11 @@ int binary_search(int *a, int length, int value) high <= length; ((i64) low + (i64) high) <= MAXi32; take IndexInv = each (i32 j; 0i32 <= j && j < length) - {Owned(a + j)}; + {RW(a + j)}; IndexInv == IndexPre; @*/ { int mid = (low + high) / 2; - /*@ extract Owned, mid; @*/ + /*@ focus RW, mid; @*/ /*@ instantiate good, mid; @*/ if (a[mid] < value) { diff --git a/src/example-archive/dafny-tutorial/working/linear_search.c b/src/example-archive/dafny-tutorial/working/linear_search.c index 17b42980..71409722 100644 --- a/src/example-archive/dafny-tutorial/working/linear_search.c +++ b/src/example-archive/dafny-tutorial/working/linear_search.c @@ -4,10 +4,10 @@ int linear_search(int *a, int length, int key) /*@ requires 0i32 < length; take IndexPre = each (i32 j; 0i32 <= j && j < length) - {Owned(a + j)}; @*/ + {RW(a + j)}; @*/ /*@ ensures take IndexPost = each (i32 j; 0i32 <= j && j < length) - {Owned(a + j)}; + {RW(a + j)}; (return < 0i32) || (IndexPost[return] == key); each (i32 j; 0i32 <= j && j < length) {return >= 0i32 || IndexPre[j] != key}; @@ -21,11 +21,11 @@ int linear_search(int *a, int length, int key) 0i32 <= idx; idx <= length; take IndexInv = each (i32 j; 0i32 <= j && j < length) - {Owned(a + j)}; + {RW(a + j)}; IndexInv == IndexPre; each (i32 j; 0i32 <= j && j < idx) {IndexPre[j] != key}; @*/ { - /*@ extract Owned, idx; @*/ + /*@ focus RW, idx; @*/ if (*(a + idx) == key) { return idx; diff --git a/src/example-archive/dafny-tutorial/working/multiple_returns.c b/src/example-archive/dafny-tutorial/working/multiple_returns.c index 8b2e20fd..6e419f0d 100644 --- a/src/example-archive/dafny-tutorial/working/multiple_returns.c +++ b/src/example-archive/dafny-tutorial/working/multiple_returns.c @@ -13,13 +13,13 @@ void multiple_returns(int x, int y, struct int_pair *ret) let MAXi32 = (i64) 2147483647i64; let MINi32 = (i64) -2147483647i64; - take PairPre = Owned(ret); + take PairPre = RW(ret); MINi32 <= (i64) x + (i64) y; (i64) x + (i64) y <= MAXi32; MINi32 <= (i64) x - (i64) y; (i64) x - (i64) y <= MAXi32; @*/ /*@ ensures - take PairPost = Owned(ret); + take PairPost = RW(ret); PairPost.fst == x + y; PairPost.snd == x - y; @*/ { diff --git a/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c b/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c index 1080d940..41d3762a 100644 --- a/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c +++ b/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c @@ -39,12 +39,12 @@ processing a method invocation at compile-time ([13, Section predicate { u32 pv, u32 qv } BothOwned (pointer p, pointer q) { if (p == q) { - take pv = Owned(p); + take pv = RW(p); return {pv: pv, qv: pv}; } else { - take pv = Owned(p); - take qv = Owned(q); + take pv = RW(p); + take qv = RW(q); return {pv: pv, qv: qv}; } } diff --git a/src/example-archive/java_program_verification_challenges/broken/error-proof/00002_side_effects.c b/src/example-archive/java_program_verification_challenges/broken/error-proof/00002_side_effects.c index 170f8cee..f1a7731a 100644 --- a/src/example-archive/java_program_verification_challenges/broken/error-proof/00002_side_effects.c +++ b/src/example-archive/java_program_verification_challenges/broken/error-proof/00002_side_effects.c @@ -60,10 +60,10 @@ void m() { } int main() - /*@ requires take vr0 = Block(result1); - take vr0 = Block(result2) - ensures take vp1 = Block(result1); - take vb1 = Block(result2) + /*@ requires take vr0 = W(result1); + take vr0 = W(result2) + ensures take vp1 = W(result1); + take vb1 = W(result2) @*/ { m(); // Execute the function m diff --git a/src/example-archive/java_program_verification_challenges/broken/error-proof/00003_break.c b/src/example-archive/java_program_verification_challenges/broken/error-proof/00003_break.c index 1127d696..795543f6 100644 --- a/src/example-archive/java_program_verification_challenges/broken/error-proof/00003_break.c +++ b/src/example-archive/java_program_verification_challenges/broken/error-proof/00003_break.c @@ -17,7 +17,7 @@ November 5-8, 2002, Revised Lectures 1. Springer Berlin Heidelberg, and catching. They require a suitable control flow semantics. Special care is needed for the ‘finally’ part of a try-catch-finally construction. Figure 4 contains a simple example (adapted from [17]) that combines many aspects. The subtle -point is that the assignment m+=10 in the finally block will still be executed, +point is that the assignment m+=10 in the finally W will still be executed, despite the earlier return statements, but has no effect on the value that is returned. The reason is that this value is bound earlier. */ @@ -53,8 +53,8 @@ void negateFirst() { } int main() - /*@ requires take vl0 = Owned(&ia_length) - ensures take vp1 = Owned(&ia_length) + /*@ requires take vl0 = RW(&ia_length) + ensures take vp1 = RW(&ia_length) @*/ { // Example usage diff --git a/src/example-archive/java_program_verification_challenges/broken/error-proof/00006_callbacks.c b/src/example-archive/java_program_verification_challenges/broken/error-proof/00006_callbacks.c index 982c3cc5..b9ccdb78 100644 --- a/src/example-archive/java_program_verification_challenges/broken/error-proof/00006_callbacks.c +++ b/src/example-archive/java_program_verification_challenges/broken/error-proof/00006_callbacks.c @@ -72,11 +72,11 @@ struct A { * @ ensures k == \old(k) - 1 && m == \old(m) + 1; */ void decrement_k(A *a) - /*@ requires take va0 = Owned
    (a); + /*@ requires take va0 = RW(a); va0.m < 2147483647i32; -2147483648i32 < va0.k; va0.k + va0.m == 0i32 - ensures take va1 = Owned(a); + ensures take va1 = RW(a); va1.k == va0.k-1i32; va1.m == va0.m+1i32; va1.k + va1.m == 0i32 @@ -97,12 +97,12 @@ void decrement_k(A *a) * @ ensures true; */ void increment_k(A *a) - /*@ requires take va0 = Owned(a); + /*@ requires take va0 = RW(a); va0.k < 2147483647i32; va0.m < 2147483647i32; -2147483648i32 < va0.m; va0.k + va0.m == 0i32 - ensures take va1 = Owned(a); + ensures take va1 = RW(a); va1.k == va0.k; va1.m == va0.m; va1.k + va1.m == 0i32 diff --git a/src/example-archive/java_program_verification_challenges/broken/error-proof/00007_static_init.c b/src/example-archive/java_program_verification_challenges/broken/error-proof/00007_static_init.c index e72ef63c..3e41fedc 100644 --- a/src/example-archive/java_program_verification_challenges/broken/error-proof/00007_static_init.c +++ b/src/example-archive/java_program_verification_challenges/broken/error-proof/00007_static_init.c @@ -78,10 +78,10 @@ void initialize() { * @ ensures result1 && !result2 && result3 && result4 */ void m() - /*@ requires take vbl0 = Owned(bl); - take vdl0 = Owned(dl); - take vb20 = Owned(b2); - take vd20 = Owned(d2) + /*@ requires take vbl0 = RW(bl); + take vdl0 = RW(dl); + take vb20 = RW(b2); + take vd20 = RW(d2) ensures true @*/ { diff --git a/src/example-archive/java_program_verification_challenges/working/00004_exceptions.c b/src/example-archive/java_program_verification_challenges/working/00004_exceptions.c index 94a50bf5..1fda6ff0 100644 --- a/src/example-archive/java_program_verification_challenges/working/00004_exceptions.c +++ b/src/example-archive/java_program_verification_challenges/working/00004_exceptions.c @@ -17,7 +17,7 @@ November 5-8, 2002, Revised Lectures 1. Springer Berlin Heidelberg, and catching. They require a suitable control flow semantics. Special care is needed for the ‘finally’ part of a try-catch-finally construction. Figure 4 contains a simple example (adapted from [17]) that combines many aspects. The subtle -point is that the assignment m+=10 in the finally block will still be executed, +point is that the assignment m+=10 in the finally W will still be executed, despite the earlier return statements, but has no effect on the value that is returned. The reason is that this value is bound earlier. @@ -38,10 +38,10 @@ int m; // Global variable m * && m == \old(m) + 10; */ int returnfinally(int d) - /*@ requires take vp0 = Owned(&m); + /*@ requires take vp0 = RW(&m); let m10 = (i64)vp0 + 10i64; m10 <= 2147483647i64; - ensures take vp1 = Owned(&m); + ensures take vp1 = RW(&m); @*/ { int result; @@ -52,14 +52,14 @@ int returnfinally(int d) result = m / d; // Normal division } - m += 10; // This corresponds to the 'finally' block in Java, executed regardless of exception + m += 10; // This corresponds to the 'finally' W in Java, executed regardless of exception return result; } int main() - /*@ requires take vp0 = Owned(&m); - ensures take vp1 = Block(&m); + /*@ requires take vp0 = RW(&m); + ensures take vp1 = W(&m); return == 0i32; @*/ { diff --git a/src/example-archive/open-sut/working/mps_1.c b/src/example-archive/open-sut/working/mps_1.c index 9f64148c..a26919c0 100644 --- a/src/example-archive/open-sut/working/mps_1.c +++ b/src/example-archive/open-sut/working/mps_1.c @@ -35,19 +35,19 @@ typedef uint8_t w8; w1 Coincidence_2_4(w8 trips[4]) /*@ requires - take ta = Owned(array_shift(trips, 0i32)); - take tb = Owned(array_shift(trips, 1i32)); - take tc = Owned(array_shift(trips, 2i32)); - take td = Owned(array_shift(trips, 3i32)); + take ta = RW(array_shift(trips, 0i32)); + take tb = RW(array_shift(trips, 1i32)); + take tc = RW(array_shift(trips, 2i32)); + take td = RW(array_shift(trips, 3i32)); let a = ta != 0u8; let b = tb != 0u8; let c = tc != 0u8; let d = td != 0u8; ensures - take ta_out = Owned(array_shift(trips, 0i32)); - take tb_out = Owned(array_shift(trips, 1i32)); - take tc_out = Owned(array_shift(trips, 2i32)); - take td_out = Owned(array_shift(trips, 3i32)); + take ta_out = RW(array_shift(trips, 0i32)); + take tb_out = RW(array_shift(trips, 1i32)); + take tc_out = RW(array_shift(trips, 2i32)); + take td_out = RW(array_shift(trips, 3i32)); return == Bool_to_u8(P_Coincidence_2_4(a, b, c, d)); @*/ { diff --git a/src/example-archive/should-fail/broken/error-proof/ownership_neg_1.c b/src/example-archive/should-fail/broken/error-proof/ownership_neg_1.c index 7b788719..2903b829 100644 --- a/src/example-archive/should-fail/broken/error-proof/ownership_neg_1.c +++ b/src/example-archive/should-fail/broken/error-proof/ownership_neg_1.c @@ -1,9 +1,9 @@ // Negative test case: proof should fail -// Precondition includes access to the resource Owned(p), which disappears in +// Precondition includes access to the resource RW(p), which disappears in // the postcondition void ownership_neg_1(int *p) -/*@ requires take P = Owned(p); @*/ +/*@ requires take P = RW(p); @*/ /*@ ensures true; @*/ { ; diff --git a/src/example-archive/should-fail/broken/error-proof/ownership_neg_2.c b/src/example-archive/should-fail/broken/error-proof/ownership_neg_2.c index 42f8044b..b375b5d7 100644 --- a/src/example-archive/should-fail/broken/error-proof/ownership_neg_2.c +++ b/src/example-archive/should-fail/broken/error-proof/ownership_neg_2.c @@ -1,10 +1,10 @@ // Negative test case: proof should fail // Precondition takes ownership of no resources, but then the postcondition -// claims ownership of Owned(p) +// claims ownership of RW(p) void ownership_neg_2(int *p) /*@ requires true; @*/ -/*@ ensures take P_ = Owned(p); @*/ +/*@ ensures take P_ = RW(p); @*/ { ; } \ No newline at end of file diff --git a/src/example-archive/should-fail/broken/error-proof/ownership_neg_3.c b/src/example-archive/should-fail/broken/error-proof/ownership_neg_3.c index b0bff2d3..4a0fba43 100644 --- a/src/example-archive/should-fail/broken/error-proof/ownership_neg_3.c +++ b/src/example-archive/should-fail/broken/error-proof/ownership_neg_3.c @@ -1,12 +1,12 @@ // Negative test case: proof should fail -// Precondition includes access to the resource Owned(p), which is duplicated in +// Precondition includes access to the resource RW(p), which is duplicated in // the postcondition void ownership_neg_3(int *p) -/*@ requires take P = Owned(p); @*/ +/*@ requires take P = RW(p); @*/ /*@ ensures - take P_ = Owned(p); - take Q_ = Owned(p); @*/ + take P_ = RW(p); + take Q_ = RW(p); @*/ { ; } \ No newline at end of file diff --git a/src/example-archive/should-fail/working/c_sequencing_race.c b/src/example-archive/should-fail/working/c_sequencing_race.c index c91abf15..0babc927 100644 --- a/src/example-archive/should-fail/working/c_sequencing_race.c +++ b/src/example-archive/should-fail/working/c_sequencing_race.c @@ -2,9 +2,9 @@ int f (int *x) -/*@ requires take xv = Owned(x); @*/ +/*@ requires take xv = RW(x); @*/ /*@ requires 0i32 <= xv && xv < 500i32; @*/ -/*@ ensures take xv2 = Owned(x); @*/ +/*@ ensures take xv2 = RW(x); @*/ { return ((*x) + (*x)); } diff --git a/src/example-archive/simple-examples/broken/error-cerberus/pred_1.c b/src/example-archive/simple-examples/broken/error-cerberus/pred_1.c index 80c71112..137a95ba 100644 --- a/src/example-archive/simple-examples/broken/error-cerberus/pred_1.c +++ b/src/example-archive/simple-examples/broken/error-cerberus/pred_1.c @@ -3,7 +3,7 @@ /*@ predicate (i32) TestMemoryEqZero_1(pointer p) { - take PVal = Owned(p); + take PVal = RW(p); if (PVal == 0i32) { return 1i32; } else { @@ -14,7 +14,7 @@ predicate (i32) TestMemoryEqZero_1(pointer p) { void pred_1(int *p) /*@ requires - take PreP = Owned(p); + take PreP = RW(p); PreP == 0i32; @*/ /*@ ensures take TestP = TestMemoryEqZero_1(p); diff --git a/src/example-archive/simple-examples/broken/error-proof/ownership_1.c b/src/example-archive/simple-examples/broken/error-proof/ownership_1.c index 62b7f3e9..d8bdaba1 100644 --- a/src/example-archive/simple-examples/broken/error-proof/ownership_1.c +++ b/src/example-archive/simple-examples/broken/error-proof/ownership_1.c @@ -1,12 +1,12 @@ -// This example should be provable because Owned locations should be +// This example should be provable because RW locations should be // disjoint. But CN currently doesn't enforce this property. // See: https://github.com/rems-project/cerberus/issues/295 void ownership_1(int *a, int *b) /*@ requires - take P1 = Owned(a); - take P2 = Owned(b); + take P1 = RW(a); + take P2 = RW(b); ensures a != b; @*/ diff --git a/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_3var.c b/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_3var.c index 481a5a85..1b8ef064 100644 --- a/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_3var.c +++ b/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_3var.c @@ -18,10 +18,10 @@ typedef struct { } example_t; int overflow_timeout_3var(example_t* p1,example_t* p2) /*@ - requires take x = Owned(p1); - take y = Owned(p2); - ensures take x2 = Owned(p1); - take y2 = Owned(p2); + requires take x = RW(p1); + take y = RW(p2); + ensures take x2 = RW(p1); + take y2 = RW(p2); @*/ { int distance = 0; diff --git a/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_4var.c b/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_4var.c index 44ee9a84..a7b787ab 100644 --- a/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_4var.c +++ b/src/example-archive/simple-examples/broken/error-timeout/overflow_timeout_4var.c @@ -18,10 +18,10 @@ typedef struct { } example_t; int overflow_timeout_4var(example_t* p1,example_t* p2) /*@ - requires take x = Owned(p1); - take y = Owned(p2); - ensures take x2 = Owned(p1); - take y2 = Owned(p2); + requires take x = RW(p1); + take y = RW(p2); + ensures take x2 = RW(p1); + take y2 = RW(p2); @*/ { int distance = 0; diff --git a/src/example-archive/simple-examples/working/array_1.c b/src/example-archive/simple-examples/working/array_1.c index c09c35b1..2435926c 100644 --- a/src/example-archive/simple-examples/working/array_1.c +++ b/src/example-archive/simple-examples/working/array_1.c @@ -2,13 +2,13 @@ void array_1(int *arr, int size, int off) /*@ requires - take arrayStart = each (i32 j; 0i32 <= j && j < size) {Owned(arr + j)}; + take arrayStart = each (i32 j; 0i32 <= j && j < size) {RW(arr + j)}; 0i32 <= off; off < size; @*/ -/*@ ensures take arrayEnd = each (i32 j; 0i32 <= j && j < size) {Owned(arr + j)}; @*/ +/*@ ensures take arrayEnd = each (i32 j; 0i32 <= j && j < size) {RW(arr + j)}; @*/ { int i = off; - /*@ extract Owned, i; @*/ // <-- required to read / write + /*@ focus RW, i; @*/ // <-- required to read / write arr[off] = 7; i++; return; diff --git a/src/example-archive/simple-examples/working/array_2.c b/src/example-archive/simple-examples/working/array_2.c index 6aa849ed..accb09e0 100644 --- a/src/example-archive/simple-examples/working/array_2.c +++ b/src/example-archive/simple-examples/working/array_2.c @@ -2,16 +2,16 @@ int array_2(int *arr, int size, int off) /*@ requires - take arrayStart = each (i32 j; 0i32 <= j && j < size) {Owned(arr + j)}; + take arrayStart = each (i32 j; 0i32 <= j && j < size) {RW(arr + j)}; 0i32 <= off; off < size; arrayStart[off] != 0i32; @*/ /*@ ensures - take arrayEnd = each (i32 j; 0i32 <= j && j < size) {Owned(arr + j)}; + take arrayEnd = each (i32 j; 0i32 <= j && j < size) {RW(arr + j)}; arrayEnd[off] == 7i32; return == arrayStart[off]; @*/ { - /*@ extract Owned, off; @*/ + /*@ focus RW, off; @*/ int tmp = arr[off]; arr[off] = 7; return tmp; diff --git a/src/example-archive/simple-examples/working/array_3.c b/src/example-archive/simple-examples/working/array_3.c index 18ed2241..a45e9ba1 100644 --- a/src/example-archive/simple-examples/working/array_3.c +++ b/src/example-archive/simple-examples/working/array_3.c @@ -5,9 +5,9 @@ void array_3(int *arr, int n) /*@ requires 0i32 < n; - take arrayStart = each (i32 j; 0i32 <= j && j < n) {Owned(arr + j)}; @*/ + take arrayStart = each (i32 j; 0i32 <= j && j < n) {RW(arr + j)}; @*/ /*@ ensures - take arrayEnd = each (i32 j; 0i32 <= j && j < n) {Owned(arr + j)}; + take arrayEnd = each (i32 j; 0i32 <= j && j < n) {RW(arr + j)}; each (i32 j; 0i32 <= j && j < n) {arrayEnd[j] == 7i32}; @*/ { int i = 0; @@ -16,10 +16,10 @@ void array_3(int *arr, int n) {arr}unchanged; 0i32 <= i; i <= n; - take arrayInv = each (i32 j; 0i32 <= j && j < n) {Owned(arr + j)}; + take arrayInv = each (i32 j; 0i32 <= j && j < n) {RW(arr + j)}; each (i32 j; 0i32 <= j && j < i) {arrayInv[j] == 7i32}; @*/ { - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ *(arr + i) = 7; i++; }; diff --git a/src/example-archive/simple-examples/working/array_read.c b/src/example-archive/simple-examples/working/array_read.c index 5ae6fbe4..e53e886c 100644 --- a/src/example-archive/simple-examples/working/array_read.c +++ b/src/example-archive/simple-examples/working/array_read.c @@ -3,7 +3,7 @@ int head(int *arr, unsigned long len) /*@ requires take arr_in = each(u64 i; i < len) { - Owned(array_shift(arr, i)) + RW(array_shift(arr, i)) }; each(u64 i; i < len) { arr_in[i] == 0i32 @@ -12,7 +12,7 @@ requires ensures take arr_out = each(u64 i; i < len) { - Owned(array_shift(arr, i)) + RW(array_shift(arr, i)) }; each(u64 i; i < len) { arr_out[i] == 0i32 @@ -22,10 +22,10 @@ ensures { unsigned long idx = 0; - // First, we apply `extract` to direct CN to the relevant element of the + // First, we apply `focus` to direct CN to the relevant element of the // iterated resource `arr_in`, which it needs in order to verify the // following read: - /*@ extract Owned, idx; @*/ + /*@ focus RW, idx; @*/ int hd = arr[idx]; diff --git a/src/example-archive/simple-examples/working/assert_2.c b/src/example-archive/simple-examples/working/assert_2.c index 9fb7f147..9c18097b 100644 --- a/src/example-archive/simple-examples/working/assert_2.c +++ b/src/example-archive/simple-examples/working/assert_2.c @@ -2,12 +2,12 @@ void assert_2(int *x, int *y) /*@ requires - take Xpre = Owned(x); - take Ypre = Owned(y); + take Xpre = RW(x); + take Ypre = RW(y); *x == 7i32; *y == 7i32; @*/ /*@ ensures - take Xpost = Owned(x); - take Ypost = Owned(y); + take Xpost = RW(x); + take Ypost = RW(y); *x == 0i32; *y == 0i32; @*/ { *x = 0; diff --git a/src/example-archive/simple-examples/working/assert_3.c b/src/example-archive/simple-examples/working/assert_3.c index ab251f66..7e5c7b89 100644 --- a/src/example-archive/simple-examples/working/assert_3.c +++ b/src/example-archive/simple-examples/working/assert_3.c @@ -4,20 +4,20 @@ // Define a lemma that asserts ownership of a particular memory cell /*@ lemma assert_own (pointer p) - requires take x0 = Owned(p); + requires take x0 = RW(p); ensures - take x1 = Owned(p); + take x1 = RW(p); x1 == x0; // <-- Note, otherwise the lemma havocs the memory contents @*/ void assert_3(int *x, int *y) /*@ requires - take Xpre = Owned(x); - take Ypre = Owned(y); + take Xpre = RW(x); + take Ypre = RW(y); *x == 7i32; *y == 7i32; @*/ /*@ ensures - take Xpost = Owned(x); - take Ypost = Owned(y); + take Xpost = RW(x); + take Ypost = RW(y); *x == 0i32; *y == 0i32; @*/ { *x = 0; diff --git a/src/example-archive/simple-examples/working/cast_4.c b/src/example-archive/simple-examples/working/cast_4.c index 5510b6c5..e94c051f 100644 --- a/src/example-archive/simple-examples/working/cast_4.c +++ b/src/example-archive/simple-examples/working/cast_4.c @@ -5,8 +5,8 @@ #define OFFSET 374328 int cast_4(int *ptr_original) -/*@ requires take Pre = Block(ptr_original); @*/ -/*@ ensures take Post = Owned(ptr_original); +/*@ requires take Pre = W(ptr_original); @*/ +/*@ ensures take Post = RW(ptr_original); return == 7i32; @*/ { *ptr_original = 7; diff --git a/src/example-archive/simple-examples/working/effect_1.c b/src/example-archive/simple-examples/working/effect_1.c index 2b3833f0..7528da5c 100644 --- a/src/example-archive/simple-examples/working/effect_1.c +++ b/src/example-archive/simple-examples/working/effect_1.c @@ -7,9 +7,9 @@ int g; void write_g_to_1() /*@ requires - take Pre = Block(&g); @*/ + take Pre = W(&g); @*/ /*@ ensures - take Post = Owned(&g); + take Post = RW(&g); Post == 1i32; @*/ { g = 1; @@ -19,9 +19,9 @@ write_g_to_1() int effect_1() /*@ requires - take Pre = Block(&g); @*/ + take Pre = W(&g); @*/ /*@ ensures - take Post = Owned(&g); + take Post = RW(&g); return == 1i32; @*/ { int x; diff --git a/src/example-archive/simple-examples/working/free_1.c b/src/example-archive/simple-examples/working/free_1.c index 1c07f886..9879d011 100644 --- a/src/example-archive/simple-examples/working/free_1.c +++ b/src/example-archive/simple-examples/working/free_1.c @@ -5,14 +5,14 @@ void my_free_int(int *target) /*@ trusted; @*/ -/*@ requires take ToFree = Owned(target); @*/ +/*@ requires take ToFree = RW(target); @*/ {} void free_1(int *x, int *y) /*@ requires - take Xpre = Owned(x); - take Ypre = Owned(y); @*/ -/*@ ensures take Ypost = Owned(y); @*/ + take Xpre = RW(x); + take Ypre = RW(y); @*/ +/*@ ensures take Ypost = RW(y); @*/ { *x = 7; my_free_int(x); diff --git a/src/example-archive/simple-examples/working/list_2.c b/src/example-archive/simple-examples/working/list_2.c index bb51d081..07b1157d 100644 --- a/src/example-archive/simple-examples/working/list_2.c +++ b/src/example-archive/simple-examples/working/list_2.c @@ -12,7 +12,7 @@ /*@ lemma IntListSeqSnoc(pointer p, pointer tail) requires take l1 = IntListSeg(p, tail); - take v = Owned(tail); + take v = RW(tail); ensures take l2 = IntListSeg(p, v.next); l2 == append(l1, Seq_Cons { val: v.val, next: Seq_Nil {} }); @*/ diff --git a/src/example-archive/simple-examples/working/list_3.c b/src/example-archive/simple-examples/working/list_3.c index 09e948fc..38a90f80 100644 --- a/src/example-archive/simple-examples/working/list_3.c +++ b/src/example-archive/simple-examples/working/list_3.c @@ -11,7 +11,7 @@ predicate (datatype seq) IntListSegVal(pointer p, pointer tail, i32 tval) { if (addr_eq(p,tail)) { return Seq_Nil{}; } else { - take H = Owned(p); + take H = RW(p); assert (is_null(H.next) || H.next != NULL); assert (H.val == tval); take tl = IntListSeg(H.next, tail); @@ -22,7 +22,7 @@ predicate (datatype seq) IntListSegVal(pointer p, pointer tail, i32 tval) { /*@ lemma IntListSeqSnocVal(pointer p, pointer tail, i32 tval) requires take l1 = IntListSegVal(p, tail, tval); - take v = Owned(tail); + take v = RW(tail); v.val == tval; ensures take l2 = IntListSegVal(p, v.next, tval); l2 == append(l1, Seq_Cons { val: v.val, next: Seq_Nil {} }); diff --git a/src/example-archive/simple-examples/working/list_preds.h b/src/example-archive/simple-examples/working/list_preds.h index 61008b04..66b0ec04 100644 --- a/src/example-archive/simple-examples/working/list_preds.h +++ b/src/example-archive/simple-examples/working/list_preds.h @@ -28,7 +28,7 @@ predicate (datatype seq) IntListSeg(pointer p, pointer tail) { if (ptr_eq(p,tail)) { return Seq_Nil{}; } else { - take H = Owned(p); + take H = RW(p); take tl = IntListSeg(H.next, tail); return (Seq_Cons { val: H.val, next: tl }); } diff --git a/src/example-archive/simple-examples/working/malloc_1.c b/src/example-archive/simple-examples/working/malloc_1.c index 9259c221..aa4fb8af 100644 --- a/src/example-archive/simple-examples/working/malloc_1.c +++ b/src/example-archive/simple-examples/working/malloc_1.c @@ -5,17 +5,17 @@ int *my_malloc__int() /*@ trusted; @*/ -/*@ ensures take New = Block(return); @*/ +/*@ ensures take New = W(return); @*/ {} int *malloc__1() /*@ ensures - take New = Owned(return); + take New = RW(return); New == 7i32; *return == 7i32; @*/ // <-- Alternative syntax { int *new; new = my_malloc__int(); - *new = 7; // Have to initialize the memory before it's owned + *new = 7; // Have to initialize the memory before it's RW return new; } diff --git a/src/example-archive/simple-examples/working/pred_2.c b/src/example-archive/simple-examples/working/pred_2.c index cee0756f..27eaf079 100644 --- a/src/example-archive/simple-examples/working/pred_2.c +++ b/src/example-archive/simple-examples/working/pred_2.c @@ -4,7 +4,7 @@ // Variant 1 - this works: /*@ predicate (i32) TestMemoryEqZero_2_var1(pointer p) { - take PVal = Owned(p); + take PVal = RW(p); let rval = test_if_zero(PVal); return rval; } @@ -20,7 +20,7 @@ function (i32) test_if_zero(i32 x) { void pred_2_var1(int *p) /*@ requires - take PreP = Owned(p); + take PreP = RW(p); PreP == 0i32; @*/ /*@ ensures take TestP = TestMemoryEqZero_2_var1(p); @@ -32,7 +32,7 @@ void pred_2_var1(int *p) // Variant 2 - this works: /*@ predicate (i32) TestMemoryEqZero_2_var2(pointer p) { - take PVal = Owned(p); + take PVal = RW(p); take rval = TestMemoryEqZero_2_Helper(p, PVal); return rval; } @@ -48,7 +48,7 @@ predicate (i32) TestMemoryEqZero_2_Helper(pointer p, i32 x) { void pred_2_var2(int *p) /*@ requires - take PreP = Owned(p); + take PreP = RW(p); PreP == 0i32; @*/ /*@ ensures take TestP = TestMemoryEqZero_2_var2(p); @@ -60,7 +60,7 @@ void pred_2_var2(int *p) // Variant 3 - this works: /*@ predicate (i32) TestMemoryEqZero_2_var3(pointer p) { - take PVal = Owned(p); + take PVal = RW(p); let rval = (PVal == 0i32 ? 1i32 : 0i32); return rval; } @@ -68,7 +68,7 @@ predicate (i32) TestMemoryEqZero_2_var3(pointer p) { void pred_2_var3(int *p) /*@ requires - take PreP = Owned(p); + take PreP = RW(p); PreP == 0i32; @*/ /*@ ensures take TestP = TestMemoryEqZero_2_var3(p); diff --git a/src/example-archive/simple-examples/working/struct_1.c b/src/example-archive/simple-examples/working/struct_1.c index 831ed01c..2465dd24 100644 --- a/src/example-archive/simple-examples/working/struct_1.c +++ b/src/example-archive/simple-examples/working/struct_1.c @@ -7,9 +7,9 @@ struct s }; void struct_1(struct s *p) -/*@ requires take StructPre = Owned(p); @*/ +/*@ requires take StructPre = RW(p); @*/ /*@ ensures - take StructPost = Owned(p); + take StructPost = RW(p); StructPre.x == StructPost.x; StructPost.y == 0i32; @*/ { diff --git a/src/example-archive/simple-examples/working/swap_1.c b/src/example-archive/simple-examples/working/swap_1.c index 6bdb45cd..483547f2 100644 --- a/src/example-archive/simple-examples/working/swap_1.c +++ b/src/example-archive/simple-examples/working/swap_1.c @@ -2,11 +2,11 @@ void swap_1(int *a, int *b) /*@ requires - take Pa = Owned(a); - take Pb = Owned(b); @*/ + take Pa = RW(a); + take Pb = RW(b); @*/ /*@ ensures - take Qa = Owned(a); - take Qb = Owned(b); + take Qa = RW(a); + take Qb = RW(b); Qb == Pa; Qa == Pb; @*/ { diff --git a/src/example-archive/simple-examples/working/write_1.c b/src/example-archive/simple-examples/working/write_1.c index 2ce303c9..bde260db 100644 --- a/src/example-archive/simple-examples/working/write_1.c +++ b/src/example-archive/simple-examples/working/write_1.c @@ -1,9 +1,9 @@ // Write into a memory cell void write_1(int *cell) -/*@ requires take CellPre = Owned(cell); @*/ +/*@ requires take CellPre = RW(cell); @*/ /*@ ensures - take CellPost = Owned(cell); + take CellPost = RW(cell); CellPost == 7i32; @*/ { *cell = 7; diff --git a/src/example-archive/simple-examples/working/write_2.c b/src/example-archive/simple-examples/working/write_2.c index d5ce2e9c..abc798f5 100644 --- a/src/example-archive/simple-examples/working/write_2.c +++ b/src/example-archive/simple-examples/working/write_2.c @@ -1,10 +1,10 @@ // Write into two memory cells void write_2(int *cell1, int *cell2) -/*@ requires take Cell1Pre = Owned(cell1); - take Cell2Pre = Owned(cell2); @*/ -/*@ ensures take Cell1Post = Owned(cell1); - take Cell2Post = Owned(cell2); +/*@ requires take Cell1Pre = RW(cell1); + take Cell2Pre = RW(cell2); @*/ +/*@ ensures take Cell1Post = RW(cell1); + take Cell2Post = RW(cell2); Cell1Post == 7i32; Cell2Post == 8i32; @*/ { *cell1 = 7; diff --git a/src/example-archive/simple-examples/working/write_3.c b/src/example-archive/simple-examples/working/write_3.c index fcd1dad9..342c7d39 100644 --- a/src/example-archive/simple-examples/working/write_3.c +++ b/src/example-archive/simple-examples/working/write_3.c @@ -2,10 +2,10 @@ void write_3(int *cell1, int *cell2) /*@ requires - take Cell1Pre = Owned(cell1); + take Cell1Pre = RW(cell1); cell1 == cell2; @*/ /*@ ensures - take Cell2Post = Owned(cell2); + take Cell2Post = RW(cell2); Cell2Post == 8i32; @*/ { *cell1 = 7; diff --git a/src/example-archive/simple-examples/working/write_4.c b/src/example-archive/simple-examples/working/write_4.c index 4f6eee24..9971bda0 100644 --- a/src/example-archive/simple-examples/working/write_4.c +++ b/src/example-archive/simple-examples/working/write_4.c @@ -4,11 +4,11 @@ static int *cell1, *cell2; void write_4() /*@ accesses cell1, cell2; requires - take Cell1Pre = Owned(cell1); - take Cell2Pre = Owned(cell2); + take Cell1Pre = RW(cell1); + take Cell2Pre = RW(cell2); ensures - take Cell1Post = Owned(cell1); - take Cell2Post = Owned(cell2); + take Cell1Post = RW(cell1); + take Cell2Post = RW(cell2); Cell1Post == 7i32; Cell2Post == 8i32; @*/ { diff --git a/src/example-archive/simple-examples/working/write_5.c b/src/example-archive/simple-examples/working/write_5.c index 2fe0c727..07d4e634 100644 --- a/src/example-archive/simple-examples/working/write_5.c +++ b/src/example-archive/simple-examples/working/write_5.c @@ -2,11 +2,11 @@ void write_5(int *pair) /*@ requires - take Cell1Pre = Owned(pair); - take Cell2Pre = Owned(pair + 1i32); @*/ + take Cell1Pre = RW(pair); + take Cell2Pre = RW(pair + 1i32); @*/ /*@ ensures - take Cell1Post = Owned(pair); - take Cell2Post = Owned(pair + 1i32); + take Cell1Post = RW(pair); + take Cell2Post = RW(pair + 1i32); Cell1Post == 7i32; Cell2Post == 8i32; @*/ { @@ -18,15 +18,15 @@ void write_5(int *pair) void write_5_alt(int *pair) /*@ requires - take PairPre = each (i32 j; j == 0i32 || j == 1i32) {Owned(pair + j)}; @*/ + take PairPre = each (i32 j; j == 0i32 || j == 1i32) {RW(pair + j)}; @*/ /*@ ensures - take PairPost = each (i32 j; j == 0i32 || j == 1i32) {Owned(pair + j)}; + take PairPost = each (i32 j; j == 0i32 || j == 1i32) {RW(pair + j)}; PairPost[0i32] == 7i32; PairPost[1i32] == 8i32; @*/ { - /*@ extract Owned, 0i32; @*/ + /*@ focus RW, 0i32; @*/ pair[0] = 7; - /*@ extract Owned, 1i32; @*/ + /*@ focus RW, 1i32; @*/ pair[1] = 8; } diff --git a/src/exercises/abs_mem.c b/src/exercises/abs_mem.c index 978fefa0..3a188c3f 100644 --- a/src/exercises/abs_mem.c +++ b/src/exercises/abs_mem.c @@ -1,8 +1,8 @@ int abs_mem (int *p) /* --BEGIN-- */ -/*@ requires take x = Owned(p); +/*@ requires take x = RW(p); MINi32() < x; - ensures take x_post = Owned(p); + ensures take x_post = RW(p); x == x_post; return == ((x >= 0i32) ? x : (0i32-x)); @*/ diff --git a/src/exercises/abs_mem_struct.c b/src/exercises/abs_mem_struct.c index 92a3005f..0bf68750 100644 --- a/src/exercises/abs_mem_struct.c +++ b/src/exercises/abs_mem_struct.c @@ -1,8 +1,8 @@ int abs_mem (int *p) /* --BEGIN-- */ -/*@ requires take x = Owned(p); +/*@ requires take x = RW(p); MINi32() < x; - ensures take x2 = Owned(p); + ensures take x2 = RW(p); x == x2; return == ((x >= 0i32) ? x : (0i32-x)); @*/ @@ -26,9 +26,9 @@ struct tuple { int abs_y (struct tuple *p) -/*@ requires take s = Owned(p); +/*@ requires take s = RW(p); MINi32() < s.y; - ensures take s2 = Owned(p); + ensures take s2 = RW(p); s == s2; return == ((s.y >= 0i32) ? s.y : (0i32-s.y)); @*/ diff --git a/src/exercises/add_read.c b/src/exercises/add_read.c index 2341bd04..bb93e867 100644 --- a/src/exercises/add_read.c +++ b/src/exercises/add_read.c @@ -1,8 +1,8 @@ unsigned int add (unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); - take Q = Owned(q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P == P_post && Q == Q_post; return == P + Q; @*/ diff --git a/src/exercises/add_two_array.c b/src/exercises/add_two_array.c index 70a8e5fc..8789bd22 100644 --- a/src/exercises/add_two_array.c +++ b/src/exercises/add_two_array.c @@ -1,23 +1,23 @@ unsigned int array_read_two (unsigned int *p, int n, int i, int j) /* --BEGIN-- */ /*@ requires take A = each(i32 k; 0i32 <= k && k < n) { - Owned(array_shift(p,k)) }; + RW(array_shift(p,k)) }; 0i32 <= i && i < n; 0i32 <= j && j < n; j != i; ensures take A_post = each(i32 k; 0i32 <= k && k < n) { - Owned(array_shift(p,k)) }; + RW(array_shift(p,k)) }; A == A_post; return == A[i] + A[j]; @*/ /* --END-- */ { /* --BEGIN-- */ - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ /* --END-- */ unsigned int tmp1 = p[i]; /* --BEGIN-- */ - /*@ extract Owned, j; @*/ + /*@ focus RW, j; @*/ /* --END-- */ unsigned int tmp2 = p[j]; return (tmp1 + tmp2); diff --git a/src/exercises/array_load.c b/src/exercises/array_load.c index 6cd87216..58e039a2 100644 --- a/src/exercises/array_load.c +++ b/src/exercises/array_load.c @@ -1,11 +1,11 @@ int read (int *p, int n, int i) /*@ requires take A = each(i32 j; 0i32 <= j && j < n) { - Owned(array_shift(p,j)) }; + RW(array_shift(p,j)) }; 0i32 <= i && i < n; ensures take A_post = each(i32 j; 0i32 <= j && j < n) { - Owned(array_shift(p,j)) }; + RW(array_shift(p,j)) }; @*/ { - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ return p[i]; } diff --git a/src/exercises/array_load.test.c b/src/exercises/array_load.test.c index f440a434..f3c145b2 100644 --- a/src/exercises/array_load.test.c +++ b/src/exercises/array_load.test.c @@ -1,9 +1,9 @@ int read (unsigned int *p, unsigned int n, unsigned int i) /*@ requires take A = each(u32 j; 0u32 <= j && j < n) { - Owned(array_shift(p,j)) }; + RW(array_shift(p,j)) }; i < n; ensures take A_post = each(u32 j; 0u32 <= j && j < n) { - Owned(array_shift(p,j)) }; + RW(array_shift(p,j)) }; @*/ { return p[i]; diff --git a/src/exercises/array_load2.c b/src/exercises/array_load2.c index 4f38a1f1..fdc98e88 100644 --- a/src/exercises/array_load2.c +++ b/src/exercises/array_load2.c @@ -1,11 +1,11 @@ int read (int *p, int n, int i) -/*@ requires take a1 = each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) }; +/*@ requires take a1 = each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) }; 0i32 <= i && i < n; - ensures take a2 = each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) }; + ensures take a2 = each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) }; a1 == a2; return == a1[i]; @*/ { - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ return p[i]; } diff --git a/src/exercises/bcp_framerule.c b/src/exercises/bcp_framerule.c index 1f5d3a10..d0a6caf3 100644 --- a/src/exercises/bcp_framerule.c +++ b/src/exercises/bcp_framerule.c @@ -1,6 +1,6 @@ void incr_first (unsigned int *p, unsigned int *q) -/*@ requires take pv = Owned(p); - ensures take pv_ = Owned(p); +/*@ requires take pv = RW(p); + ensures take pv_ = RW(p); pv_ == pv + 1u32; @*/ { @@ -10,10 +10,10 @@ void incr_first (unsigned int *p, unsigned int *q) } void incr_first_frame (unsigned int *p, unsigned int *q) -/*@ requires take pv = Owned(p); - take qv = Owned(q); - ensures take pv_ = Owned(p); - take qv_ = Owned(q); +/*@ requires take pv = RW(p); + take qv = RW(q); + ensures take pv_ = RW(p); + take qv_ = RW(q); pv_ == pv + 1u32; qv_ == qv; @*/ diff --git a/src/exercises/dll/dllist_and_int.h b/src/exercises/dll/dllist_and_int.h index 229350e4..d1b05807 100644 --- a/src/exercises/dll/dllist_and_int.h +++ b/src/exercises/dll/dllist_and_int.h @@ -6,12 +6,12 @@ struct dllist_and_int { extern struct dllist_and_int *malloc__dllist_and_int(); /*@ spec malloc__dllist_and_int(); requires true; - ensures take R = Block(return); + ensures take R = W(return); !ptr_eq(return,NULL); @*/ extern void free__dllist_and_int (struct dllist_and_int *p); /*@ spec free__dllist_and_int(pointer p); - requires take R = Block(p); + requires take R = W(p); ensures true; @*/ diff --git a/src/exercises/dll/malloc_free.h b/src/exercises/dll/malloc_free.h index a18b81c6..815dc139 100644 --- a/src/exercises/dll/malloc_free.h +++ b/src/exercises/dll/malloc_free.h @@ -1,12 +1,12 @@ extern struct dllist *malloc__dllist(); /*@ spec malloc__dllist(); requires true; - ensures take R = Block(return); + ensures take R = W(return); !ptr_eq(return,NULL); @*/ extern void free__dllist (struct dllist *p); /*@ spec free__dllist(pointer p); - requires take R = Block(p); + requires take R = W(p); ensures true; @*/ diff --git a/src/exercises/dll/predicates.h b/src/exercises/dll/predicates.h index 52a00a66..d8f00e11 100644 --- a/src/exercises/dll/predicates.h +++ b/src/exercises/dll/predicates.h @@ -3,7 +3,7 @@ predicate (datatype Dll) Dll_at (pointer p) { if (is_null(p)) { return Empty_Dll{}; } else { - take n = Owned(p); + take n = RW(p); take L = Own_Backwards(n.prev, p, n); take R = Own_Forwards(n.next, p, n); return Nonempty_Dll{left: L, curr: n, right: R}; @@ -16,7 +16,7 @@ predicate (datatype List) Own_Forwards (pointer p, if (is_null(p)) { return Nil{}; } else { - take P = Owned(p); + take P = RW(p); assert (ptr_eq(P.prev, prev_pointer)); assert(ptr_eq(prev_dllist.next, p)); take T = Own_Forwards(P.next, p, P); @@ -30,7 +30,7 @@ predicate (datatype List) Own_Backwards (pointer p, if (is_null(p)) { return Nil{}; } else { - take P = Owned(p); + take P = RW(p); assert (ptr_eq(P.next, next_pointer)); assert(ptr_eq(next_dllist.prev, p)); take T = Own_Backwards(P.prev, p, P); diff --git a/src/exercises/dll/remove.c b/src/exercises/dll/remove.c index 5169007c..5aad3846 100644 --- a/src/exercises/dll/remove.c +++ b/src/exercises/dll/remove.c @@ -7,7 +7,7 @@ struct dllist_and_int *remove(struct dllist *n) /*@ requires !is_null(n); take Before = Dll_at(n); let Del = Node(Before); - ensures take Ret = Owned(return); + ensures take Ret = RW(return); take After = Dll_at(Ret.dllist); Ret.data == Del.data; (is_null(Del.prev) && is_null(Del.next)) diff --git a/src/exercises/free.h b/src/exercises/free.h index b5eb5832..9da5813c 100644 --- a/src/exercises/free.h +++ b/src/exercises/free.h @@ -1,13 +1,13 @@ extern void freeInt (int *p); /*@ spec freeInt(pointer p); - requires take P = Block(p); + requires take P = W(p); ensures true; @*/ extern void freeUnsignedInt (unsigned int *p); /*@ spec freeUnsignedInt(pointer p); - requires take P = Block(p); + requires take P = W(p); ensures true; @*/ diff --git a/src/exercises/init_array.c b/src/exercises/init_array.c index b288cb1c..f1609062 100644 --- a/src/exercises/init_array.c +++ b/src/exercises/init_array.c @@ -1,22 +1,22 @@ void init_array (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; ensures take A_post = each(u32 i; i < n) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; @*/ { unsigned int j = 0; while (j < n) /* --BEGIN-- */ /*@ inv take Ai = each(u32 i; i < n) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; {p} unchanged; {n} unchanged; @*/ /* --END-- */ { /* --BEGIN-- */ - /*@ extract Owned, j; @*/ + /*@ focus RW, j; @*/ /* --END-- */ p[j] = 0; j++; diff --git a/src/exercises/init_array2.c b/src/exercises/init_array2.c index f447f553..5f49e1eb 100644 --- a/src/exercises/init_array2.c +++ b/src/exercises/init_array2.c @@ -1,25 +1,25 @@ void init_array2 (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { - Block( array_shift(p, i)) }; + W( array_shift(p, i)) }; ensures take A_post = each(u32 i; i < n) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; @*/ { unsigned int j = 0; while (j < n) /* --BEGIN-- */ /*@ inv take Al = each(u32 i; i < j) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; take Ar = each(u32 i; j <= i && i < n) { - Block( array_shift(p, i)) }; + W( array_shift(p, i)) }; {p} unchanged; {n} unchanged; j <= n; @*/ /* --END-- */ { /* --BEGIN-- */ - /*@ extract Block, j; @*/ - /*@ extract Owned, j; @*/ + /*@ focus W, j; @*/ + /*@ focus RW, j; @*/ /* --END-- */ p[j] = 0; j++; diff --git a/src/exercises/init_array_rev.c b/src/exercises/init_array_rev.c index e46b4f3f..dbf9e98d 100644 --- a/src/exercises/init_array_rev.c +++ b/src/exercises/init_array_rev.c @@ -1,26 +1,26 @@ void init_array_rev (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { - Block( array_shift(p, i)) }; + W( array_shift(p, i)) }; n > 0u32; ensures take A_post = each(u32 i; i < n) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; @*/ { unsigned int j = 0; while (j < n) /* --BEGIN-- */ /*@ inv take Al = each(u32 i; i < n-j) { - Block( array_shift(p, i)) }; + W( array_shift(p, i)) }; take Ar = each(u32 i; n-j <= i && i < n) { - Owned( array_shift(p, i)) }; + RW( array_shift(p, i)) }; {p} unchanged; {n} unchanged; 0u32 <= j && j <= n; @*/ /* --END-- */ { /* --BEGIN-- */ - /*@ extract Block, n-(j+1u32); @*/ - /*@ extract Owned, n-(j+1u32); @*/ + /*@ focus W, n-(j+1u32); @*/ + /*@ focus RW, n-(j+1u32); @*/ /* --END-- */ p[n-(j+1)] = 0; j++; diff --git a/src/exercises/init_point.c b/src/exercises/init_point.c index b43f2618..659ec522 100644 --- a/src/exercises/init_point.c +++ b/src/exercises/init_point.c @@ -1,6 +1,6 @@ void zero (unsigned int *coord) -/*@ requires take Coord = Block(coord); - ensures take Coord_post = Owned(coord); +/*@ requires take Coord = W(coord); + ensures take Coord_post = RW(coord); Coord_post == 0u32; @*/ { *coord = 0; @@ -9,8 +9,8 @@ void zero (unsigned int *coord) struct point { unsigned int x; unsigned int y; }; void init_point(struct point *p) -/*@ requires take P = Block(p); - ensures take P_post = Owned(p); +/*@ requires take P = W(p); + ensures take P_post = RW(p); P_post.x == 0u32; P_post.y == 0u32; @*/ diff --git a/src/exercises/list/c_types.test.h b/src/exercises/list/c_types.test.h index 8cd0ded2..f4c8150e 100644 --- a/src/exercises/list/c_types.test.h +++ b/src/exercises/list/c_types.test.h @@ -6,14 +6,14 @@ struct sllist { }; struct sllist *malloc__sllist() -/*@ ensures take R = Block(return); +/*@ ensures take R = W(return); @*/ { return cn_malloc(sizeof(struct sllist)); } void free__sllist (struct sllist *p) -/*@ requires take P = Block(p); +/*@ requires take P = W(p); @*/ { cn_free_sized(p, sizeof(struct sllist)); diff --git a/src/exercises/list/c_types.verif.h b/src/exercises/list/c_types.verif.h index 7caa03b3..daa8b750 100644 --- a/src/exercises/list/c_types.verif.h +++ b/src/exercises/list/c_types.verif.h @@ -6,12 +6,12 @@ struct sllist { extern struct sllist *malloc__sllist(); /*@ spec malloc__sllist(); requires true; - ensures take R = Block(return); + ensures take R = W(return); @*/ extern void free__sllist (struct sllist *p); /*@ spec free__sllist(pointer p); - requires take P = Block(p); + requires take P = W(p); ensures true; @*/ diff --git a/src/exercises/list/cn_types.h b/src/exercises/list/cn_types.h index 102923c5..b4be8911 100644 --- a/src/exercises/list/cn_types.h +++ b/src/exercises/list/cn_types.h @@ -8,7 +8,7 @@ predicate (datatype List) SLList_At(pointer p) { if (is_null(p)) { return Nil{}; } else { - take H = Owned(p); + take H = RW(p); take T = SLList_At(H.tail); return (Cons { Head: H.head, Tail: T }); } diff --git a/src/exercises/malloc.h b/src/exercises/malloc.h index fe2c2fc2..d0439c88 100644 --- a/src/exercises/malloc.h +++ b/src/exercises/malloc.h @@ -1,12 +1,12 @@ extern int *mallocInt (); /*@ spec mallocInt(); requires true; - ensures take R = Block(return); + ensures take R = W(return); @*/ extern unsigned int *mallocUnsignedInt (); /*@ spec mallocUnsignedInt(); requires true; - ensures take R = Block(return); + ensures take R = W(return); @*/ diff --git a/src/exercises/malloc_alt.h b/src/exercises/malloc_alt.h index e7a733df..e1068995 100644 --- a/src/exercises/malloc_alt.h +++ b/src/exercises/malloc_alt.h @@ -1,13 +1,13 @@ extern int *mallocInt (); /*@ spec mallocInt() requires true - ensures take v = Block(return) + ensures take v = W(return) @*/ extern unsigned int *mallocUnsignedInt (); /*@ spec mallocUnsignedInt() requires true - ensures take v = Block(return) + ensures take v = W(return) @*/ diff --git a/src/exercises/queue/allocation.verif.h b/src/exercises/queue/allocation.verif.h index c507bf2e..d9fddd76 100644 --- a/src/exercises/queue/allocation.verif.h +++ b/src/exercises/queue/allocation.verif.h @@ -1,23 +1,23 @@ extern struct queue *malloc_queue(); /*@ spec malloc_queue(); requires true; - ensures take R = Block(return); + ensures take R = W(return); @*/ extern void free_queue (struct queue *p); /*@ spec free_queue(pointer p); - requires take P = Block(p); + requires take P = W(p); ensures true; @*/ extern struct queue_cell *malloc_queue_cell(); /*@ spec malloc_queue_cell(); requires true; - ensures take R = Block(return); + ensures take R = W(return); @*/ extern void free_queue_cell (struct queue_cell *p); /*@ spec free_queue_cell(pointer p); - requires take P = Block(p); + requires take P = W(p); ensures true; @*/ diff --git a/src/exercises/queue/cn_types_1.h b/src/exercises/queue/cn_types_1.h index 9bc4e1d0..2c975e96 100644 --- a/src/exercises/queue/cn_types_1.h +++ b/src/exercises/queue/cn_types_1.h @@ -1,6 +1,6 @@ /*@ predicate (datatype List) QueuePtr_At (pointer q) { - take Q = Owned(q); + take Q = RW(q); assert ( (is_null(Q.front) && is_null(Q.back)) || (!is_null(Q.front) && !is_null(Q.back))); take L = QueueFB(Q.front, Q.back); diff --git a/src/exercises/queue/cn_types_2.h b/src/exercises/queue/cn_types_2.h index b478b7e5..2291fdc5 100644 --- a/src/exercises/queue/cn_types_2.h +++ b/src/exercises/queue/cn_types_2.h @@ -3,7 +3,7 @@ predicate (datatype List) QueueFB (pointer front, pointer back) { if (is_null(front)) { return Nil{}; } else { - take B = Owned(back); + take B = RW(back); assert (is_null(B.next)); assert (ptr_eq(front, back) || !addr_eq(front, back)); take L = QueueAux (front, back); diff --git a/src/exercises/queue/cn_types_3.test.h b/src/exercises/queue/cn_types_3.test.h index 73bfca7f..59455ee9 100644 --- a/src/exercises/queue/cn_types_3.test.h +++ b/src/exercises/queue/cn_types_3.test.h @@ -3,7 +3,7 @@ predicate (datatype List) QueueAux (pointer f, pointer b) { if (ptr_eq(f,b)) { return Nil{}; } else { - take F = Owned(f); + take F = RW(f); assert (!is_null(F.next)); assert (ptr_eq(F.next, b) || !addr_eq(F.next, b)); take B = QueueAux(F.next, b); diff --git a/src/exercises/queue/cn_types_3.verif.h b/src/exercises/queue/cn_types_3.verif.h index 73bfca7f..59455ee9 100644 --- a/src/exercises/queue/cn_types_3.verif.h +++ b/src/exercises/queue/cn_types_3.verif.h @@ -3,7 +3,7 @@ predicate (datatype List) QueueAux (pointer f, pointer b) { if (ptr_eq(f,b)) { return Nil{}; } else { - take F = Owned(f); + take F = RW(f); assert (!is_null(F.next)); assert (ptr_eq(F.next, b) || !addr_eq(F.next, b)); take B = QueueAux(F.next, b); diff --git a/src/exercises/queue/pop_lemma.h b/src/exercises/queue/pop_lemma.h index 0188cda5..ef76aaab 100644 --- a/src/exercises/queue/pop_lemma.h +++ b/src/exercises/queue/pop_lemma.h @@ -2,10 +2,10 @@ lemma snoc_facts (pointer front, pointer back, i32 x) requires take Q = QueueAux(front, back); - take B = Owned(back); + take B = RW(back); ensures take Q_post = QueueAux(front, back); - take B_post = Owned(back); + take B_post = RW(back); Q == Q_post; B == B_post; let L = Snoc (Cons{Head: x, Tail: Q}, B.first); Hd(L) == x; diff --git a/src/exercises/queue/pop_unified.c b/src/exercises/queue/pop_unified.c index 06f0a91f..3ae33cbf 100644 --- a/src/exercises/queue/pop_unified.c +++ b/src/exercises/queue/pop_unified.c @@ -7,7 +7,7 @@ predicate (result) Queue_pop_lemma(pointer front, pointer back, i32 popped) { if (is_null(front)) { return { after: Nil{}, before: Snoc(Nil{}, popped) }; } else { - take B = Owned(back); + take B = RW(back); assert (is_null(B.next)); take L = QueueAux (front, back); return { after: Snoc(L, B.first), before: Snoc(Cons {Head: popped, Tail: L}, B.first) }; @@ -19,10 +19,10 @@ void snoc_fact(struct queue_cell *front, struct queue_cell *back, int x) /*@ requires take Q = QueueAux(front, back); - take B = Owned(back); + take B = RW(back); ensures take Q_post = QueueAux(front, back); - take B_post = Owned(back); + take B_post = RW(back); Q == Q_post; B == B_post; let L = Snoc (Cons{Head: x, Tail: Q}, B.first); Hd(L) == x; diff --git a/src/exercises/queue/push_induction.c b/src/exercises/queue/push_induction.c index e62f52cb..37b2ad34 100644 --- a/src/exercises/queue/push_induction.c +++ b/src/exercises/queue/push_induction.c @@ -7,13 +7,13 @@ void push_induction(struct queue_cell* front requires ptr_eq(front, second_last) || !addr_eq(front, second_last); take Q = QueueAux(front, second_last); - take Second_last = Owned(second_last); + take Second_last = RW(second_last); ptr_eq(Second_last.next, last); - take Last = Owned(last); + take Last = RW(last); ensures ptr_eq(front, last) || !addr_eq(front, last); take Q_post = QueueAux(front, last); - take Last2 = Owned(last); + take Last2 = RW(last); Q_post == Snoc(Q, Second_last.first); Last == Last2; @*/ diff --git a/src/exercises/queue/push_lemma.h b/src/exercises/queue/push_lemma.h index 0692c1d0..00ba86d7 100644 --- a/src/exercises/queue/push_lemma.h +++ b/src/exercises/queue/push_lemma.h @@ -3,7 +3,7 @@ lemma push_lemma (pointer front, pointer p) requires ptr_eq(front, p) || !addr_eq(front, p); take Q = QueueAux(front, p); - take P = Owned(p); + take P = RW(p); ensures ptr_eq(front, P.next) || !addr_eq(front, P.next); take Q_post = QueueAux(front, P.next); diff --git a/src/exercises/read.broken.c b/src/exercises/read.broken.c index d08ee184..1ccc2699 100644 --- a/src/exercises/read.broken.c +++ b/src/exercises/read.broken.c @@ -1,5 +1,5 @@ unsigned int read (unsigned int *p) -/*@ requires take v1 = Owned(p); @*/ +/*@ requires take v1 = RW(p); @*/ { return *p; } diff --git a/src/exercises/read.c b/src/exercises/read.c index 6441a695..ef4d9447 100644 --- a/src/exercises/read.c +++ b/src/exercises/read.c @@ -1,7 +1,7 @@ unsigned int read (unsigned int *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = RW(p); + ensures take P_post = RW(p); @*/ /* --END-- */ { diff --git a/src/exercises/read2.c b/src/exercises/read2.c index 4f8b4502..32ac8cb3 100644 --- a/src/exercises/read2.c +++ b/src/exercises/read2.c @@ -1,6 +1,6 @@ unsigned int read (unsigned int *p) -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = RW(p); + ensures take P_post = RW(p); return == P; P_post == P; @*/ diff --git a/src/exercises/ref.h b/src/exercises/ref.h index bbb83fa0..de69904b 100644 --- a/src/exercises/ref.h +++ b/src/exercises/ref.h @@ -1,14 +1,14 @@ extern unsigned int *refUnsignedInt (unsigned int v); /*@ spec refUnsignedInt(u32 v); requires true; - ensures take R = Owned(return); + ensures take R = RW(return); R == v; @*/ extern int *refInt (int v); /*@ spec refInt(i32 v); requires true; - ensures take R = Owned(return); + ensures take R = RW(return); R == v; @*/ diff --git a/src/exercises/slf0_basic_incr.c b/src/exercises/slf0_basic_incr.c index 51aa8f43..51105193 100644 --- a/src/exercises/slf0_basic_incr.c +++ b/src/exercises/slf0_basic_incr.c @@ -1,6 +1,6 @@ void incr (unsigned int *p) -/*@ requires take n1 = Owned(p); - ensures take n2 = Owned(p); +/*@ requires take n1 = RW(p); + ensures take n2 = RW(p); n2 == n1 + 1u32; @*/ { diff --git a/src/exercises/slf0_basic_incr.signed.broken.c b/src/exercises/slf0_basic_incr.signed.broken.c index 3fbd627d..6ade0b32 100644 --- a/src/exercises/slf0_basic_incr.signed.broken.c +++ b/src/exercises/slf0_basic_incr.signed.broken.c @@ -1,6 +1,6 @@ void incr (int *p) -/*@ requires take P = Block(p); - ensures take P_post = Owned(p); +/*@ requires take P = W(p); + ensures take P_post = RW(p); @*/ { *p = *p+1; diff --git a/src/exercises/slf0_basic_incr.signed.c b/src/exercises/slf0_basic_incr.signed.c index 2986c617..e8f04e84 100644 --- a/src/exercises/slf0_basic_incr.signed.c +++ b/src/exercises/slf0_basic_incr.signed.c @@ -1,7 +1,7 @@ void incr (int *p) -/*@ requires take P = Owned(p); +/*@ requires take P = RW(p); ((i64) P) + 1i64 <= (i64) MAXi32(); - ensures take P_post = Owned(p); + ensures take P_post = RW(p); P_post == P + 1i32; @*/ { diff --git a/src/exercises/slf0_incr.broken.c b/src/exercises/slf0_incr.broken.c index 995e5c0e..dc1567e2 100644 --- a/src/exercises/slf0_incr.broken.c +++ b/src/exercises/slf0_incr.broken.c @@ -1,7 +1,7 @@ void incr (int *p) /* --BEGIN-- */ -/*@ requires take v1 = Block(p); - ensures take v2 = Owned(p); +/*@ requires take v1 = W(p); + ensures take v2 = RW(p); v2 == v1+1i32; @*/ /* --END-- */ { diff --git a/src/exercises/slf10_basic_ref.c b/src/exercises/slf10_basic_ref.c index 49c2ad45..a516bb74 100644 --- a/src/exercises/slf10_basic_ref.c +++ b/src/exercises/slf10_basic_ref.c @@ -1,7 +1,7 @@ extern unsigned int *refUnsignedInt (unsigned int v); /*@ spec refUnsignedInt(u32 v); requires true; - ensures take vr = Owned(return); + ensures take vr = RW(return); vr == v; @*/ diff --git a/src/exercises/slf11_basic_ref_greater.c b/src/exercises/slf11_basic_ref_greater.c index 2ccf25eb..7f7d1e4d 100644 --- a/src/exercises/slf11_basic_ref_greater.c +++ b/src/exercises/slf11_basic_ref_greater.c @@ -2,9 +2,9 @@ unsigned int *ref_greater (unsigned int *p) /* --BEGIN-- */ -/*@ requires take n1 = Owned(p); - ensures take n2 = Owned(p); - take m2 = Owned(return); +/*@ requires take n1 = RW(p); + ensures take n2 = RW(p); + take m2 = RW(return); n2 == n1; m2 == n1 + 1u32; @*/ diff --git a/src/exercises/slf12_basic_ref_greater_abstract.c b/src/exercises/slf12_basic_ref_greater_abstract.c index cc499767..b057989f 100644 --- a/src/exercises/slf12_basic_ref_greater_abstract.c +++ b/src/exercises/slf12_basic_ref_greater_abstract.c @@ -2,10 +2,10 @@ unsigned int *ref_greater (unsigned int *p) /* --BEGIN-- */ -/*@ requires take n1 = Owned(p); +/*@ requires take n1 = RW(p); n1 < n1 + 1u32; - ensures take n2 = Owned(p); - take m2 = Owned(return); + ensures take n2 = RW(p); + take m2 = RW(return); n2 == n1; m2 > n1; @*/ diff --git a/src/exercises/slf13_basic_ref_with_frame.c b/src/exercises/slf13_basic_ref_with_frame.c index b8129a9d..44ff474d 100644 --- a/src/exercises/slf13_basic_ref_with_frame.c +++ b/src/exercises/slf13_basic_ref_with_frame.c @@ -2,10 +2,10 @@ unsigned int *triple_ref_with_frame(unsigned int *p_, unsigned int v) /* --BEGIN-- */ -/*@ requires take v_1 = Owned(p_); - ensures take v_2 = Owned(p_); +/*@ requires take v_1 = RW(p_); + ensures take v_2 = RW(p_); v_2 == v_1; - take vr = Owned(return); + take vr = RW(return); vr == v; @*/ /* --END-- */ diff --git a/src/exercises/slf17_get_and_free.c b/src/exercises/slf17_get_and_free.c index a2238315..a194f69b 100644 --- a/src/exercises/slf17_get_and_free.c +++ b/src/exercises/slf17_get_and_free.c @@ -1,7 +1,7 @@ #include "free.h" unsigned int get_and_free (unsigned int *p) -/*@ requires take P = Owned(p); +/*@ requires take P = RW(p); ensures return == P; @*/ { diff --git a/src/exercises/slf3_basic_inplace_double.c b/src/exercises/slf3_basic_inplace_double.c index ca7cddde..2fcd00f9 100644 --- a/src/exercises/slf3_basic_inplace_double.c +++ b/src/exercises/slf3_basic_inplace_double.c @@ -1,9 +1,9 @@ void inplace_double (int *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); +/*@ requires take P = RW(p); let M = 2i64 * ((i64) P); (i64) MINi32() <= M; M <= (i64) MAXi32(); - ensures take P_post = Owned(p); + ensures take P_post = RW(p); P_post == (i32) M; @*/ /* --END-- */ diff --git a/src/exercises/slf4_basic_incr_two.c b/src/exercises/slf4_basic_incr_two.c index e81f6054..ed1f7b36 100644 --- a/src/exercises/slf4_basic_incr_two.c +++ b/src/exercises/slf4_basic_incr_two.c @@ -1,10 +1,10 @@ #include "slf0_basic_incr.c" void incr_two (unsigned int *p, unsigned int *q) -/*@ requires take n1 = Owned(p); - take m1 = Owned(q); - ensures take n2 = Owned(p); - take m2 = Owned(q); +/*@ requires take n1 = RW(p); + take m1 = RW(q); + ensures take n2 = RW(p); + take m2 = RW(q); n2 == n1 + 1u32; m2 == m1 + 1u32; @*/ diff --git a/src/exercises/slf5_basic_aliased_call.broken.c b/src/exercises/slf5_basic_aliased_call.broken.c index 681ae115..413bffe3 100644 --- a/src/exercises/slf5_basic_aliased_call.broken.c +++ b/src/exercises/slf5_basic_aliased_call.broken.c @@ -1,8 +1,8 @@ #include "slf4_basic_incr_two.c" void aliased_call (unsigned int *p) -/*@ requires take n1 = Owned(p); - ensures take n2 = Owned(p); +/*@ requires take n1 = RW(p); + ensures take n2 = RW(p); n2 == n1 + 2u32; @*/ { incr_two(p, p); diff --git a/src/exercises/slf6_basic_incr_two_aliased_call.c b/src/exercises/slf6_basic_incr_two_aliased_call.c index 6d96c659..e18e39db 100644 --- a/src/exercises/slf6_basic_incr_two_aliased_call.c +++ b/src/exercises/slf6_basic_incr_two_aliased_call.c @@ -2,9 +2,9 @@ void incr_two (unsigned int *p, unsigned int *q) -/*@ requires take n1 = Owned(p); +/*@ requires take n1 = RW(p); ptr_eq(q,p); - ensures take n2 = Owned(p); + ensures take n2 = RW(p); n2 == n1 + 2u32; @*/ { @@ -15,8 +15,8 @@ void incr_two (unsigned int *p, unsigned int *q) void aliased_call (unsigned int *p) -/*@ requires take n1 = Owned(p); - ensures take n2 = Owned(p); +/*@ requires take n1 = RW(p); + ensures take n2 = RW(p); n2 == n1 + 2u32; @*/ { diff --git a/src/exercises/slf7_basic_incr_first.c b/src/exercises/slf7_basic_incr_first.c index cfe34d75..37f63d63 100644 --- a/src/exercises/slf7_basic_incr_first.c +++ b/src/exercises/slf7_basic_incr_first.c @@ -1,10 +1,10 @@ #include "slf0_basic_incr.c" void incr_first(unsigned int *p, unsigned int *q) -/*@ requires take n1 = Owned(p); - take m1 = Owned(q); - ensures take n2 = Owned(p); - take m2 = Owned(q); +/*@ requires take n1 = RW(p); + take m1 = RW(q); + ensures take n2 = RW(p); + take m2 = RW(q); n2 == n1 + 1u32; m2 == m1; @*/ @@ -14,8 +14,8 @@ void incr_first(unsigned int *p, unsigned int *q) void incr_first_(unsigned int *p, unsigned int *q) -/*@ requires take n1 = Owned(p); - ensures take n2 = Owned(p); +/*@ requires take n1 = RW(p); + ensures take n2 = RW(p); n2 == n1 + 1u32; @*/ { diff --git a/src/exercises/slf8_basic_transfer.c b/src/exercises/slf8_basic_transfer.c index 71a80c6a..409a0d0e 100644 --- a/src/exercises/slf8_basic_transfer.c +++ b/src/exercises/slf8_basic_transfer.c @@ -1,9 +1,9 @@ void transfer (unsigned int *p, unsigned int *q) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - take Q = Owned(q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == P + Q; Q_post == 0u32; @*/ diff --git a/src/exercises/slf9_basic_transfer_aliased.c b/src/exercises/slf9_basic_transfer_aliased.c index a3ab3b73..53c4da63 100644 --- a/src/exercises/slf9_basic_transfer_aliased.c +++ b/src/exercises/slf9_basic_transfer_aliased.c @@ -1,7 +1,7 @@ void transfer (unsigned int *p, unsigned int *q) -/*@ requires take n1 = Owned(p); +/*@ requires take n1 = RW(p); ptr_eq(p,q); - ensures take n2 = Owned(p); + ensures take n2 = RW(p); n2 == 0u32; @*/ { diff --git a/src/exercises/slf_incr2.c b/src/exercises/slf_incr2.c index 6ed25927..6488d4e4 100644 --- a/src/exercises/slf_incr2.c +++ b/src/exercises/slf_incr2.c @@ -2,12 +2,12 @@ predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) { if (ptr_eq(p,q)) { - take PX = Owned(p); + take PX = RW(p); return {P: PX, Q: PX}; } else { - take PX = Owned(p); - take QX = Owned(q); + take PX = RW(p); + take QX = RW(q); return {P: PX, Q: QX}; } } @@ -30,11 +30,11 @@ void incr2(unsigned int *p, unsigned int *q) } void call_both_better(unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); - take Q = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); !ptr_eq(p,q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == P + 3u32; Q_post == Q + 1u32; @*/ diff --git a/src/exercises/slf_incr2.test.c b/src/exercises/slf_incr2.test.c index ab324639..65b8bf36 100644 --- a/src/exercises/slf_incr2.test.c +++ b/src/exercises/slf_incr2.test.c @@ -2,12 +2,12 @@ predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) { if (ptr_eq(p,q)) { - take PX = Owned(p); + take PX = RW(p); return {P: PX, Q: PX}; } else { - take PX = Owned(p); - take QX = Owned(q); + take PX = RW(p); + take QX = RW(q); return {P: PX, Q: QX}; } } @@ -29,11 +29,11 @@ void incr2(unsigned int *p, unsigned int *q) } void call_both_better(unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); - take Q = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); !ptr_eq(p,q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == P + 3u32; Q_post == Q + 1u32; @*/ diff --git a/src/exercises/slf_incr2_alias.c b/src/exercises/slf_incr2_alias.c index 2f8cd75c..f50484ab 100644 --- a/src/exercises/slf_incr2_alias.c +++ b/src/exercises/slf_incr2_alias.c @@ -1,9 +1,9 @@ // Increment two different pointers (same as above) void incr2a (unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); - take Q = Owned(q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == P + 1u32; Q_post == Q + 1u32; @*/ @@ -18,9 +18,9 @@ void incr2a (unsigned int *p, unsigned int *q) // Increment the same pointer twice void incr2b (unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); +/*@ requires take P = RW(p); ptr_eq(q,p); - ensures take P_post = Owned(p); + ensures take P_post = RW(p); ptr_eq(q,p); P_post == P + 2u32; @*/ @@ -34,10 +34,10 @@ void incr2b (unsigned int *p, unsigned int *q) } void call_both (unsigned int *p, unsigned int *q) -/*@ requires take pv = Owned(p); - take qv = Owned(q); - ensures take pv_ = Owned(p); - take qv_ = Owned(q); +/*@ requires take pv = RW(p); + take qv = RW(q); + ensures take pv_ = RW(p); + take qv_ = RW(q); pv_ == pv + 3u32; qv_ == qv + 1u32; @*/ diff --git a/src/exercises/slf_incr2_noalias.c b/src/exercises/slf_incr2_noalias.c index 7c7e2369..91dedd2d 100644 --- a/src/exercises/slf_incr2_noalias.c +++ b/src/exercises/slf_incr2_noalias.c @@ -1,8 +1,8 @@ void incr2a (unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); - take Q = Owned(q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == P + 1u32; Q_post == Q + 1u32; @*/ diff --git a/src/exercises/slf_length_acc.c b/src/exercises/slf_length_acc.c index d53f5c2c..d229f24e 100644 --- a/src/exercises/slf_length_acc.c +++ b/src/exercises/slf_length_acc.c @@ -17,9 +17,9 @@ function [rec] (u32) length(datatype List xs) { void IntList_length_acc_aux (struct sllist *xs, unsigned int *p) /*@ requires take L1 = SLList_At(xs); - take P = Owned(p); + take P = RW(p); ensures take L1_post = SLList_At(xs); - take P_post = Owned(p); + take P_post = RW(p); L1 == L1_post; P_post == P + length(L1); @*/ diff --git a/src/exercises/slf_quadruple_mem.c b/src/exercises/slf_quadruple_mem.c index c7a86dc3..dd7f8ea0 100644 --- a/src/exercises/slf_quadruple_mem.c +++ b/src/exercises/slf_quadruple_mem.c @@ -1,9 +1,9 @@ int quadruple_mem (int *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); +/*@ requires take P = RW(p); let P64 = (i64) P; (i64)MINi32() <= P64 * 4i64; P64 * 4i64 <= (i64)MAXi32(); - ensures take P_post = Owned(p); + ensures take P_post = RW(p); P_post == P; return == 4i32 * P; @*/ diff --git a/src/exercises/slf_ref_greater.c b/src/exercises/slf_ref_greater.c index 96138e91..ca2a16fe 100644 --- a/src/exercises/slf_ref_greater.c +++ b/src/exercises/slf_ref_greater.c @@ -2,10 +2,10 @@ unsigned int *ref_greater_abstract (unsigned int *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); +/*@ requires take P = RW(p); P < 4294967295u32; - ensures take P_post = Owned(p); - take R = Owned(return); + ensures take P_post = RW(p); + take R = RW(return); P == P_post; P <= R; @*/ diff --git a/src/exercises/slf_sized_stack.c b/src/exercises/slf_sized_stack.c index 669dc813..5dd71af7 100644 --- a/src/exercises/slf_sized_stack.c +++ b/src/exercises/slf_sized_stack.c @@ -11,7 +11,7 @@ struct sized_stack type_synonym SizedStack = {u32 Size, datatype List Data} predicate (SizedStack) SizedStack_At (pointer p) { - take P = Owned(p); + take P = RW(p); take D = SLList_At(P.data); assert(P.size == Length(D)); return { Size: P.size, Data: D }; @@ -22,13 +22,13 @@ extern struct sized_stack *malloc__sized_stack(); /*@ spec malloc__sized_stack(); requires true; - ensures take R = Block(return); + ensures take R = W(return); @*/ extern void *free__sized_stack(struct sized_stack *s); /*@ spec free__sized_stack(pointer s); - requires take R = Block(s); + requires take R = W(s); ensures true; @*/ diff --git a/src/exercises/swap.c b/src/exercises/swap.c index 435ef1b0..8191331b 100644 --- a/src/exercises/swap.c +++ b/src/exercises/swap.c @@ -1,9 +1,9 @@ void swap (unsigned int *p, unsigned int *q) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - take Q = Owned(q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == Q && Q_post == P; @*/ /* --END-- */ diff --git a/src/exercises/swap_array.c b/src/exercises/swap_array.c index 8cb18d67..41d5fa6c 100644 --- a/src/exercises/swap_array.c +++ b/src/exercises/swap_array.c @@ -1,20 +1,20 @@ void swap_array (int *p, int n, int i, int j) /* --BEGIN-- */ -/*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; +/*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; 0i32 <= i && i < n; 0i32 <= j && j < n; j != i; - ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + ensures take a2 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; a2 == a1[i: a1[j], j: a1[i]]; @*/ /* --END-- */ { /* --BEGIN-- */ - /*@ extract Owned, i; @*/ + /*@ focus RW, i; @*/ /* --END-- */ int tmp = p[i]; /* --BEGIN-- */ - /*@ extract Owned, j; @*/ + /*@ focus RW, j; @*/ /* --END-- */ p[i] = p[j]; p[j] = tmp; diff --git a/src/exercises/transpose.broken.c b/src/exercises/transpose.broken.c index 8e4c9075..0d05c162 100644 --- a/src/exercises/transpose.broken.c +++ b/src/exercises/transpose.broken.c @@ -1,8 +1,8 @@ struct point { unsigned int x; unsigned int y; }; void transpose (struct point *p) -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = RW(p); + ensures take P_post = RW(p); P_post.x == P.y; P_post.y == P.x; @*/ diff --git a/src/exercises/transpose.c b/src/exercises/transpose.c index 29581e34..b5fce8f6 100644 --- a/src/exercises/transpose.c +++ b/src/exercises/transpose.c @@ -1,8 +1,8 @@ struct point { unsigned int x; unsigned int y; }; void transpose (struct point *p) -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = RW(p); + ensures take P_post = RW(p); P_post.x == P.y; P_post.y == P.x; @*/ diff --git a/src/exercises/transpose2.c b/src/exercises/transpose2.c index 535e25ce..35eb9d7c 100644 --- a/src/exercises/transpose2.c +++ b/src/exercises/transpose2.c @@ -1,8 +1,8 @@ void swap (unsigned int *p, unsigned int *q) -/*@ requires take P = Owned(p); - take Q = Owned(q); - ensures take P_post = Owned(p); - take Q_post = Owned(q); +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); P_post == Q && Q_post == P; @*/ { @@ -16,8 +16,8 @@ struct point { unsigned int x; unsigned int y; }; void transpose2 (struct point *p) /* --BEGIN-- */ -/*@ requires take P = Owned(p); - ensures take P_post = Owned(p); +/*@ requires take P = RW(p); + ensures take P_post = RW(p); P_post.x == P.y; P_post.y == P.x; @*/ diff --git a/src/exercises/zero.c b/src/exercises/zero.c index 3c767e1c..bcb45ce6 100644 --- a/src/exercises/zero.c +++ b/src/exercises/zero.c @@ -1,7 +1,7 @@ void zero (unsigned int *p) /* --BEGIN-- */ -/*@ requires take P = Block(p); - ensures take P_post = Owned(p); +/*@ requires take P = W(p); + ensures take P_post = RW(p); P_post == 0u32; @*/ /* --END-- */ diff --git a/src/old/asciidoc_to_md.md b/src/old/asciidoc_to_md.md index ab3c2691..9b65383d 100644 --- a/src/old/asciidoc_to_md.md +++ b/src/old/asciidoc_to_md.md @@ -44,7 +44,7 @@ by hand. ``` 1. Convert indented list items ``` - * list item with the following indented code block + * list item with the following indented code W + [source,c] ---- diff --git a/src/old/asciidoctor.css b/src/old/asciidoctor.css index 843fe415..578ee416 100644 --- a/src/old/asciidoctor.css +++ b/src/old/asciidoctor.css @@ -22,7 +22,7 @@ sub{bottom:-.25em} img{border:0} svg:not(:root){overflow:hidden} figure{margin:0} -audio,video{display:inline-block} +audio,video{display:inline-W} audio:not([controls]){display:none;height:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0} @@ -49,7 +49,7 @@ img{-ms-interpolation-mode:bicubic} .text-center{text-align:center!important} .text-justify{text-align:justify!important} .hide{display:none} -img,object,svg{display:inline-block;vertical-align:middle} +img,object,svg{display:inline-W;vertical-align:middle} textarea{height:auto;min-height:50px} select{width:100%} .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} @@ -106,12 +106,12 @@ h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title str :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} -pre>code{display:block} +pre>code{display:W} pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} em em{font-style:normal} strong strong{font-weight:400} .keyseq{color:rgba(51,51,51,.8)} -kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} +kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-W;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} .keyseq kbd:first-child{margin-left:0} .keyseq kbd:last-child{margin-right:0} .menuseq,.menuref{color:#000} @@ -177,14 +177,14 @@ body.toc2.toc-right{padding-left:0;padding-right:20em}} .sect1{padding-bottom:1.25em}} .sect1:last-child{padding-bottom:0} .sect1+.sect1{border-top:1px solid #e7e7e9} -#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} -#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} +#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:W;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} +#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:W;padding-top:.1em} #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} details{margin-left:1.25rem} -details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent} +details>summary{cursor:pointer;display:W;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent} details>summary::-webkit-details-marker{display:none} details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)} details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)} @@ -210,7 +210,7 @@ table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} .listingblock>.content{position:relative} .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5} -.listingblock:hover code[data-lang]::before{display:block} +.listingblock:hover code[data-lang]::before{display:W} .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} .listingblock pre.highlightjs{padding:0} @@ -225,7 +225,7 @@ table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:n table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal} table.linenotable td.code{padding-left:.75em} table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} -pre.pygments span.linenos{display:inline-block;margin-right:.75em} +pre.pygments span.linenos{display:inline-W;margin-right:.75em} .quoteblock{margin:0 1em 1.25em 1.5em;display:table} .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em} .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} @@ -239,10 +239,10 @@ pre.pygments span.linenos{display:inline-block;margin-right:.75em} .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} .quoteblock .attribution br,.verseblock .attribution br{display:none} -.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} +.quoteblock .attribution cite,.verseblock .attribution cite{display:W;letter-spacing:-.025em;color:rgba(0,0,0,.6)} .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} -.quoteblock.abstract{margin:0 1em 1.25em;display:block} +.quoteblock.abstract{margin:0 1em 1.25em;display:W} .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf} .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0} @@ -282,7 +282,7 @@ li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin- ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} ul.unstyled,ol.unstyled{margin-left:0} -li>p:empty:only-child::before{content:"";display:inline-block} +li>p:empty:only-child::before{content:"";display:inline-W} ul.checklist>li>p:first-child{margin-left:-1em} ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em} @@ -305,16 +305,16 @@ td.hdlist2{word-wrap:anywhere} .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} .colist td:not([class]):first-child img{max-width:none} .colist td:not([class]):last-child{padding:.25em 0} -.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd} +.thumb,.th{line-height:0;display:inline-W;border:4px solid #fff;box-shadow:0 0 0 1px #ddd} .imageblock.left{margin:.25em .625em 1.25em 0} .imageblock.right{margin:.25em 0 1.25em .625em} .imageblock>.title{margin-bottom:0} .imageblock.thumb,.imageblock.th{border-width:6px} .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} -.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} +.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-W;line-height:0} .image.left{margin-right:.625em} .image.right{margin-left:.625em} -a.image{text-decoration:none;display:inline-block} +a.image{text-decoration:none;display:inline-W} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} @@ -371,7 +371,7 @@ a span.icon>.fa{cursor:inherit} .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} -.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} +.conum[data-value]{display:inline-W;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} .conum[data-value] *{color:#fff!important} .conum[data-value]+b{display:none} .conum[data-value]::after{content:attr(data-value)} @@ -391,7 +391,7 @@ p{margin-bottom:1.25rem} html{font-size:80%} a{color:inherit!important;text-decoration:underline!important} a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} -a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} +a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-W;font-size:.875em;padding-left:.25em} abbr[title]{border-bottom:1px dotted} abbr[title]::after{content:" (" attr(title) ")"} pre,blockquote,tr,img,object,svg{page-break-inside:avoid} @@ -404,16 +404,16 @@ h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} body.book #header{text-align:center} body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} -body.book #header .details{border:0!important;display:block;padding:0!important} +body.book #header .details{border:0!important;display:W;padding:0!important} body.book #header .details span:first-child{margin-left:0!important} -body.book #header .details br{display:block} +body.book #header .details br{display:W} body.book #header .details br+span::before{content:none!important} body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} -.listingblock code[data-lang]::before{display:block} +.listingblock code[data-lang]::before{display:W} #footer{padding:0 .9375em} .hide-on-print{display:none!important} -.print-only{display:block!important} +.print-only{display:W!important} .hide-for-print{display:none!important} .show-for-print{display:inherit!important}} @media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem} diff --git a/src/old/tutorial.md b/src/old/tutorial.md index 0fa1bb5f..d76230b9 100644 --- a/src/old/tutorial.md +++ b/src/old/tutorial.md @@ -186,7 +186,7 @@ statement, CN lists the typechecked sub-expressions, and the memory accesses and function calls within these. In our example, there is only one possible control-flow path: entering -the function body (section "`function body`") and executing the block +the function body (section "`function body`") and executing the W from lines 2 to 4, followed by the return statement at line 3. The entry for the latter contains the sequence of sub-expressions in the return statement, including reads of the variables `x` and `y`. @@ -219,7 +219,7 @@ whatever installed on your system.) _Proof context._ The second section, below the error trace, lists the proof context CN has reached along this control-flow path. -"`Available resources`" lists the owned resources, as discussed in later sections. +"`Available resources`" lists the RW resources, as discussed in later sections. "`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. @@ -325,31 +325,31 @@ cn verify exercises/read.c exercises/read.c:3:10: error: Missing resource for reading return \*p; ^~ -Resource needed: Owned(p) +Resource needed: RW(p) Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_403624.html ``` -For the read `*p` to be safe, ownership of a resource is missing: a resource `Owned(p)`. +For the read `*p` to be safe, ownership of a resource is missing: a resource `RW(p)`. -### Owned resources +### RW resources - + -Given a C-type `T` and pointer `p`, the resource `Owned(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). +Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). -In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `Owned(p)`, as shown below. For now ignore the notation `take ... = Owned(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `Owned(p)` resource. +In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `RW(p)`, as shown below. For now ignore the notation `take ... = RW(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `RW(p)` resource. ```c title="solutions/read.c" --8<-- @@ -359,9 +359,9 @@ solutions/read.c This specification means that: -- any function calling `read` has to be able to provide a resource `Owned(p)` to pass into `read`, and +- any function calling `read` has to be able to provide a resource `RW(p)` to pass into `read`, and -- the caller will receive back a resource `Owned(p)` when `read` returns. +- the caller will receive back a resource `RW(p)` when `read` returns. ### Resource outputs @@ -369,12 +369,12 @@ A caller of `read` may also wish to know that `read` actually returns the correc -In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `Owned(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. +In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `RW(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. -CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = Owned(p)` does two things: (1) it assert ownership of resource `Owned(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. +CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = RW(p)` does two things: (1) it assert ownership of resource `RW(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. @@ -424,21 +424,21 @@ CN rejects this program with the following message: ``` cn verify exercises/read.broken.c [1/1]: read -build/exercises/read.broken.c:4:3: error: Left_Sublist-over unused resource 'Owned(p)(v1)' +build/exercises/read.broken.c:4:3: error: Left_Sublist-over unused resource 'RW(p)(v1)' return \*p; ^~~~~~~~~~ Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_17eb4a.html ``` CN has typechecked the function and verified (1) that it is safe to -execute under the precondition (given ownership `Owned(p)`) +execute under the precondition (given ownership `RW(p)`) and (2) that the function (vacuously) satisfies its postcondition. But following the check of the postcondition it finds that not all resources have been "`used up`". -Indeed, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the owned memory or otherwise dispose of it. In CN this is a type error. +Indeed, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the RW memory or otherwise dispose of it. In CN this is a type error. -CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "`forgotten`". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the owned area of memory (as we shall see later). +CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "`forgotten`". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the RW area of memory (as we shall see later). CN’s motivation for linear tracking of resources is its focus on low-level systems software in which memory is managed manually; in @@ -465,40 +465,40 @@ exercises/abs_mem.c --8<-- ``` -### Block resources +### W resources -Aside from the `Owned` resources seen so far, CN has another -built-in type of resource called `Block`. Given a C-type `T` and -pointer `p`, `Block(p)` asserts the same ownership as -`Owned(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `Owned`, `Block` memory is not assumed +Aside from the `RW` resources seen so far, CN has another +built-in type of resource called `W`. Given a C-type `T` and +pointer `p`, `W(p)` asserts the same ownership as +`RW(p)` — ownership of a memory cell at `p` the size of type +`T` — but, in contrast to `RW`, `W` memory is not assumed to be initialised. CN uses this distinction to prevent reads from uninitialised memory: - A read at C-type `T` and pointer `p` requires a resource - `Owned(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `Owned` resource unchanged. + `RW(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `RW` resource unchanged. - A write at C-type `T` and pointer `p` needs only a -`Block(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `Block` resource -(it destroys it) and returns a new resource `Owned(p)` with the +`W(p)` (so, unlike reads, writes to uninitialised memory +are fine). The write consumes ownership of the `W` resource +(it destroys it) and returns a new resource `RW(p)` with the value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. - + -Since `Owned` carries the same ownership as `Block`, just with the -additional information that the `Owned` memory is initalised, a -resource `Owned(p)` is "`at least as good`" as `Block(p)` — -an `Owned(p)` resource can be used whenever `Block(p)` is +Since `RW` carries the same ownership as `W`, just with the +additional information that the `RW` memory is initalised, a +resource `RW(p)` is "`at least as good`" as `W(p)` — +an `RW(p)` resource can be used whenever `W(p)` is needed. For instance CN’s type checking of a write to `p` requires a -`Block(p)`, but if an `Owned(p)` resource is what is +`W(p)`, but if an `RW(p)` resource is what is available, this can be used just the same. This allows an already-initialised memory cell to be over-written again. -Unlike `Owned`, whose output is the pointee value, `Block` has no meaningful output. +Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. ### Writing through pointers @@ -510,7 +510,7 @@ exercises/slf0_basic_incr.signed.c --8<-- ``` -In the precondition we assert ownership of resource `Owned(p)`, +In the precondition we assert ownership of resource `RW(p)`, binding its output/pointee value to `P`, and use `P` to specify that `p` must point to a sufficiently small value at the start of the function so as not to overflow when incremented. The postcondition @@ -518,7 +518,7 @@ asserts ownership of `p` with output `P_post`, as before, and uses this to express that the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. -If we incorrectly tweaked this specification and used `Block(p)` instead of `Owned(p)` in the precondition, as below, then CN would reject the program. +If we incorrectly tweaked this specification and used `W(p)` instead of `RW(p)` in the precondition, as below, then CN would reject the program. ```c title="exercises/slf0_basic_incr.signed.broken.c" --8<-- @@ -532,17 +532,17 @@ CN reports: build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading int n = \*p; ^~ -Resource needed: Owned(p) +Resource needed: RW(p) Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html ``` -The `Owned(p)` resource required for reading is missing, since, per the precondition, only `Block(p)` is available. Checking the linked HTML file confirms this. Here the section "`Available resources`" lists all resource ownership at the point of the failure: +The `RW(p)` resource required for reading is missing, since, per the precondition, only `W(p)` is available. Checking the linked HTML file confirms this. Here the section "`Available resources`" lists all resource ownership at the point of the failure: -- `Block(p)(u)`, i.e., ownership of uninitialised memory +- `W(p)(u)`, i.e., ownership of uninitialised memory at location `p`; the output is a `void`/`unit` value `u` (specified in the second pair of parentheses) -- `Owned(&ARG0)(p)`, the ownership of (initialised) +- `RW(&ARG0)(p)`, the ownership of (initialised) memory at location `&ARG0`, i.e., the memory location where the first function argument is stored; its output is the pointer `p` (not to be confused with the pointee of `p`); and finally @@ -572,15 +572,15 @@ exercises/slf3_basic_inplace_double.c --8<-- ``` -### Multiple owned pointers +### Multiple RW pointers When functions manipulate multiple pointers, we can assert their ownership just like before. However pointer ownership in CN is unique -- that is, simultaneously owning -`Owned` or `Block` resources for two pointers implies that these +`RW` or `W` resources for two pointers implies that these pointers are disjoint. -The following example shows the use of two `Owned` resources for +The following example shows the use of two `RW` resources for accessing two different pointers by a function `add`, which reads two `int` values in memory, at locations `p` and `q`, and returns their sum. @@ -609,7 +609,7 @@ In the following we will sometimes use unsigned integer types to focus on specif ### Exercises -_Swap._ Specify the function `swap`, which takes two owned `unsigned int` pointers and swaps their values. +_Swap._ Specify the function `swap`, which takes two RW `unsigned int` pointers and swaps their values. ```c title="exercises/swap.c" --8<-- @@ -648,24 +648,24 @@ the members of `P` and `P_post` individually. -### Compound Owned and Block resources +### Compound RW and W resources While one might like to think of a struct as a single (compound) object that is manipulated as a whole, C permits more flexible struct manipulation: given a struct pointer, programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. -CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `Owned` and `Block` are defined inductively on the structure of the C-type `T`. +CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `RW` and `W` are defined inductively on the structure of the C-type `T`. -For struct types `T`, the `Owned` resource is defined as the collection of `Owned` resources for its members (as well as `Block` resources for any padding bytes in-between them). The resource `Block`, similarly, is made up of `Block` resources for all members (and padding bytes). +For struct types `T`, the `RW` resource is defined as the collection of `RW` resources for its members (as well as `W` resources for any padding bytes in-between them). The resource `W`, similarly, is made up of `W` resources for all members (and padding bytes). To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. -Recall the function `zero` from our earlier exercise. It takes an `int` pointer to uninitialised memory, with `Block` ownership, and initialises the value to zero, returning an `Owned` resource with output `0`. +Recall the function `zero` from our earlier exercise. It takes an `int` pointer to uninitialised memory, with `W` ownership, and initialises the value to zero, returning an `RW` resource with output `0`. Now consider the function `init_point`, shown below, which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. @@ -675,9 +675,9 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `Block(p)`. The `zero` function, however, works on `int` pointers and requires `Block` ownership. +As stated in its precondition, `init_point` receives ownership `W(p)`. The `zero` function, however, works on `int` pointers and requires `W` ownership. -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `Block(p)` into a `Block` for member `x` and a `Block` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `Owned` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `Owned(p)`, CN combines these back into a compound resource. The resulting `Owned` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. +CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `W(p)` into a `W` for member `x` and a `W` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `RW` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `RW(p)`, CN combines these back into a compound resource. The resulting `RW` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. ### Resource inference @@ -693,17 +693,17 @@ exercises/transpose.broken.c --8<-- ``` -The precondition of `transpose` asserts ownership of an `Owned(p)` resource. The error report now instead lists under "`Available resources`" two resources: +The precondition of `transpose` asserts ownership of an `RW(p)` resource. The error report now instead lists under "`Available resources`" two resources: -- `Owned(member_shift(p, x))` with output `P.x` and +- `RW(member_shift(p, x))` with output `P.x` and -- `Owned(member_shift(p, y))` with output `P.y` +- `RW(member_shift(p, y))` with output `P.y` Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. -When the function returns, the two member resources are recombined "`on demand`" to satisfy the postcondition `Owned(p)`. +When the function returns, the two member resources are recombined "`on demand`" to satisfy the postcondition `RW(p)`. ### Exercises @@ -737,7 +737,7 @@ To support reasoning about code manipulating arrays and computed pointers, CN ha ```c each (i32 i; 0i32 <= i && i < 10i32) -{ Owned(array_shift(p,i)) } +{ RW(array_shift(p,i)) } ``` In detail, this can be read as follows: @@ -746,7 +746,7 @@ In detail, this can be read as follows: - if `i` is between `0` and `10`, … -- assert ownership of a resource `Owned` … +- assert ownership of a resource `RW` … - for cell `i` of the array with base-address `p`. @@ -778,8 +778,8 @@ exercises/array_load.broken.c The CN precondition requires -- ownership of the array on entry — one `Owned` resource for each array index between `0` and `n` — and -- that `i` lies within the range of owned indices. +- ownership of the array on entry — one `RW` resource for each array index between `0` and `n` — and +- that `i` lies within the range of RW indices. On exit the array ownership is returned again. @@ -791,12 +791,12 @@ cn verify solutions/array_load.broken.c build/solutions/array_load.broken.c:5:10: error: Missing resource for reading return p[i]; ^~~~ -Resource needed: Owned(array_shift(p, (u64)i)) +Resource needed: RW(array_shift(p, (u64)i)) ``` -The reason is that, when searching for a required resource, such as the `Owned` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. +The reason is that, when searching for a required resource, such as the `RW` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. -To make the `Owned` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`extract`" ownership for index `i` out of the iterated resource. +To make the `RW` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`focus`" ownership for index `i` out of the iterated resource. ```c title="exercises/array_load.c" --8<-- @@ -804,10 +804,10 @@ exercises/array_load.c --8<-- ``` -Here the CN comment `/*@ extract Owned, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `Owned` resource for index `i`. In our example this operation splits the iterated resource into two: +Here the CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits the iterated resource into two: ```c -each(i32 j; 0i32 <= j && j < n) { Owned(array_shift(p,j)) } +each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) } ``` is split into @@ -815,19 +815,19 @@ is split into 1. the instantiation of the iterated resource at `i` ```c -Owned(array_shift(p,i)) +RW(array_shift(p,i)) ``` 2. the remainder of the iterated resource, the ownership for all indices except `i` ```c each(i32 j; 0i32 <= j && j < n && j != i) - { Owned(array_shift(p,j)) } + { RW(array_shift(p,j)) } ``` -After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `extract` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. +After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `focus` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. -Following an `extract` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. +Following an `focus` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. So far the specification only guarantees safe execution but does not specify the behaviour of `read`. To address this, let’s return to @@ -835,9 +835,9 @@ the iterated resources in the function specification. When we specify `take A = each ...` here, what is `A`? In CN, the output of an iterated resource is a _map_ from indices to resource outputs. In this example, where index `j` has CN type `i32` and the iterated -resource is `Owned`, the output `A` is a map from `i32` +resource is `RW`, the output `A` is a map from `i32` indices to `i32` values — CN type `map`. If the type of -`j` was `i64` and the resource `Owned`, `A` would have +`j` was `i64` and the resource `RW`, `A` would have type `map`. We can use this to refine our specification with information about the functional behaviour of `read`. @@ -848,7 +848,7 @@ exercises/array_load2.c --8<-- ``` -We specify that `read` does not change the array — the outputs of `Owned`, +We specify that `read` does not change the array — the outputs of `RW`, `A` and `A_post`, taken before and after running the function, are the same — and that the value returned is `A[i]`. @@ -865,7 +865,7 @@ exercises/add_two_array.c ``` @@ -882,18 +882,18 @@ exercises/swap_array.c TODO: BCP: I wrote this, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfecdt understanding of how the numeric stuff works. void swap_array (int *p, int n, int i, int j) - /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; 0i32 <= i && i < n; 0i32 <= j && j < n; j != i; - take xi = Owned(array_shift(p,i)); - take xj = Owned(array_shift(p,j)) - ensures take a2 = each(i32 k; 0i32 <= k && k < n) { Owned(array_shift(p,k)) }; + take xi = RW(array_shift(p,i)); + take xj = RW(array_shift(p,j)) + ensures take a2 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; a1[i:xj][j:xi] == a2 @*/ { - extract Owned, i; - extract Owned, j; + focus RW, i; + focus RW, j; int tmp = p[i]; p[i] = p[j]; p[j] = tmp; @@ -905,7 +905,7 @@ TODO: BCP: I wrote this, which seemed natural but did not work -- I still don't The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. -In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all owned resources and the constraints required to verify each iteration of the loop. +In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all RW resources and the constraints required to verify each iteration of the loop. Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. @@ -917,7 +917,7 @@ exercises/init_array.c --8<-- ``` -If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `Owned` resource -- one `Owned` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. +If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `RW` resource -- one `RW` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). @@ -941,13 +941,13 @@ The second thing we need to do, however, is less straightforward. Recall that, a TODO: BCP: This seems like a good idea! --> -The final piece needed in the verification is an `extract` statement, as used in the previous examples: to separate the individual `Owned` resource for index `j` out of the iterated `Owned` resource and make it available to the resource inference, we specify `extract Owned, j;`. +The final piece needed in the verification is an `focus` statement, as used in the previous examples: to separate the individual `RW` resource for index `j` out of the iterated `RW` resource and make it available to the resource inference, we specify `focus RW, j;`. -With the `inv` and `extract` statements in place, CN accepts the function. +With the `inv` and `focus` statements in place, CN accepts the function. ### Second loop example -The specification of `init_array` is overly strong: it requires an iterated `Owned` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `Block` resource for the array should also be sufficient. The modified specification is then as follows. +The specification of `init_array` is overly strong: it requires an iterated `RW` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `W` resource for the array should also be sufficient. The modified specification is then as follows. ```c title="exercises/init_array2.c" --8<-- @@ -955,7 +955,7 @@ exercises/init_array2.c --8<-- ``` -This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `Block` to `Owned` "`state`", so that on function return the full array is initialised. (Recall that stores only require `Block` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) +This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `W` to `RW` "`state`", so that on function return the full array is initialised. (Recall that stores only require `W` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) To verify this modified example we again need a loop Invariant. But this time the loop invariant is more involved: since each iteration of @@ -963,7 +963,7 @@ the loop initialises one more array cell, the loop invariant has to do precise book-keeping of the initialisation status of the different sections of the array. -To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `Owned` resource, for all other array indices we have the (unchanged) `Block` ownership. +To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `RW` resource, for all other array indices we have the (unchanged) `W` ownership. ```c title="solutions/init_array2.c" --8<-- @@ -973,21 +973,21 @@ solutions/init_array2.c Let's go through this line-by-line: -- We assert ownership of an iterated `Owned` resource, one for each index `i` strictly smaller than loop variable `j`. +- We assert ownership of an iterated `RW` resource, one for each index `i` strictly smaller than loop variable `j`. -- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `Block` resource. +- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `W` resource. - As in the previous example, we assert `p` and `n` are unchanged. -- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `Owned` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. +- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `RW` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. -As before, we also have to instruct CN to `extract` ownership of individual array cells out of the iterated resources: +As before, we also have to instruct CN to `focus` ownership of individual array cells out of the iterated resources: -- to allow CN to extract the individual `Block` to be written, we use `extract Block, j;`; +- to allow CN to focus the individual `W` to be written, we use `focus W, j;`; -- the store returns a matching `Owned` resource for index `j`; +- the store returns a matching `RW` resource for index `j`; -- finally, we add `extract Owned, j;` to allow CN to "`attach`" this resource to the iterated `Owned` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `extract` only for the "`reverse`" direction. +- finally, we add `focus RW, j;` to allow CN to "`attach`" this resource to the iterated `RW` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `focus` only for the "`reverse`" direction. @@ -1053,7 +1053,7 @@ exercises/slf_incr2_alias.c This version does correctly state that the final values of `p` and `q` are,m respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. - + A better way is to define a _predicate_ that captures both the aliased @@ -1061,7 +1061,7 @@ and the non-aliased cases together and use it in the pre- and postconditions: - + ```c title="exercises/slf_incr2.c" @@ -1174,7 +1174,7 @@ Now it's time to look at some more interesting heap structures. To begin with, here is a C definition for linked list cells, together with allocation and deallocation functions: - + ```c title="exercises/list/c_types.h" --8<-- @@ -1192,7 +1192,7 @@ structures, as one would do in ML, Haskell, or Coq. We use the datatype `List` for CN-level lists. Intuitively, the `SLList_At` predicate walks over a singly-linked -pointer structure in the C heap and extracts an `Owned` version of +pointer structure in the C heap and extracts an `RW` version of the CN-level list that it represents. ```c title="exercises/list/cn_types.h" @@ -1975,7 +1975,7 @@ list before we return, and will claim we are missing a resource for returning. The `split_case` on `is_null(n->next->next)` is similar, but for unpacking the `Own_Forwards` predicate. Note that we have to go one more node forward to make sure that everything past `n->next` -is still owned at the end of the function. +is still RW at the end of the function. Now let's look at the `remove` operation. Traditionally, a `remove` operation for a list returns the integer that was removed. However we @@ -2267,5 +2267,5 @@ alternative: [](https://www.sphinx-doc.org/en/master/index.html) Misc notes: -- Nb: take V = Owned(p) === p |-t-> V +- Nb: take V = RW(p) === p |-t-> V --> diff --git a/src/underconstruction/bst/c_types.h b/src/underconstruction/bst/c_types.h index 196270b3..ad80fc35 100644 --- a/src/underconstruction/bst/c_types.h +++ b/src/underconstruction/bst/c_types.h @@ -10,12 +10,12 @@ struct node { extern struct node* malloc_node(); /*@ spec malloc_node(); requires true; - ensures take R = Block(return); + ensures take R = W(return); !ptr_eq(return, NULL); @*/ extern void freenode (struct node *t); /*@ spec freenode(pointer t); - requires take R = Block(t); + requires take R = W(t); ensures true; @*/ diff --git a/src/underconstruction/bst/cn_getters.h b/src/underconstruction/bst/cn_getters.h index d0a84d31..df7ee6b6 100644 --- a/src/underconstruction/bst/cn_getters.h +++ b/src/underconstruction/bst/cn_getters.h @@ -1,4 +1,4 @@ -// Defines basic CN functions to extract a member of the Tree datatype +// Defines basic CN functions to focus a member of the Tree datatype /*@ function (i32) Data_Of (datatype Tree sapling) diff --git a/src/underconstruction/bst/cn_types.h b/src/underconstruction/bst/cn_types.h index 024b73de..979f8566 100644 --- a/src/underconstruction/bst/cn_types.h +++ b/src/underconstruction/bst/cn_types.h @@ -15,7 +15,7 @@ predicate (datatype Tree) Tree_At (pointer t) } else { - take T = Owned(t); + take T = RW(t); take L = Tree_At(T.left); assert (L == Leaf{} || Data_Of(L) < T.data); take R = Tree_At(T.right); diff --git a/src/underconstruction/bst/getter.c b/src/underconstruction/bst/getter.c index a6a04a66..37f0901d 100644 --- a/src/underconstruction/bst/getter.c +++ b/src/underconstruction/bst/getter.c @@ -23,10 +23,10 @@ int get_Tree_Data (struct node *t) struct node* get_Tree_Left (struct node *t) /* FILL IN HERE */ /* --BEGIN-- */ -/*@ requires take v1 = Owned(t); - take v1_left = Owned(v1.left); - ensures take v2 = Owned(t); - take v2_left = Owned(v2.left); +/*@ requires take v1 = RW(t); + take v1_left = RW(v1.left); + ensures take v2 = RW(t); + take v2_left = RW(v2.left); v1 == v2 && v1_left == v2_left; ptr_eq(return, ((is_null(t)) ? (t) : (v1.left))); @*/ /* --END-- */ @@ -44,10 +44,10 @@ struct node* get_Tree_Left (struct node *t) struct node* get_Tree_Right (struct node *t) /* FILL IN HERE */ /* --BEGIN-- */ -/*@ requires take v1 = Owned(t); - take v1_right = Owned(v1.right); - ensures take v2 = Owned(t); - take v2_right = Owned(v2.right); +/*@ requires take v1 = RW(t); + take v1_right = RW(v1.right); + ensures take v2 = RW(t); + take v2_right = RW(v2.right); v1 == v2 && v1_right == v2_right; ptr_eq(return, ((is_null(t)) ? (t) : (v1.right))); @*/ /* --END-- */ From 3dd4b268c941a1ebbe9dad4a97b7cc11fd83abe9 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 13:51:37 -0400 Subject: [PATCH 062/158] Finished first testing version of lists --- docs/getting-started/tutorials/lists.md | 18 +-- docs/getting-started/tutorials/verif-lists.md | 7 +- src/exercises/list/mergesort.brokentest.c | 124 ------------------ src/exercises/list/mergesort.verif.c | 42 +++--- 4 files changed, 28 insertions(+), 163 deletions(-) delete mode 100644 src/exercises/list/mergesort.brokentest.c diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index 12385479..03de625d 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -115,8 +115,9 @@ exercises/list/copy.c ### Merge sort - -BCP: This could use a gentler explanation (probably in pieces) + BCP: This could use a gentler explanation +(probably in pieces) We've heard from more than one reader that this +example is particularly hard to digest without some additional help Finally, here is a slightly tricky in-place version of merge sort that @@ -124,14 +125,6 @@ avoids allocating any new list cells in the splitting step by taking alternate cells from the original list and linking them together into two new lists of roughly equal lengths. - -BCP: We've heard from more than one reader that this example is particularly hard to digest without some additional help - - - -BCP: Nit: Merge multiple requires and ensures clauses into one - - ```c title="exercises/list/mergesort.test.c" --8<-- exercises/list/mergesort.test.c @@ -140,9 +133,8 @@ exercises/list/mergesort.test.c ### Exercises -_Allocating append_. Fill in the CN annotations on -`IntList_append2`. (You will need some in the body as well as at -the top.) +_Allocating append_. Fill in an appropriate specification for +`IntList_append2`. ```c title="exercises/list/append2.c" --8<-- diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index 306aabfc..60db6581 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -127,7 +127,8 @@ exercises/list/copy.c ### Merge sort -BCP: This could use a gentler explanation (probably in pieces) +BCP: This could use a gentler explanation (probably in pieces). But +much of it will be in lists.md, not here. Finally, here is a slightly tricky in-place version of merge sort that @@ -135,10 +136,6 @@ avoids allocating any new list cells in the splitting step by taking alternate cells from the original list and linking them together into two new lists of roughly equal lengths. - -BCP: We've heard from more than one reader that this example is particularly hard to digest without some additional help - - BCP: Nit: Merge multiple requires and ensures clauses into one diff --git a/src/exercises/list/mergesort.brokentest.c b/src/exercises/list/mergesort.brokentest.c deleted file mode 100644 index b382c6f1..00000000 --- a/src/exercises/list/mergesort.brokentest.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "./headers.test.h" - -/*@ -function [rec] ({datatype List fst, datatype List snd}) - split (datatype List xs) -{ - match xs { - Nil {} => { - {fst: Nil{}, snd: Nil{}} - } - Cons {Head: h1, Tail: Nil{}} => { - {fst: Nil{}, snd: xs} - } - Cons {Head: h1, Tail: Cons {Head : h2, Tail : tl2 }} => { - let P = split(tl2); - {fst: Cons { Head: h1, Tail: P.fst}, - snd: Cons { Head: h2, Tail: P.snd}} - } - } -} - -function [rec] (datatype List) merge(datatype List xs, datatype List ys) { - match xs { - Nil {} => { ys } - Cons {Head: x, Tail: xs1} => { - match ys { - Nil {} => { xs } - Cons{ Head: y, Tail: ys1} => { - (x < y) ? - (Cons{ Head: x, Tail: merge(xs1, ys) }) - : (Cons{ Head: y, Tail: merge(xs, ys1) }) - } - } - } - } -} - -function [rec] (datatype List) Mergesort(datatype List xs) { - match xs { - Nil{} => { xs } - Cons{Head: x, Tail: Nil{}} => { xs } - Cons{Head: x, Tail: Cons{Head: y, Tail: zs}} => { - let P = split(xs); - let L1 = Mergesort(P.fst); - let L2 = Mergesort(P.snd); - merge(L1, L2) - } - } -} -@*/ - -struct sllist_pair { - struct sllist* fst; - struct sllist* snd; -}; - -struct sllist_pair split(struct sllist *xs) -/*@ requires take Xs = SLList_At(xs); - ensures take Ys = SLList_At(return.fst); - take Zs = SLList_At(return.snd); - {fst: Ys, snd: Zs} == split(Xs); @*/ -{ - if (xs == 0) { - struct sllist_pair r = {.fst = 0, .snd = 0}; - return r; - } else { - struct sllist *cdr = xs -> tail; - if (cdr == 0) { - struct sllist_pair r = {.fst = 0, .snd = xs}; - return r; - } else { - struct sllist_pair p = split(cdr->tail); - xs->tail = p.fst; - cdr->tail = p.snd; - struct sllist_pair r = {.fst = xs, .snd = cdr}; - return r; - } - } -} - -struct sllist* merge(struct sllist *xs, struct sllist *ys) -/*@ requires take Xs = SLList_At(xs); - take Ys = SLList_At(ys); - ensures take Zs = SLList_At(return); - Zs == merge(Xs, Ys); @*/ -{ - if (xs == 0) { - return ys; - } else { - if (ys == 0) { - return xs; - } else { - if (xs->head < ys->head) { - struct sllist *zs = merge(xs->tail, ys); - xs->tail = zs; - return xs; - } else { - struct sllist *zs = merge(xs, ys->tail); - ys->tail = zs; - return ys; - } - } - } -} - -struct sllist* mergesort(struct sllist *xs) -/*@ requires take Xs = SLList_At(xs); - ensures take Ys = SLList_At(return); - Ys == Mergesort(Xs); @*/ -{ - if (xs == 0) { - return xs; - } else { - struct sllist *tail = xs->tail; - if (tail == 0) { - return xs; - } else { - struct sllist_pair p = split(xs); - p.fst = mergesort(p.fst); - p.snd = mergesort(p.snd); - return merge(p.fst, p.snd); - } - } -} diff --git a/src/exercises/list/mergesort.verif.c b/src/exercises/list/mergesort.verif.c index 604ed454..d7df0d0c 100644 --- a/src/exercises/list/mergesort.verif.c +++ b/src/exercises/list/mergesort.verif.c @@ -1,8 +1,8 @@ #include "./headers.verif.h" /*@ -function [rec] ({datatype List fst, datatype List snd}) - split (datatype List xs) +function [rec] ({datatype List fst, datatype List snd}) + Split_list (datatype List xs) { match xs { Nil {} => { @@ -12,7 +12,7 @@ function [rec] ({datatype List fst, datatype List snd}) {fst: Nil{}, snd: xs} } Cons {Head: h1, Tail: Cons {Head : h2, Tail : tl2 }} => { - let P = split(tl2); + let P = Split_list(tl2); {fst: Cons { Head: h1, Tail: P.fst}, snd: Cons { Head: h2, Tail: P.snd}} } @@ -35,14 +35,14 @@ function [rec] (datatype List) merge(datatype List xs, datatype List ys) { } } -function [rec] (datatype List) mergesort(datatype List xs) { +function [rec] (datatype List) merge_sort(datatype List xs) { match xs { Nil{} => { xs } Cons{Head: x, Tail: Nil{}} => { xs } Cons{Head: x, Tail: Cons{Head: y, Tail: zs}} => { - let P = split(xs); - let L1 = mergesort(P.fst); - let L2 = mergesort(P.snd); + let P = Split_list(xs); + let L1 = merge_sort(P.fst); + let L2 = merge_sort(P.snd); merge(L1, L2) } } @@ -54,25 +54,25 @@ struct sllist_pair { struct sllist* snd; }; -struct sllist_pair split(struct sllist *xs) +struct sllist_pair split_list(struct sllist *xs) /*@ requires take Xs = SLList_At(xs); @*/ /*@ ensures take Ys = SLList_At(return.fst); @*/ /*@ ensures take Zs = SLList_At(return.snd); @*/ -/*@ ensures {fst: Ys, snd: Zs} == split(Xs); @*/ +/*@ ensures {fst: Ys, snd: Zs} == Split_list(Xs); @*/ { if (xs == 0) { - /*@ unfold split(Xs); @*/ + /*@ unfold Split_list(Xs); @*/ struct sllist_pair r = {.fst = 0, .snd = 0}; return r; } else { struct sllist *cdr = xs -> tail; if (cdr == 0) { - /*@ unfold split(Xs); @*/ + /*@ unfold Split_list(Xs); @*/ struct sllist_pair r = {.fst = 0, .snd = xs}; return r; } else { - /*@ unfold split(Xs); @*/ - struct sllist_pair p = split(cdr->tail); + /*@ unfold Split_list(Xs); @*/ + struct sllist_pair p = split_list(cdr->tail); xs->tail = p.fst; cdr->tail = p.snd; struct sllist_pair r = {.fst = xs, .snd = cdr}; @@ -110,24 +110,24 @@ struct sllist* merge(struct sllist *xs, struct sllist *ys) } } -struct sllist* mergesort(struct sllist *xs) +struct sllist* merge_sort(struct sllist *xs) /*@ requires take Xs = SLList_At(xs); @*/ /*@ ensures take Ys = SLList_At(return); @*/ -/*@ ensures Ys == mergesort(Xs); @*/ +/*@ ensures Ys == merge_sort(Xs); @*/ { if (xs == 0) { - /*@ unfold mergesort(Xs); @*/ + /*@ unfold merge_sort(Xs); @*/ return xs; } else { struct sllist *tail = xs->tail; if (tail == 0) { - /*@ unfold mergesort(Xs); @*/ + /*@ unfold merge_sort(Xs); @*/ return xs; } else { - /*@ unfold mergesort(Xs); @*/ - struct sllist_pair p = split(xs); - p.fst = mergesort(p.fst); - p.snd = mergesort(p.snd); + /*@ unfold merge_sort(Xs); @*/ + struct sllist_pair p = split_list(xs); + p.fst = merge_sort(p.fst); + p.snd = merge_sort(p.snd); return merge(p.fst, p.snd); } } From a4c37609b519de683f3584a71be04d16c839a71f Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 13:51:59 -0400 Subject: [PATCH 063/158] Add missing file --- src/exercises/list/mergesort.test.c | 124 ++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/exercises/list/mergesort.test.c diff --git a/src/exercises/list/mergesort.test.c b/src/exercises/list/mergesort.test.c new file mode 100644 index 00000000..6277711d --- /dev/null +++ b/src/exercises/list/mergesort.test.c @@ -0,0 +1,124 @@ +#include "./headers.test.h" + +/*@ +function [rec] ({datatype List fst, datatype List snd}) + Split_list (datatype List xs) +{ + match xs { + Nil {} => { + {fst: Nil{}, snd: Nil{}} + } + Cons {Head: h1, Tail: Nil{}} => { + {fst: Nil{}, snd: xs} + } + Cons {Head: h1, Tail: Cons {Head : h2, Tail : tl2 }} => { + let P = Split_list(tl2); + {fst: Cons { Head: h1, Tail: P.fst}, + snd: Cons { Head: h2, Tail: P.snd}} + } + } +} + +function [rec] (datatype List) Merge(datatype List xs, datatype List ys) { + match xs { + Nil {} => { ys } + Cons {Head: x, Tail: xs1} => { + match ys { + Nil {} => { xs } + Cons{ Head: y, Tail: ys1} => { + (x < y) ? + (Cons{ Head: x, Tail: Merge(xs1, ys) }) + : (Cons{ Head: y, Tail: Merge(xs, ys1) }) + } + } + } + } +} + +function [rec] (datatype List) Merge_sort(datatype List xs) { + match xs { + Nil{} => { xs } + Cons{Head: x, Tail: Nil{}} => { xs } + Cons{Head: x, Tail: Cons{Head: y, Tail: zs}} => { + let P = Split_list(xs); + let L1 = Merge_sort(P.fst); + let L2 = Merge_sort(P.snd); + Merge(L1, L2) + } + } +} +@*/ + +struct sllist_pair { + struct sllist* fst; + struct sllist* snd; +}; + +struct sllist_pair split_list(struct sllist *xs) +/*@ requires take Xs = SLList_At(xs); + ensures take Ys = SLList_At(return.fst); + take Zs = SLList_At(return.snd); + {fst: Ys, snd: Zs} == Split_list(Xs); @*/ +{ + if (xs == 0) { + struct sllist_pair r = {.fst = 0, .snd = 0}; + return r; + } else { + struct sllist *cdr = xs -> tail; + if (cdr == 0) { + struct sllist_pair r = {.fst = 0, .snd = xs}; + return r; + } else { + struct sllist_pair p = split_list(cdr->tail); + xs->tail = p.fst; + cdr->tail = p.snd; + struct sllist_pair r = {.fst = xs, .snd = cdr}; + return r; + } + } +} + +struct sllist* merge(struct sllist *xs, struct sllist *ys) +/*@ requires take Xs = SLList_At(xs); + take Ys = SLList_At(ys); + ensures take Zs = SLList_At(return); + Zs == Merge(Xs, Ys); @*/ +{ + if (xs == 0) { + return ys; + } else { + if (ys == 0) { + return xs; + } else { + if (xs->head < ys->head) { + struct sllist *zs = merge(xs->tail, ys); + xs->tail = zs; + return xs; + } else { + struct sllist *zs = merge(xs, ys->tail); + ys->tail = zs; + return ys; + } + } + } +} + +struct sllist* merge_sort(struct sllist *xs) +/*@ requires take Xs = SLList_At(xs); + ensures take Ys = SLList_At(return); + Ys == Merge_sort(Xs); @*/ +{ + if (xs == 0) { + return xs; + } else { + struct sllist *tail = xs->tail; + if (tail == 0) { + return xs; + } else { + struct sllist_pair p = split_list(xs); + p.fst = merge_sort(p.fst); + p.snd = merge_sort(p.snd); + return merge(p.fst, p.snd); + } + } +} From dd7e8fc6fa7935f6ac1f80e1d67124a46a52f9b9 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 15:04:13 -0400 Subject: [PATCH 064/158] Testing version of the imperative queue case study --- .../case-studies/imperative-queues.md | 163 ++---------------- src/exercises/queue/allocation.test.h | 25 +++ .../queue/{cn_types_2.h => cn_types_2.test.h} | 0 src/exercises/queue/cn_types_2.verif.h | 13 ++ .../queue/{empty.c => empty.verif.c} | 0 src/exercises/queue/headers.test.h | 8 +- src/exercises/queue/headers.verif.h | 2 +- src/exercises/queue/pop.test.c | 26 +++ src/exercises/queue/{pop.c => pop.verif.c} | 0 src/exercises/queue/push.test.c | 24 +++ 10 files changed, 105 insertions(+), 156 deletions(-) create mode 100644 src/exercises/queue/allocation.test.h rename src/exercises/queue/{cn_types_2.h => cn_types_2.test.h} (100%) create mode 100644 src/exercises/queue/cn_types_2.verif.h rename src/exercises/queue/{empty.c => empty.verif.c} (100%) create mode 100644 src/exercises/queue/pop.test.c rename src/exercises/queue/{pop.c => pop.verif.c} (100%) create mode 100644 src/exercises/queue/push.test.c diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index c023d7f1..0dc1b853 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -24,8 +24,6 @@ exercises/queue/cn_types_1.h --8<-- ``` -BCP: Explain the asserts if needed. - Given a pointer to a `queue` struct, this predicate grabs ownership of the struct, asserts that the `front` and `back` pointers must either both be NULL or both be non-NULL, and then hands off to an @@ -69,6 +67,10 @@ walking down the cells from the front and gathering all the rest of them into a sequence. We take the result from `QueueAux` and `snoc` on the very last element. +BCP: Explain the asserts. (Why) are they useful +for testing? If they are not useful, make a testing-only version +that omits them! Ditto the QueueAux predicate below. + Finally, the `QueueAux` predicate recurses down the list of cells and returns a list of their contents. @@ -97,9 +99,9 @@ Now we need a bit of boilerplate: just as with linked lists, we need to be able to allocate and deallocate queues and queue cells. There are no interesting novelties here. -```c title="exercises/queue/allocation.verif.h" +```c title="exercises/queue/allocation.test.h" --8<-- -exercises/queue/allocation.verif.h +exercises/queue/allocation.test.h --8<-- ``` @@ -121,9 +123,9 @@ first. Here's the unannotated C code -- make sure you understand it. -```c title="exercises/queue/push_orig.broken.c" +```c title="exercises/queue/push.test.c" --8<-- -exercises/queue/push_orig.broken.c +exercises/queue/push.test.c --8<-- ``` @@ -143,56 +145,12 @@ with. Now, here is the annotated version of the `push` operation. -```c title="exercises/queue/push.c" ---8<-- -exercises/queue/push.c ---8<-- -``` - -The case where the queue starts out empty (`q->back == 0`) is easy. -CN can work it out all by itself. - -The case where the starting queue is nonempty is more interesting. -The `push` operation messes with the end of the sequence of queue -elements, so we should expect that validating `push` is going to -require some reasoning about this sequence. Here, in fact, is the -lemma we need. - -BCP: Not sure I can explain what "pointer" means here, or why we don't need to declare more specific types for these arguments to the lemma. - - -```c title="exercises/queue/push_lemma.h" +```c title="solutions/queue/push.test.c" --8<-- -exercises/queue/push_lemma.h +solutions/queue/push.test.c --8<-- ``` -This says, in effect, that we have two choices for how to read out the -values in some chain of queue cells of length at least 2, starting -with the cell `front` and terminating when we get to the next cell -_following_ some given cell `p` -- call it `c`. We can either -gather up all the cells from `front` to `c`, or we can gather up -just the cells from `front` to `p` and then `snoc` on the single -value from `c`. - -When we apply this lemma, `p` will be the old `back` cell and -`c` will be the new one. But to prove it (by induction, of course), -we need to state it more generally, allowing `p` to be any internal -cell in the list starting at `front` and `c` its successor. - -The reason we need this lemma is that, to add a new cell at the end of -the queue, we need to reassign ownership of the old `back` cell. -In the precondition of `push`, we took ownership of this cell -separately from the rest; in the postcondition, it needs to be treated -as part of the rest (so that the new `back` cell can now be treated -specially). - -One interesting technicality is worth noting: After the assignment -`q->back = c`, we can no longer prove `QueueFB(q->front, -oldback)`, but we don't care about this, since we want to prove -`QueueFB(q->front, q->back)`. However, crucially, -`QueueAux(q->front, oldback)` is still true. - Now let's look at the `pop` operation. Here is the un-annotated @@ -208,7 +166,7 @@ _Exercise_: Again, before reading on, see if you can write down a plausible top-level specification. (For extra credit, see how far you can get with verifying it!) -Here is the fully annotated `pop` code: +Here is the annotated `pop` code: ```c title="exercises/queue/pop.c" --8<-- @@ -216,101 +174,4 @@ exercises/queue/pop.c --8<-- ``` -There are three annotations to explain. Let's consider them in order. - -First, the `split_case` on `is_null(q->front)` is needed to tell -CN which of the branches of the `if` at the beginning of the -`QueueFB` predicate it can "unpack". (`QueuePtr_At` can be -unpacked immediately because it is unconditional, but `QueueFB` -cannot.) - -BCP: the word "unpack" is mysterious here. - -The guard/condition for `QueueFB` is `is_null(front)`, which is -why we need to do a `split_case` on this value. On one branch of the -`split_case` we have a contradiction: the fact that `before == -Nil{}` (from `QueueFB`) conflicts with `before != Nil` -from the precondition, so that case is immediate. On the other -branch, CN now knows that the queue is non-empty, as required, and type -checking proceeds. - -When `h == q->back`, we are in the case where the queue contains -just a single element, so we just need to NULL out its `front` and -`back` fields and deallocate the dead cell. The `unfold` -annotation is needed because the `snoc` function is recursive, so CN -doesn't do the unfolding automatically. - -Finally, when the queue contains two or more elements, we need to -deallocate the front cell, return its `first` field, and redirect -the `front` field of the queue structure to point to the next cell. -To push the verification through, we need a simple lemma about the -`snoc` function: - -```c title="exercises/queue/pop_lemma.h" ---8<-- -exercises/queue/pop_lemma.h ---8<-- -``` - -The crucial part of this lemma is the last three lines, which express -a simple, general fact about `snoc`: -if we form a sequence by calling `snoc` to add a final element -`B.first` to a sequence with head element `x` and tail `Q`, then the -head of the resulting sequence is still `x`, and its tail is `snoc -(Q, B.first)`. - -The `requires` clause and the first three lines of the `ensures` -clause simply set things up so that we can name the various values we -are talking about. Since these values come from structures in the -heap, we need to take ownership of them. And since lemmas in CN are -effectively just trusted functions that can also take in ghost values, -we need to take ownership in both the `requires` and `ensures` -clauses. (Taking them just in the `requires` clause would imply -that they are consumed and deallocated when the lemma is applied -- -not what we want!) - -BCP: The thing about ghost values is mysterious. - - -(The only reason we can't currently prove this lemma in CN is that we -don't have `take`s in CN statements, because this is just a simple -unfolding.) - -BCP: Ugh. - -_Exercise_: -Investigate what happens when you make each of the following changes -to the queue definitions. What error does CN report? Where are the -telltale clues in the error report that suggest what the problem was? - -- Remove `assert (is_null(B.next));` from `InqQueueFB`. -- Remove `assert (is_null(B.next));` from `InqQueueAux`. -- Remove one or both of occurrences of `free_queue_cell(f)` in - `pop_queue`. -- Remove, in turn, each of the CN annotations in the bodies of - `pop_queue` and `push_queue`. - -_Exercise_: The conditional in the `pop` function tests whether or -not `f == b` to find out whether we have reached the last element of -the queue. Another way to get the same information would be to test -whether `f->next == 0`. Can you verify this version? -_Note_: I (BCP) have not worked out the details, so am not sure how hard -this is (or if it is even not possible, though I'd be surprised). -Please let me know if you get it working! - -_Exercise_: Looking at the code for the `pop` operation, -it might seem reasonable to move the identical assignments to `x` in both -branches to above the `if`. This doesn't "just work" because the -ownership reasoning is different. In the first case, ownership of -`h` comes from `QueueFB` (because `h == q->back`). In the -second case, it comes from `QueueAux` (because `h != -q->back`). - -Can you generalize the `snoc_facts` lemma to handle both cases? You -can get past the dereference with a `split_case` but formulating the -lemma before the `return` will be a bit more complicated. - - - -_Note_: Again, this has not been shown to be possible, but Dhruv -believes it should be! +BCP: Need some exercises. diff --git a/src/exercises/queue/allocation.test.h b/src/exercises/queue/allocation.test.h new file mode 100644 index 00000000..bec96430 --- /dev/null +++ b/src/exercises/queue/allocation.test.h @@ -0,0 +1,25 @@ +#include "../cn_malloc.h" + +struct queue *malloc__queue() +/*@ ensures take R = W(return); @*/ +{ + return cn_malloc(sizeof(struct queue)); +} + +void free__queue (struct queue *p) +/*@ requires take P = W(p); @*/ +{ + cn_free_sized(p, sizeof(struct queue)); +} + +struct queue_cell *malloc__queue_cell() +/*@ ensures take R = W(return); @*/ +{ + return cn_malloc(sizeof(struct queue_cell)); +} + +void free__queue_cell (struct queue_cell *p) +/*@ requires take P = W(p); @*/ +{ + cn_free_sized(p, sizeof(struct queue_cell)); +} diff --git a/src/exercises/queue/cn_types_2.h b/src/exercises/queue/cn_types_2.test.h similarity index 100% rename from src/exercises/queue/cn_types_2.h rename to src/exercises/queue/cn_types_2.test.h diff --git a/src/exercises/queue/cn_types_2.verif.h b/src/exercises/queue/cn_types_2.verif.h new file mode 100644 index 00000000..2291fdc5 --- /dev/null +++ b/src/exercises/queue/cn_types_2.verif.h @@ -0,0 +1,13 @@ +/*@ +predicate (datatype List) QueueFB (pointer front, pointer back) { + if (is_null(front)) { + return Nil{}; + } else { + take B = RW(back); + assert (is_null(B.next)); + assert (ptr_eq(front, back) || !addr_eq(front, back)); + take L = QueueAux (front, back); + return Snoc(L, B.first); + } +} +@*/ diff --git a/src/exercises/queue/empty.c b/src/exercises/queue/empty.verif.c similarity index 100% rename from src/exercises/queue/empty.c rename to src/exercises/queue/empty.verif.c diff --git a/src/exercises/queue/headers.test.h b/src/exercises/queue/headers.test.h index 00fca88f..7a9e27f1 100644 --- a/src/exercises/queue/headers.test.h +++ b/src/exercises/queue/headers.test.h @@ -1,11 +1,11 @@ -#include "../list/c_types.h" +#include "../list/c_types.test.h" #include "../list/cn_types.h" #include "../list/hdtl.h" #include "../list/snoc.h" #include "./c_types.h" #include "./cn_types_1.h" -#include "./cn_types_2.test.h" -#include "./cn_types_3.test.h" +#include "./cn_types_2.test.h" +#include "./cn_types_3.test.h" -#include "./allocation.verif.h" +#include "./allocation.test.h" diff --git a/src/exercises/queue/headers.verif.h b/src/exercises/queue/headers.verif.h index c6934c4e..18f4041e 100644 --- a/src/exercises/queue/headers.verif.h +++ b/src/exercises/queue/headers.verif.h @@ -5,7 +5,7 @@ #include "./c_types.h" #include "./cn_types_1.h" -#include "./cn_types_2.h" +#include "./cn_types_2.verif.h" #include "./cn_types_3.verif.h" #include "./allocation.verif.h" diff --git a/src/exercises/queue/pop.test.c b/src/exercises/queue/pop.test.c new file mode 100644 index 00000000..ea83f29f --- /dev/null +++ b/src/exercises/queue/pop.test.c @@ -0,0 +1,26 @@ +#include "./headers.test.h" + +int pop_queue (struct queue *q) +/* --BEGIN-- */ +/*@ requires take Q = QueuePtr_At(q); + Q != Nil{}; + ensures take Q_post = QueuePtr_At(q); + Q_post == Tl(Q); + return == Hd(Q); +@*/ +/* --END-- */ +{ + struct queue_cell* h = q->front; + if (h == q->back) { + int x = h->first; + free__queue_cell(h); + q->front = 0; + q->back = 0; + return x; + } else { + int x = h->first; + q->front = h->next; + free__queue_cell(h); + return x; + } +} diff --git a/src/exercises/queue/pop.c b/src/exercises/queue/pop.verif.c similarity index 100% rename from src/exercises/queue/pop.c rename to src/exercises/queue/pop.verif.c diff --git a/src/exercises/queue/push.test.c b/src/exercises/queue/push.test.c new file mode 100644 index 00000000..9e78f062 --- /dev/null +++ b/src/exercises/queue/push.test.c @@ -0,0 +1,24 @@ +#include "./headers.test.h" + +void push_queue (int x, struct queue *q) +/* --BEGIN-- */ +/*@ requires take Q = QueuePtr_At(q); + ensures take Q_post = QueuePtr_At(q); + Q_post == Snoc (Q, x); +@*/ +/* --END-- */ +{ + struct queue_cell *c = malloc_queue_cell(); + c->first = x; + c->next = 0; + if (q->back == 0) { + q->front = c; + q->back = c; + return; + } else { + struct queue_cell *oldback = q->back; + q->back->next = c; + q->back = c; + return; + } +} From 4ff03efca7e08762dfa1dc0d411a7295e7328f94 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 17:05:55 -0400 Subject: [PATCH 065/158] DLL and runway examples --- .../case-studies/doubly-linked-lists.md | 80 +++--- .../case-studies/imperative-queues.md | 11 +- .../case-studies/the-runway.md | 90 +------ .../case-studies/verif-doubly-linked-lists.md | 234 ++++++++++++++++++ .../case-studies/verif-imperative-queues.md | 2 + .../case-studies/verif-the-runway.md | 209 ++++++++++++++++ docs/getting-started/tutorials/README.md | 6 +- docs/getting-started/tutorials/todo.md | 71 ++++++ docs/getting-started/tutorials/welcome.md | 3 + src/exercises/dll/add.test.c | 42 ++++ src/exercises/dll/allocation.test.h | 13 + .../dll/{malloc_free.h => allocation.verif.h} | 0 src/exercises/dll/dllist_and_int.test.h | 16 ++ ...llist_and_int.h => dllist_and_int.verif.h} | 0 src/exercises/dll/headers.test.h | 8 + src/exercises/dll/headers.verif.h | 2 +- src/exercises/dll/remove.test.c | 42 ++++ .../dll/{remove.c => remove.verify.c} | 2 +- .../dll/{singleton.c => singleton.verif.c} | 0 src/exercises/list/c_types.test.h | 6 +- src/exercises/queue/push.test.c | 2 +- 21 files changed, 704 insertions(+), 135 deletions(-) create mode 100644 docs/getting-started/case-studies/verif-doubly-linked-lists.md create mode 100644 docs/getting-started/case-studies/verif-the-runway.md create mode 100644 src/exercises/dll/add.test.c create mode 100644 src/exercises/dll/allocation.test.h rename src/exercises/dll/{malloc_free.h => allocation.verif.h} (100%) create mode 100644 src/exercises/dll/dllist_and_int.test.h rename src/exercises/dll/{dllist_and_int.h => dllist_and_int.verif.h} (100%) create mode 100644 src/exercises/dll/headers.test.h create mode 100644 src/exercises/dll/remove.test.c rename src/exercises/dll/{remove.c => remove.verify.c} (97%) rename src/exercises/dll/{singleton.c => singleton.verif.c} (100%) diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index b57a683d..4ca18dac 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -3,7 +3,7 @@ BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. A doubly linked list is a linked list where each node has a pointer -to both the next node and the previous node. This allows for O(1) +to both the next node and the previous node. This allows for constant-time operations for adding or removing nodes anywhere in the list. Because of all the sharing in this data structure, the separation @@ -11,6 +11,10 @@ reasoning is a bit tricky. We'll give you the core definitions and then invite you to help fill in the annotations for some of the functions that manipulate doubly linked lists. +## Types + +BCP: Does that work for testing? + First, here is the C type definition: ```c title="exercises/dll/c_types.h" @@ -50,6 +54,9 @@ Note that `Dll_at` takes ownership of the node passed in, and then calls `Own_Backwards` and `Own_Forwards`, which recursively take ownership of the rest of the list. +BCP: Has ptr_eq been explained? It's useful +-- should be! + Also, notice that `Own_Forwards` and `Own_Backwards` include `ptr_eq` assertions for the `prev` and `next` pointers. This is to ensure that the nodes in the list are correctly doubly linked. For example, the @@ -70,59 +77,68 @@ exercises/dll/getters.h --8<-- ``` -We also need some boilerplate for allocation and deallocation. +We also need the usual boilerplate for allocation and deallocation. -```c title="exercises/dll/malloc_free.h" +```c title="exercises/dll/allocation.test.h" --8<-- -exercises/dll/malloc_free.h +exercises/dll/allocation.test.h --8<-- ``` For convenience, we gather all of these files into a single header file. -```c title="exercises/dll/headers.verif.h" +```c title="exercises/dll/headers.test.h" --8<-- -exercises/dll/headers.verif.h +exercises/dll/headers.test.h --8<-- ``` +## Singleton + Now we can move on to an initialization function. Since an empty list is represented as a null pointer, we will look at initializing a singleton list (or in other words, a list with only one item). -```c title="exercises/dll/singleton.c" +```c title="exercises/dll/singleton.test.c" --8<-- -exercises/dll/singleton.c +exercises/dll/singleton.test.c --8<-- ``` +## Add + The `add` and `remove` functions are where it gets a little tricker. Let's start with `add`. Here is the unannotated version: -```c title="exercises/dll/add_orig.broken.c" +```c title="exercises/dll/add.test.c" --8<-- -exercises/dll/add_orig.broken.c +exercises/dll/add.test.c --8<-- ``` _Exercise_: Before reading on, see if you can figure out what -specification is appropriate and what other are needed. +specification is appropriate. BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. Now, here is the annotated version of the `add` operation: -```c title="exercises/dll/add.c" +BCP: If we're not going to _discuss_ the +solution, there's no need to include it here in-line, since people +already know where to find the file. (But, of course, we should +discuss it!) + +```c title="solutions/dll/add.c" --8<-- -exercises/dll/add.c +solutions/dll/add.c --8<-- ``` -First, let's look at the pre- and post-conditions. The `requires` +The `requires` clause is straightforward. We need to own the list centered around the node that `n` points to. `Before` is a `Dll` that is either empty, or it has a List to the left, @@ -139,18 +155,9 @@ list. Otherwise, the left left part of the list now has the data from the old `curr` node, the new `curr` node is the added node, and the right part of the list is the same as before. -Now, let's look at the annotations in the function body. CN can -figure out the empty list case for itself, but it needs some help with -the non-empty list case. The `split_case` on `is_null(n->prev)` -tells CN to unpack the `Own_Backwards` predicate. Without this -annotation, CN cannot reason that we didn't lose the left half of the -list before we return, and will claim we are missing a resource for -returning. The `split_case` on `is_null(n->next->next)` is similar, -but for unpacking the `Own_Forwards` predicate. Note that we have to -go one more node forward to make sure that everything past `n->next` -is still RW at the end of the function. - -Now let's look at the `remove` operation. Traditionally, a `remove` +## Remove + +Finally, let's look at the `remove` operation. Traditionally, a `remove` operation for a list returns the integer that was removed. However we also want all of our functions to return a pointer to the list. Because of this, we define a `struct` that includes an `int` @@ -164,22 +171,22 @@ exercises/dll/dllist_and_int.h Now we can look at the code for the `remove` operation. Here is the un-annotated version: -```c title="exercises/dll/remove_orig.broken.c" +```c title="exercises/dll/remove.test.c" --8<-- -exercises/dll/remove_orig.broken.c +exercises/dll/remove.test.c --8<-- ``` _Exercise_: Before reading on, see if you can figure out what -specification is appropriate and what annotations are needed. +specification is appropriate. BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. -Now, here is the fully annotated version of the `remove` operation: +Now, here is the annotated version of the `remove` operation: -```c title="exercises/dll/remove.c" +```c title="solutions/dll/remove.test.c" --8<-- -exercises/dll/remove.c +solutions/dll/remove.test.c --8<-- ``` @@ -211,14 +218,7 @@ Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. the tail, as seen shown in `After == Dll{left: Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` -The annotations in the function body are similar to in the `add` -function. Both of these `split_case` annotations are needed to unpack -the `Own_Forwards` and `Own_Backwards` predicates. Without them, CN -will not be able to reason that we didn't lose the left or right half -of the list before we return and will claim we are missing a resource -for returning. - - +## Exercises _Exercise_: There are many other functions that one might want to implement for a doubly linked list. For example, one might want to diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 0dc1b853..e0e2c4a7 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -1,8 +1,8 @@ # Imperative Queues -A queue is a linked list with O(1) operations for adding things to one -end (the "back") and removing them from the other (the "front"). Here -are the C type definitions: +A queue is a linked list with constant-time operations for adding +things to one end (the "back") and removing them from the other (the +"front"). Here are the C type definitions: ```c title="exercises/queue/c_types.h" --8<-- @@ -163,8 +163,7 @@ exercises/queue/pop_orig.broken.c ``` _Exercise_: Again, before reading on, see if you can write down a -plausible top-level specification. (For extra credit, see how far you -can get with verifying it!) +plausible top-level specification and test its correctness. Here is the annotated `pop` code: @@ -174,4 +173,4 @@ exercises/queue/pop.c --8<-- ``` -BCP: Need some exercises. +BCP: Needs some more exercises? diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 5fe1e8a1..19b54299 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -1,6 +1,11 @@ # Airport Simulation -BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... +BCP: I'm nervous about this case study -- it +is not nearly as well debugged as the others, and it seems potentially +quite confusing. I propose deleting it, but if others like it we can +try to whip it into better shape... (Later: It seems people do like +it, because it is more like SUT code than the other examples. So we +should make it better.) Suppose we have been tasked with writing a program that simulates a runway at an airport. This airport is very small, so it only has one @@ -71,6 +76,9 @@ following fields: or departed while planes are waiting for the other mode. This will help us keep track of the 3-plane limit as described in _(6)_. +BCP: Do we need these functions for the +testing version? Has function been explained earlier? + ```c title="exercises/runway/state.h" --8<-- exercises/runway/state.h @@ -127,83 +135,3 @@ exercises/runway/funcs2.c --8<-- ``` - - -## Acknowledgment of Support and Disclaimer - -This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). - - - - diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md new file mode 100644 index 00000000..729563ef --- /dev/null +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -0,0 +1,234 @@ +# Doubly-linked Lists + +Need updating after testing/verif split. + +BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. + +A doubly linked list is a linked list where each node has a pointer +to both the next node and the previous node. This allows for O(1) +operations for adding or removing nodes anywhere in the list. + +Because of all the sharing in this data structure, the separation +reasoning is a bit tricky. We'll give you the core definitions and +then invite you to help fill in the annotations for some of the +functions that manipulate doubly linked lists. + +First, here is the C type definition: + +```c title="exercises/dll/c_types.h" +--8<-- +exercises/dll/c_types.h +--8<-- +``` + +The idea behind the representation of this list is that we don't keep +track of the front or back, but rather we take any node in the list +and have a sequence to the left and to the right of that node. The `left` +and `right` are from the point of view of the node itself, so `left` +is kept in reverse order. Additionally, similarly to in the +`Imperative Queues` example, we can reuse the `List` type. + +```c title="exercises/dll/cn_types.h" +--8<-- +exercises/dll/cn_types.h +--8<-- +``` + +The predicate for this datatype is a bit complicated. The idea is that +we first own the node that is passed in. Then we follow all of the +`prev` pointers to own everything backwards from the node, and finally +all the `next` pointers to own everything forwards from the node, to +construct the `left` and `right` fields. + +BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? + +```c title="exercises/dll/predicates.h" +--8<-- +exercises/dll/predicates.h +--8<-- +``` + +Note that `Dll_at` takes ownership of the node passed in, and then +calls `Own_Backwards` and `Own_Forwards`, which recursively take +ownership of the rest of the list. + +Also, notice that `Own_Forwards` and `Own_Backwards` include `ptr_eq` +assertions for the `prev` and `next` pointers. This is to ensure that +the nodes in the list are correctly doubly linked. For example, the +line `assert (ptr_eq(n.prev, prev_pointer));` in `Own_Forwards` +ensures that the current node correctly points backward to the +previous node in the list. The line `assert(ptr_eq(prev_node.next, +p));` ensures that the previous node correctly points forward to the +current node. + +Before we move on to the functions that manipulate doubly linked +lists, we need to define a few "getter" functions that will allow us +to access the fields of our `Dll` datatype. This will make the +specifications easier to write. + +```c title="exercises/dll/getters.h" +--8<-- +exercises/dll/getters.h +--8<-- +``` + +We also need some boilerplate for allocation and deallocation. + +```c title="exercises/dll/malloc_free.h" +--8<-- +exercises/dll/malloc_free.h +--8<-- +``` + +For convenience, we gather all of these files into a single header file. + +```c title="exercises/dll/headers.verif.h" +--8<-- +exercises/dll/headers.verif.h +--8<-- +``` + + + +Now we can move on to an initialization function. Since an empty list +is represented as a null pointer, we will look at initializing a +singleton list (or in other words, a list with only one item). + +```c title="exercises/dll/singleton.c" +--8<-- +exercises/dll/singleton.c +--8<-- +``` + + + +The `add` and `remove` functions are where it gets a little tricker. +Let's start with `add`. Here is the unannotated version: + +```c title="exercises/dll/add_orig.broken.c" +--8<-- +exercises/dll/add_orig.broken.c +--8<-- +``` + +_Exercise_: Before reading on, see if you can figure out what +specification is appropriate and what other are needed. + +BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. + +Now, here is the annotated version of the `add` operation: + +```c title="exercises/dll/add.c" +--8<-- +exercises/dll/add.c +--8<-- +``` + +First, let's look at the pre- and post-conditions. The `requires` +clause is straightforward. We need to own the list centered around +the node that `n` points to. `Before` is a `Dll` +that is either empty, or it has a List to the left, +the current node that `n` points to, and a List to the right. +This corresponds to the state of the list when it is passed in. + +In the ensures clause, we again establish ownership of the list, but +this time it is centered around the added node. This means that +`After` is a `Dll` structure similar to `Before`, except that the node +`curr` is now the created node. The old `curr` is pushed into the left +part of the new list. The conditional operator in the `ensures` clause +is saying that if the list was empty coming in, it now is a singleton +list. Otherwise, the left left part of the list now has the data from +the old `curr` node, the new `curr` node is the added node, and the +right part of the list is the same as before. + +Now, let's look at the annotations in the function body. CN can +figure out the empty list case for itself, but it needs some help with +the non-empty list case. The `split_case` on `is_null(n->prev)` +tells CN to unpack the `Own_Backwards` predicate. Without this +annotation, CN cannot reason that we didn't lose the left half of the +list before we return, and will claim we are missing a resource for +returning. The `split_case` on `is_null(n->next->next)` is similar, +but for unpacking the `Own_Forwards` predicate. Note that we have to +go one more node forward to make sure that everything past `n->next` +is still RW at the end of the function. + +Now let's look at the `remove` operation. Traditionally, a `remove` +operation for a list returns the integer that was removed. However we +also want all of our functions to return a pointer to the +list. Because of this, we define a `struct` that includes an `int` +and a `node`. + +```c title="exercises/dll/dllist_and_int.h" +--8<-- +exercises/dll/dllist_and_int.h +--8<-- +``` + +Now we can look at the code for the `remove` operation. Here is the un-annotated version: + +```c title="exercises/dll/remove_orig.broken.c" +--8<-- +exercises/dll/remove_orig.broken.c +--8<-- +``` + +_Exercise_: Before reading on, see if you can figure out what +specification is appropriate and what annotations are needed. + +BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. + +Now, here is the fully annotated version of the `remove` operation: + +```c title="exercises/dll/remove.c" +--8<-- +exercises/dll/remove.c +--8<-- +``` + +First, let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we +assign the node of that list to the identifier `del` +to make our spec more readable. So `Before` refers to the `Dll` when the function is called, and `del` refers to the node that will be deleted. + +Then in the `ensures` clause, we must take ownership +of the `node_and_int` struct as well as the `Dll` that +the node is part of. Here, `After` refers to the `Dll` +when the function returns. We ensure that the int that is returned is the value of the deleted node, as intended. Then we have a complicated nested ternary conditional that ensures that `After` is the same as `Before` except for the deleted node. Let's break down this conditional: + +- The first guard asks if both `del.prev` and `del.next` are null. In this case, we are removing the only node in the list, so the resulting list will be empty. The `else` branch of this conditional contains its own conditional. + +- For the following conditional, the guard checks if 'del.prev' is + _not_ null. This means that the returned node is `del.next`, + regardless of whether or not `del.prev` is null. If this is the + case, `After` is now centered around `del.next`, and the left part + of the list is the same as before. Since `del.next` was previously + the head of the right side, the right side loses its head in + `After`. This is where we get `After == Dll{left: +Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. + +- The final `else` branch is the case where `del.next` is null, but + `del.prev` is not null. In this case, the returned node is + `del.prev`. This branch follows the same logic as the one before it, + except now we are taking the head of the left side rather than the + right side. Now the right side is unchanged, and the left side is just + the tail, as seen shown in `After == Dll{left: +Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` + +The annotations in the function body are similar to in the `add` +function. Both of these `split_case` annotations are needed to unpack +the `Own_Forwards` and `Own_Backwards` predicates. Without them, CN +will not be able to reason that we didn't lose the left or right half +of the list before we return and will claim we are missing a resource +for returning. + + + +_Exercise_: There are many other functions that one might want to +implement for a doubly linked list. For example, one might want to +implement a function that appends one list to another, or a function +that reverses a list. Try implementing a few of these functions and +writing their specifications. + +_Exercise_: For extra practice, try coming up with one or two +variations on the Dll data structure itself (there are many!). + + diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md index 1f7b62f9..0586047a 100644 --- a/docs/getting-started/case-studies/verif-imperative-queues.md +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -1,5 +1,7 @@ # Verifying Imperative Queues +Need updating after testing/verif split. + A queue is a linked list with O(1) operations for adding things to one end (the "back") and removing them from the other (the "front"). Here are the C type definitions: diff --git a/docs/getting-started/case-studies/verif-the-runway.md b/docs/getting-started/case-studies/verif-the-runway.md new file mode 100644 index 00000000..5fe1e8a1 --- /dev/null +++ b/docs/getting-started/case-studies/verif-the-runway.md @@ -0,0 +1,209 @@ +# Airport Simulation + +BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... + +Suppose we have been tasked with writing a program that simulates a +runway at an airport. This airport is very small, so it only has one +runway, which is used for both takeoffs and landings. We want to +verify that the runway is always used safely, by checking the +following informal specification: + +1. The runway has two modes: departure mode and arrival mode. The two +modes can never be active at the same time. Neither mode is active +at the beginning of the day. +BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) + +2. At any given moment, there is a waiting list of planes that need to + land at the airport and planes that need to leave the + airport. These are modeled with counters `W_A` for the number of + planes waiting to arrive, and `W_D` for the number of planes + waiting to depart. + +3. At any moment, a plane is either waiting to arrive, waiting to + depart, or on the runway. Once a plane has started arriving or + departing, the corresponding counter (`W_A` or `W_D`) is + decremented. There is no need to keep track of planes once they + have arrived or departed. Additionally, once a plane is waiting to + arrive or depart, it continues waiting until it has arrived or + departed. + +4. It takes 5 minutes for a plane to arrive or depart. During these 5 + minutes, no other plane may use the runway. We can keep track of + how long a plane has been on the runway with the + `Runway_Counter`. If the `Runway_Counter` is at 0, then there is + currently no plane using the runway, and it is clear for another + plane to begin arriving or departing. Once the `Runway_Counter` + reaches 5, we can reset it at the next clock tick. One clock tick + represents 1 minute. + +5. If there is at least one plane waiting to depart and no cars + waiting to arrive, then the runway is set to departure mode (and + vice versa for arrivals). + +6. If both modes of the runway are inactive and planes become ready to + depart and arrive simultaneously, the runway will activate arrival + mode first. If the runway is in arrival mode and there are planes + waiting to depart, no more than 3 planes may arrive from that time + point. When either no more planes are waiting to arrive or 3 planes + have arrived, the runway switches to departure mode. If the runway + is on arrival mode and no planes are waiting to depart, then the + runway may stay in arrival mode until a plane is ready to depart, + from which time the 3-plane limit is imposed (and vice versa for + departures). Put simply, if any planes are waiting for a mode that + is inactive, that mode will become active no more than 15 minutes + later (5 minutes for each of 3 planes). + +To encode all this in CN, we first need a way to describe the state of +the runway at a given time. We can use a _struct_ that includes the +following fields: + +- `ModeA` and `ModeD` to represent the arrival and departure modes, + respectively. We can define constants for `ACTIVE` and `INACTIVE`, + as described in the `Constants` section above. + +- `W_A` and `W_D` to represent the number of planes waiting to arrive + and depart, respectively. + +- `Runway_Time` to represent the time (in minutes) that a plane has + spent on the runway while arriving or departing. + +- `Plane_Counter` to represent the number of planes that have arrived + or departed while planes are waiting for the other mode. This will + help us keep track of the 3-plane limit as described in _(6)_. + +```c title="exercises/runway/state.h" +--8<-- +exercises/runway/state.h +--8<-- +``` + +Next, we need to specify what makes a state valid. We must define a +rigorous specification in order to ensure that the runway is always +safe and working as intended. Try thinking about what this might look +like before looking at the code below. + +```c title="exercises/runway/valid_state.h" +--8<-- +exercises/runway/valid_state.h +--8<-- +``` + +Let's walk through the specifications in `valid_state`: + +- The first two lines ensure that both modes in our model behave as intended: they can only be active or inactive. Any other value for these fields would be invalid. + +- The third line says that either arrival mode or departure mode must be inactive. This specification ensures that the runway is never in both modes at the same time. + +- The fourth line says that the number of planes waiting to arrive or depart must be non-negative. This makes sense: we can't have a negative number of planes! + +- The fifth line ensures that the runway time is between 0 and 5. This addresses how a plane takes 5 minutes on the runway as described in _(4)_. + +- The sixth line ensures that the plane counter is between 0 and 3. This is important for the 3-plane limit as described in _(6)_. + +- The seventh line refers to the state at the beginning of the day. If both modes are inactive, then the day has just begun, and thus no planes have departed yet. This is why the plane counter must be 0. + +- The eighth line says that if there is a plane on the runway, then one of the modes must be active. This is because a plane can only be on the runway if it is either arriving or departing. + +- The final two lines ensure that we are incrementing `Plane_Counter` only if there are planes waiting for the other mode, as described in _(6)_. + +Now that we have the tools to reason about the state of the runway formally, let's start writing some functions. + +First, let's look at an initialization function and functions to update `Plane_Counter`. Step through these yourself and make sure you understand the reasoning behind each specification. + +```c title="exercises/runway/funcs1.h" +--8<-- +exercises/runway/funcs1.h +--8<-- +``` + +_Exercise_: Now try adding your own specifications to the following +functions. Make sure that you specify a valid state as a pre- and +post-condition for every function. If you get stuck, the solution is +in the solutions folder. + +```c title="exercises/runway/funcs2.c" +--8<-- +exercises/runway/funcs2.c +--8<-- +``` + + + +## Acknowledgment of Support and Disclaimer + +This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). + + + + diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index a6f2d4b2..f2661745 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -30,7 +30,11 @@ - [(Verification) Verifying imperative queues](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) -- [Airport Simulation](../case-studies/the-runway.md) +- [(Verification) + Verifying doubly-linked lists](../case-studies/verif-doubly-linked-lists.md) +- [Airport simulation](../case-studies/the-runway.md) +- [(Verification) + Verifying the airport simulation](../case-studies/verif-the-runway.md) ## TODOs diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index eeeab28c..b795737a 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -107,3 +107,74 @@ The current case studies from the verification tutorial maybe people start by writing unit tests and later add PBT; it would be silly to *not* run the unit tests they've written. +## Older notes + +Further topics: + +- doubly linked lists +- Trees: - deep copy - sum - maybe the accumulating sum +- cn_function +- pack +- bitwise functions (operators are not present in the logical language) +- "ownership" in Rust vs. CN +- tips amnd tricks -- + cf. [](https://dafny.org/dafny/DafnyRef/DafnyRef.html#sec-verification) +- more data structures to try out + [](https://www.geeksforgeeks.org/data-structures/#most-popular-data-structures) +- Maybe add some explanation of -- or at least a pointer to -- + Dhruv's Iris-in-C examples: + pop_queue_lemma_stages.c + push_queue_induction.c + pop_queue_unified.c + +Further exercises: + +- Some exercises that get THEM to write predicates, datatype + declarations, etc. + +Misc things to do: + +- replace 0 with NULL in specs + +- naming issues - rename == to ptr_eq everywhere in specs - rename list to List in filenames. or go more radical and rename List to cnlist - consider renaming SLList_At to just List (and sllist to just list, + etc.) everywhere (since we are only dealing with one kind of list + in the tutorial, the extra pedantry is not getting us much; and + this simplification would avoid trying to fix conventions that all + CN code should use everywhere...) + + - related: the name Cons is awkward for several reasons: + - long / verbose (nothing to do about that, I guess) + - Seq is capitalized, but it means List + - most important part is buried in the middle + - What are the established C conventions here?? + +- some of the examples use int while the exercises that follow use + unsigned int. This is a needless source of potential confusion. + +- everyplace we do storage allocation, we should really allow the + malloc call to return NULL if it wants to; the caller should + explicitly check that it didn't get back NULL. This requires + defining an "exit" function" with trivial pre- and postconditions + (true / false). + +- In queue.c, when I tried /_@ unfold QueueAux (F.front, F.back, + B.first); @_/ I was confused by "the specification function + `QueueAux' is not declared". I guess this is, again, the + distinction between functions and predicates...? + +- In debugging the queue example, The fact that some of the + constraints in the error report are forced while others are random + values filled in by the SMT solver is pretty problematic... + +For later: + +Alternative formatting tools to consider at some point (not now!): +probably the best fit: +[](https://myst-parser.readthedocs.io/en/latest/) +another very standard one to consider: +alternative: [](https://www.sphinx-doc.org/en/master/index.html) + +Misc notes: + +- Nb: take V = RW(p) === p |-t-> V + diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 5c61fe0f..9c536abb 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -39,4 +39,7 @@ Before getting started, make sure you have a running installation of CN and a local copy of the source files for all the exercises and examples; these can be downloaded from [here](link:exercises.zip). +## Acknowledgment of Support and Disclaimer + +This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). diff --git a/src/exercises/dll/add.test.c b/src/exercises/dll/add.test.c new file mode 100644 index 00000000..7fa8d997 --- /dev/null +++ b/src/exercises/dll/add.test.c @@ -0,0 +1,42 @@ +#include "./headers.test.h" + +// Adds after the given node and returns a pointer to the new node +struct dllist *add(int element, struct dllist *n) +/* --BEGIN-- */ +/*@ requires take Before = Dll_at(n); + ensures take After = Dll_at(return); + is_null(n) ? + After == Nonempty_Dll { + left: Nil{}, + curr: Node(After), + right: Nil{}} + : After == Nonempty_Dll { + left: Cons {Head: Node(Before).data, + Tail: Left_Sublist(Before)}, + curr: Node(After), + right: Right_Sublist(Before)}; +@*/ +/* --END-- */ +{ + struct dllist *new_dllist = malloc__dllist(); + new_dllist->data = element; + new_dllist->prev = 0; + new_dllist->next = 0; + + if (n == 0) //empty list case + { + new_dllist->prev = 0; + new_dllist->next = 0; + return new_dllist; + } else { + new_dllist->next = n->next; + new_dllist->prev = n; + + if (n->next != 0) { + n->next->prev = new_dllist; + } + + n->next = new_dllist; + return new_dllist; + } +} diff --git a/src/exercises/dll/allocation.test.h b/src/exercises/dll/allocation.test.h new file mode 100644 index 00000000..e89b48e0 --- /dev/null +++ b/src/exercises/dll/allocation.test.h @@ -0,0 +1,13 @@ +#include "../cn_malloc.h" + +struct dllist *malloc__dllist() +/*@ ensures take R = W(return); @*/ +{ + return cn_malloc(sizeof(struct dllist)); +} + +void free__dllist (struct dllist *p) +/*@ requires take P = W(p); @*/ +{ + cn_free_sized(p, sizeof(struct dllist)); +} diff --git a/src/exercises/dll/malloc_free.h b/src/exercises/dll/allocation.verif.h similarity index 100% rename from src/exercises/dll/malloc_free.h rename to src/exercises/dll/allocation.verif.h diff --git a/src/exercises/dll/dllist_and_int.test.h b/src/exercises/dll/dllist_and_int.test.h new file mode 100644 index 00000000..425060c5 --- /dev/null +++ b/src/exercises/dll/dllist_and_int.test.h @@ -0,0 +1,16 @@ +struct dllist_and_int { + struct dllist* dllist; + int data; +}; + +struct dllist_and_int *malloc__dllist_and_int() +/*@ ensures take R = W(return); @*/ +{ + return cn_malloc(sizeof(struct dllist_and_int)); +} + +void free__dllist_and_int (struct dllist_and_int *p) +/*@ requires take P = W(p); @*/ +{ + cn_free_sized(p, sizeof(struct dllist_and_int)); +} diff --git a/src/exercises/dll/dllist_and_int.h b/src/exercises/dll/dllist_and_int.verif.h similarity index 100% rename from src/exercises/dll/dllist_and_int.h rename to src/exercises/dll/dllist_and_int.verif.h diff --git a/src/exercises/dll/headers.test.h b/src/exercises/dll/headers.test.h new file mode 100644 index 00000000..bcf9cd4e --- /dev/null +++ b/src/exercises/dll/headers.test.h @@ -0,0 +1,8 @@ +#include "../list/headers.test.h" +#include "../list/append.h" +#include "../list/rev.h" +#include "./c_types.h" +#include "./cn_types.h" +#include "./getters.h" +#include "./allocation.test.h" +#include "./predicates.h" diff --git a/src/exercises/dll/headers.verif.h b/src/exercises/dll/headers.verif.h index 0fa29dc0..2ee55fcb 100644 --- a/src/exercises/dll/headers.verif.h +++ b/src/exercises/dll/headers.verif.h @@ -4,5 +4,5 @@ #include "./c_types.h" #include "./cn_types.h" #include "./getters.h" -#include "./malloc_free.h" +#include "./allocation.verif.h" #include "./predicates.h" diff --git a/src/exercises/dll/remove.test.c b/src/exercises/dll/remove.test.c new file mode 100644 index 00000000..0f0154ab --- /dev/null +++ b/src/exercises/dll/remove.test.c @@ -0,0 +1,42 @@ +#include "./headers.test.h" +#include "./dllist_and_int.test.h" + +// Remove the given node from the list and returns another pointer +// to somewhere in the list, or a null pointer if the list is empty +struct dllist_and_int *remove_current(struct dllist *n) +/* --BEGIN-- */ +/*@ requires !is_null(n); + take Before = Dll_at(n); + let Del = Node(Before); + ensures take Ret = RW(return); + take After = Dll_at(Ret.dllist); + Ret.data == Del.data; + (is_null(Del.prev) && is_null(Del.next)) + ? After == Empty_Dll{} + : (!is_null(Del.next) ? + After == Nonempty_Dll {left: Left_Sublist(Before), + curr: Node(After), + right: Tl(Right_Sublist(Before))} + : After == Nonempty_Dll {left: Tl(Left_Sublist(Before)), + curr: Node(After), + right: Right_Sublist(Before)}); +@*/ +/* --END-- */ +{ + struct dllist *temp = 0; + if (n->prev != 0) { + n->prev->next = n->next; + temp = n->prev; + } + if (n->next != 0) { + n->next->prev = n->prev; + temp = n->next; + } + + struct dllist_and_int *pair = malloc__dllist_and_int(); + pair->dllist = temp; + pair->data = n->data; + + free__dllist(n); + return pair; +} diff --git a/src/exercises/dll/remove.c b/src/exercises/dll/remove.verify.c similarity index 97% rename from src/exercises/dll/remove.c rename to src/exercises/dll/remove.verify.c index 5aad3846..bf148ba2 100644 --- a/src/exercises/dll/remove.c +++ b/src/exercises/dll/remove.verify.c @@ -1,5 +1,5 @@ #include "./headers.verif.h" -#include "./dllist_and_int.h" +#include "./dllist_and_int.verif.h" // Remove the given node from the list and returns another pointer // to somewhere in the list, or a null pointer if the list is empty diff --git a/src/exercises/dll/singleton.c b/src/exercises/dll/singleton.verif.c similarity index 100% rename from src/exercises/dll/singleton.c rename to src/exercises/dll/singleton.verif.c diff --git a/src/exercises/list/c_types.test.h b/src/exercises/list/c_types.test.h index f4c8150e..9c35e214 100644 --- a/src/exercises/list/c_types.test.h +++ b/src/exercises/list/c_types.test.h @@ -6,15 +6,13 @@ struct sllist { }; struct sllist *malloc__sllist() -/*@ ensures take R = W(return); -@*/ +/*@ ensures take R = W(return); @*/ { return cn_malloc(sizeof(struct sllist)); } void free__sllist (struct sllist *p) -/*@ requires take P = W(p); -@*/ +/*@ requires take P = W(p); @*/ { cn_free_sized(p, sizeof(struct sllist)); } diff --git a/src/exercises/queue/push.test.c b/src/exercises/queue/push.test.c index 9e78f062..1c86b076 100644 --- a/src/exercises/queue/push.test.c +++ b/src/exercises/queue/push.test.c @@ -8,7 +8,7 @@ void push_queue (int x, struct queue *q) @*/ /* --END-- */ { - struct queue_cell *c = malloc_queue_cell(); + struct queue_cell *c = malloc__queue_cell(); c->first = x; c->next = 0; if (q->back == 0) { From 4f6064957062c3bdcb565c68021912efc5b83db6 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 17:21:38 -0400 Subject: [PATCH 066/158] Tidying --- .../case-studies/verif-doubly-linked-lists.md | 2 +- .../getting-started/case-studies/verif-imperative-queues.md | 2 +- docs/getting-started/case-studies/verif-the-runway.md | 2 +- docs/getting-started/tutorials/README.md | 6 +++--- docs/getting-started/tutorials/alloc.md | 4 ++++ docs/getting-started/tutorials/compound.md | 3 ++- docs/getting-started/tutorials/welcome.md | 6 ++++-- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md index 729563ef..b292b44c 100644 --- a/docs/getting-started/case-studies/verif-doubly-linked-lists.md +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -1,4 +1,4 @@ -# Doubly-linked Lists +# Doubly-linked Lists, Verified Need updating after testing/verif split. diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md index 0586047a..c9fd65c8 100644 --- a/docs/getting-started/case-studies/verif-imperative-queues.md +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -1,4 +1,4 @@ -# Verifying Imperative Queues +# Imperative Queues, Verified Need updating after testing/verif split. diff --git a/docs/getting-started/case-studies/verif-the-runway.md b/docs/getting-started/case-studies/verif-the-runway.md index 5fe1e8a1..91c6099a 100644 --- a/docs/getting-started/case-studies/verif-the-runway.md +++ b/docs/getting-started/case-studies/verif-the-runway.md @@ -1,4 +1,4 @@ -# Airport Simulation +# Airport Simulation, Verified BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index f2661745..3a01a795 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -28,13 +28,13 @@ - [Imperative queues](../case-studies/imperative-queues.md) - [(Verification) - Verifying imperative queues](../case-studies/verif-imperative-queues.md) + Imperative queues, verified](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) - [(Verification) - Verifying doubly-linked lists](../case-studies/verif-doubly-linked-lists.md) + Doubly-linked lists, verified](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) - [(Verification) - Verifying the airport simulation](../case-studies/verif-the-runway.md) + Airport simulation, verified](../case-studies/verif-the-runway.md) ## TODOs diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index 5e279f2e..946ec713 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -1,5 +1,9 @@ # Allocating and Deallocating Memory + +BCP: Needs testing and verification variants. + + XXXXXXXXXXXXXXXXXXX intro needed ## W resources diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index ed46235d..ebfb6b68 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -50,7 +50,8 @@ The precondition of `transpose` asserts ownership of an `RW(p)` re - `RW(member_shift(p, y))` with output `P.y` -BCP: We should verify that it really does say this. +BCP: We should verify that it really does say this. (It certainly +does not, after recent syntax changes...) Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 9c536abb..640fd01f 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -33,7 +33,7 @@ the document. Most readers -- even readers whose primary interest is verification -- should skip these sections on a first reading and, if desired, come back to them on a second pass. -## Setup +## Setup Instructions Before getting started, make sure you have a running installation of CN and a local copy of the source files for all the exercises and @@ -42,4 +42,6 @@ examples; these can be downloaded from [here](link:exercises.zip). ## Acknowledgment of Support and Disclaimer This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). - + +Or DARPA? + From efa840b5a16e6436bb242de31075fb99597bc5f0 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 13 Mar 2025 17:21:59 -0400 Subject: [PATCH 067/158] Missing file --- src/exercises/dll/singleton.test.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/exercises/dll/singleton.test.c diff --git a/src/exercises/dll/singleton.test.c b/src/exercises/dll/singleton.test.c new file mode 100644 index 00000000..bc31fa53 --- /dev/null +++ b/src/exercises/dll/singleton.test.c @@ -0,0 +1,18 @@ +#include "./headers.test.h" + +struct dllist *singleton(int element) +/*@ ensures take Ret = Dll_at(return); + Ret == Nonempty_Dll { + left: Nil{}, + curr: struct dllist {prev: NULL, + data: element, + next: NULL}, + right: Nil{}}; +@*/ +{ + struct dllist *n = malloc__dllist(); + n->data = element; + n->prev = 0; + n->next = 0; + return n; +} From 19f46a376a150debea16eedb54075a419a54bcf3 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 14 Mar 2025 00:03:50 -0400 Subject: [PATCH 068/158] finish most of pointers chapter --- docs/getting-started/tutorials/pointers.md | 86 ++++++++++++++-------- src/exercises/double.c | 13 ++++ src/exercises/five_six.c | 12 +++ src/exercises/slf0_basic_incr.c | 6 +- src/exercises/slf3_basic_inplace_double.c | 10 +-- 5 files changed, 86 insertions(+), 41 deletions(-) create mode 100644 src/exercises/double.c create mode 100644 src/exercises/five_six.c diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index ce9ed74d..bfb0f044 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,7 +1,5 @@ # Pointers and Simple Ownership -JWS is in the middle of editing this section - words are common in real C code... --> -BCP: Do we mean 32-bit word here?? + @@ -159,38 +157,53 @@ exercises/read2.c CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. -_Exercise._ JWS: TODO, probably double +_Exercise._ Write a specification for `double`, which takes a pointer `p` and +returns double the pointee value. Running `cn test` on this correct +implementation should succeed, +```c title="exercises/double.c" +--8<-- +exercises/double.c +--8<-- +``` +while running `cn test` on this incorrect implementation +```C + int n = *p; + int m = n + n; + *p = 0; + return m; +``` +and this incorrect implementation +```C + int n = *p; + int m = n + n + n; + return m; +``` +should fail. ## Writing through pointers -Let’s explore resources and their outputs in another example. The C function -`incr` takes an `unsigned int` pointer `p` and increments the value in the -memory cell that it points to. +We next have an example where data is written to a pointer. The function +`incr` takes a pointer `p` and increments the value in the memory cell that it +points to. - + +```c title="exercises/slf0_basic_incr.c" --8<-- -exercises/slf0_basic_incr.signed.c +exercises/slf0_basic_incr.c --8<-- ``` -In the precondition we assert ownership of resource `RW(p)`, -binding its output/pointee value to `P`, and use `P` to specify -that `p` must point to a sufficiently small value at the start of -the function so as not to overflow when incremented. The postcondition -asserts ownership of `p` with output `P_post`, as before, and uses -this to express that the value `p` points to is incremented by -`incr`: `P_post == P + 1i32`. +The precondition binds the initial pointee value to `P`. The postcondition binds +the value _after_ function execution to `P_post`, and uses this to express that +the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. _Exercise._ Write a specification for `inplace_double`, which takes a pointer `p` and doubles the pointee value. Make sure your postcondition captures the function's intended behavior. -JWS: TODO make these unsigned int - ```c title="exercises/slf3_basic_inplace_double.c" --8<-- exercises/slf3_basic_inplace_double.c @@ -240,8 +253,6 @@ memory leaks are typically very undesirable. their resource footprint and, in particular, return any unused resources back to the caller. --> -_Exercise._ JWS: TODO - ## Disjoint memory regions When functions manipulate multiple pointers, we can assert ownership of each @@ -249,7 +260,18 @@ one, just like before. But there is an additional twist: simultaneously owning resources for two pointers implies that these pointers refer to _disjoint_ regions of memory. -JWS: TODO five/six example +Consider this example to see when disjointness matters: + +```c title="exercises/five_six.c" +--8<-- +exercises/five_six.c +--8<-- +``` + +The postcondition claims that the function returns `5`. Observe that this is +only true when `p` and `q` are disjoint; otherwise, the write to `q` would +override the write to `p`. In CN, we can make this assumption for free — no +extra work is needed to assert that the pointers are disjoint. _Exercise._ Write a specification for the function `transfer`, shown below. @@ -266,7 +288,7 @@ larger programs typically also manipulate compound values, often represented using C `struct`s. Specifying functions manipulating structs works in much the same way as with basic types. -For instance, the following example uses a `struct` `point` to +For instance, the following example uses a `struct point` to represent a point in two-dimensional space. The function `transpose` swaps a point’s `x` and `y` coordinates. @@ -276,21 +298,21 @@ exercises/transpose.c --8<-- ``` -Here the precondition asserts ownership for `p`, at type `struct -point`; the output `P_post` is a value of type `struct point`, i.e. a -record with members `x` and `y`. The postcondition similarly asserts -ownership of `p`, with output `P_post`, and asserts the coordinates -have been swapped, by referring to the members of `P` and `P_post` +Here we have `RW(p)` resources, with the appropriate type of `p` +filled in. Accordingly, `P` and `P_post` are values with type `struct point`, +i.e., they are records with members `x` and `y`. The postcondition asserts the +coordinates have been swapped by referring to the members of `P` and `P_post` individually. -The reason `RW` needs a C-type annotation is so that it can (a) + There is a design decision to consider here rems-project/cerberus#349 -_Exercise._ JWS: TODO +_Exercise._ TODO (it would be nice to actually find a +bug!) diff --git a/src/exercises/double.c b/src/exercises/double.c new file mode 100644 index 00000000..99be5768 --- /dev/null +++ b/src/exercises/double.c @@ -0,0 +1,13 @@ +unsigned int double (unsigned int *p) +/* --BEGIN-- */ +/*@ requires take P = RW(p); + ensures take P_post = RW(p); + return == P + P; + P_post == P; +@*/ +/* --END-- */ +{ + int n = *p; + int m = n + n; + return m; +} diff --git a/src/exercises/five_six.c b/src/exercises/five_six.c new file mode 100644 index 00000000..184a37fd --- /dev/null +++ b/src/exercises/five_six.c @@ -0,0 +1,12 @@ +unsigned int five_six(unsigned int *p, unsigned int *q) +/*@ requires take P = RW(p); + take Q = RW(q); + ensures take P_post = RW(p); + take Q_post = RW(q); + return == 5; +@*/ +{ + *p = 5; + *q = 6; + return *p; +} \ No newline at end of file diff --git a/src/exercises/slf0_basic_incr.c b/src/exercises/slf0_basic_incr.c index 51105193..7f8c0793 100644 --- a/src/exercises/slf0_basic_incr.c +++ b/src/exercises/slf0_basic_incr.c @@ -1,7 +1,7 @@ void incr (unsigned int *p) -/*@ requires take n1 = RW(p); - ensures take n2 = RW(p); - n2 == n1 + 1u32; +/*@ requires take P = RW(p); + ensures take P_post = RW(p); + P_post == P + 1u32; @*/ { unsigned int n = *p; diff --git a/src/exercises/slf3_basic_inplace_double.c b/src/exercises/slf3_basic_inplace_double.c index 2fcd00f9..b5bd30b0 100644 --- a/src/exercises/slf3_basic_inplace_double.c +++ b/src/exercises/slf3_basic_inplace_double.c @@ -1,10 +1,8 @@ -void inplace_double (int *p) +void inplace_double (unsigned int *p) /* --BEGIN-- */ -/*@ requires take P = RW(p); - let M = 2i64 * ((i64) P); - (i64) MINi32() <= M; M <= (i64) MAXi32(); - ensures take P_post = RW(p); - P_post == (i32) M; +/*@ requires take P = RW(p); + ensures take P_post = RW(p); + P_post == P + P; @*/ /* --END-- */ { From 1b3a8db961c7073b6267d6f964274f8e89d3bfca Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 14 Mar 2025 12:52:31 -0400 Subject: [PATCH 069/158] Polishing --- docs/getting-started/tutorials/README.md | 3 +- docs/getting-started/tutorials/first-taste.md | 63 ++++++++++++++++++- docs/getting-started/tutorials/pointers.md | 16 ++--- .../tutorials/preconditions.md | 44 ------------- docs/getting-started/tutorials/todo.md | 1 + src/exercises/{double.c => double_it.c} | 6 +- src/exercises/five_six.c | 4 +- src/exercises/slf3_basic_inplace_double.c | 4 +- 8 files changed, 78 insertions(+), 63 deletions(-) delete mode 100644 docs/getting-started/tutorials/preconditions.md rename src/exercises/{double.c => double_it.c} (68%) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 3a01a795..52c0e812 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -3,8 +3,7 @@ - [Welcome](welcome.md) ## A Tour of CN -- [Specifications](first-taste.md) -- [Preconditions](preconditions.md) +- [A first taste of CN: Specification and testing](first-taste.md) - [(Verification) A first taste of verification](verif-basics.md) - [Working with pointers](pointers.md) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 92376d06..02c29196 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,4 +1,10 @@ -# Specifications +# A First Taste of CN: Specification and Testing + +This section introduces the most basic features of CN: a notation for +writing _specifications_ of C functions and a tool for _testing_ the +behavior of the code against those specifications. + +## A First Specification Suppose we are writing a function `min3`, which takes three `unsigned int` arguments. @@ -46,6 +52,8 @@ exercises/min3/min3.broken.c --8<-- ``` +## Testing + How can we find out whether our implementation satisfies our specification? We can test it! @@ -158,11 +166,62 @@ _Exercise._ Practice the workflow of specifying and testing the function `add`. - Write a specification with the postcondition that `add` should return the sum of its inputs. Remember that CN supports standard arithmetic and boolean operators such as `+` and `==`. -- Write an _incorrect_ implementation of `add` and check that `cn test` fails. - Write a _correct_ implementation and check that `cn test` succeeds. +- Write an _incorrect_ implementation of `add` and check that `cn test` fails. +- Extra credit: Can you find a way to write an incorrect + implementation of `add` for which testing will (incorrectly) succeed + -- i.e., such that `cn test` cannot find a counterexample after 100 + tests? ```c title="exercises/add.partial.c" --8<-- exercises/add.partial.c --8<-- ``` + +## Specifications with Preconditions + +Here's a silly way of writing a function that +returns whatever number it is given as input: + +```c title="exercises/id_by_div/id_by_div.broken.c" +--8<-- +exercises/id_by_div/id_by_div.broken.c +--8<-- +``` + +If we try to `cn test` this function, however, we will get a counterexample such as this one: +``` +x = 7 +``` + +Oh! Because integer division is truncating, our silly function will +only work as desired when the input `x` is even. We can add this +requirement as a _precondition_, using the `requires` keyword. + +```c title="exercises/id_by_div/id_by_div.fixed.c" +--8<-- +exercises/id_by_div/id_by_div.fixed.c +--8<-- +``` + +A specification with both preconditions and postconditions says that, if +the preconditions hold at the point where the function is called, then the +postconditions will hold when the function returns. + +The other new piece of syntax here is the `u32` type annotations. In +CN specifications, numeric types need to be annotated explicitly, and +we use `u32` for `unsigned int`. Try removing the annotations to see +the error message that results. + +## Exercises + +_Exercise._ Without changing the postcondition or implementation, fix +the specification in the following example by adding a precondition on +the inputs `x` and `n`. Check that `cn test` succeeds. + +```c title="exercises/id_by_div/id_by_div_n.broken.c" +--8<-- +exercises/id_by_div/id_by_div_n.broken.c +--8<-- +``` diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index bfb0f044..55a48d57 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -157,25 +157,25 @@ exercises/read2.c CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. -_Exercise._ Write a specification for `double`, which takes a pointer `p` and +_Exercise._ Write a specification for `double_it`, which takes a pointer `p` and returns double the pointee value. Running `cn test` on this correct implementation should succeed, -```c title="exercises/double.c" +```c title="exercises/double_it.c" --8<-- -exercises/double.c +exercises/double_it.c --8<-- ``` while running `cn test` on this incorrect implementation ```C - int n = *p; - int m = n + n; + unsigned int n = *p; + unsigned int m = n + n; *p = 0; return m; ``` -and this incorrect implementation +or this incorrect implementation ```C - int n = *p; - int m = n + n + n; + unsigned int n = *p; + unsigned int m = n + n + n; return m; ``` should fail. diff --git a/docs/getting-started/tutorials/preconditions.md b/docs/getting-started/tutorials/preconditions.md deleted file mode 100644 index fadbadca..00000000 --- a/docs/getting-started/tutorials/preconditions.md +++ /dev/null @@ -1,44 +0,0 @@ -# Specifications with Preconditions - -Here's a silly way of writing a function that -returns whatever number it is given as input: - -```c title="exercises/id_by_div/id_by_div.broken.c" ---8<-- -exercises/id_by_div/id_by_div.broken.c ---8<-- -``` - -If we try to `cn test` this function, however, we will get a counterexample such as this one: -``` -x = 7 -``` - -Oh! Because integer division is truncating, our silly function will -only work as desired when the input `x` is even. We can add this -requirement as a _precondition_, using the `requires` keyword. - -```c title="exercises/id_by_div/id_by_div.fixed.c" ---8<-- -exercises/id_by_div/id_by_div.fixed.c ---8<-- -``` - -A specification with both preconditions and postconditions says that, if -the preconditions hold at the point where the function is called, then the -postconditions will hold when the function returns. - -The other new piece of syntax here is the `u32` type annotations. In -CN specifications, numeric types need to be annotated explicitly, and -we use `u32` for `unsigned int`. Try removing the annotations to see -the error message that results. - -_Exercise._ Without changing the postcondition or implementation, fix -the specification in the following example by adding a precondition on -the inputs `x` and `n`. Check that `cn test` succeeds. - -```c title="exercises/id_by_div/id_by_div_n.broken.c" ---8<-- -exercises/id_by_div/id_by_div_n.broken.c ---8<-- -``` diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index b795737a..71ad1528 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -31,6 +31,7 @@ - The file `overview-pbt.md` is mostly subsumed by other text here, but there are some more specific instructions that probably belong in the reference manual. +- rename some .broken files to .partial? ## General notes diff --git a/src/exercises/double.c b/src/exercises/double_it.c similarity index 68% rename from src/exercises/double.c rename to src/exercises/double_it.c index 99be5768..7258d4c8 100644 --- a/src/exercises/double.c +++ b/src/exercises/double_it.c @@ -1,4 +1,4 @@ -unsigned int double (unsigned int *p) +unsigned int double_it (unsigned int *p) /* --BEGIN-- */ /*@ requires take P = RW(p); ensures take P_post = RW(p); @@ -7,7 +7,7 @@ unsigned int double (unsigned int *p) @*/ /* --END-- */ { - int n = *p; - int m = n + n; + unsigned int n = *p; + unsigned int m = n + n; return m; } diff --git a/src/exercises/five_six.c b/src/exercises/five_six.c index 184a37fd..82ddf8ee 100644 --- a/src/exercises/five_six.c +++ b/src/exercises/five_six.c @@ -3,10 +3,10 @@ unsigned int five_six(unsigned int *p, unsigned int *q) take Q = RW(q); ensures take P_post = RW(p); take Q_post = RW(q); - return == 5; + return == 5u32; @*/ { *p = 5; *q = 6; return *p; -} \ No newline at end of file +} diff --git a/src/exercises/slf3_basic_inplace_double.c b/src/exercises/slf3_basic_inplace_double.c index b5bd30b0..2e2a07b9 100644 --- a/src/exercises/slf3_basic_inplace_double.c +++ b/src/exercises/slf3_basic_inplace_double.c @@ -6,7 +6,7 @@ void inplace_double (unsigned int *p) @*/ /* --END-- */ { - int n = *p; - int m = n + n; + unsigned int n = *p; + unsigned int m = n + n; *p = m; } From 26f7190e925ddeaee826ad3a56bcca66147d8803 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 14 Mar 2025 16:00:28 -0400 Subject: [PATCH 070/158] Polishing --- docs/getting-started/tutorials/README.md | 18 +++++++++--------- docs/getting-started/tutorials/first-taste.md | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 52c0e812..351d6ced 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,35 +4,35 @@ ## A Tour of CN - [A first taste of CN: Specification and testing](first-taste.md) -- [(Verification) +- [   (Verification) A first taste of verification](verif-basics.md) - [Working with pointers](pointers.md) -- [(Verification) +- [   (Verification) Pointers to structured objects, verified](compound.md) - [Arrays and loops](arrays.md) -- [(Verification) +- [   (Verification) Arrays and loops, verified](verif-arrays.md) - [Allocating and deallocating memory](alloc.md) - [More on numeric types](numeric.md) - [Defining predicates](predicates.md) - [Lists](lists.md) -- [(Verification) +- [   (Verification) Lists](verif-lists.md) -- [(Verification) +- [   (Verification) Case analysis](verif-splitcase.md) -- [(Verification) +- [   (Verification) Working with external lemmas](verif-external.md) ## Case studies - [Imperative queues](../case-studies/imperative-queues.md) -- [(Verification) +- [   (Verification) Imperative queues, verified](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) -- [(Verification) +- [   (Verification) Doubly-linked lists, verified](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) -- [(Verification) +- [   (Verification) Airport simulation, verified](../case-studies/verif-the-runway.md) ## TODOs diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 02c29196..e1cfc545 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -153,7 +153,7 @@ cases: 1, passed: 1, failed: 0, errored: 0, skipped: 0 Hooray! -## Exercises +### Exercises _Refining the specification of `min3`_: The specification we wrote is a bit loose: It says the result value should be smaller than `x`, `y`, @@ -214,7 +214,7 @@ CN specifications, numeric types need to be annotated explicitly, and we use `u32` for `unsigned int`. Try removing the annotations to see the error message that results. -## Exercises +### Exercises _Exercise._ Without changing the postcondition or implementation, fix the specification in the following example by adding a precondition on From 9f6e142336ac87ee1aded6009c7f23068baa2733 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 26 Mar 2025 16:56:11 -0400 Subject: [PATCH 071/158] Testing tutorial tidying --- Makefile | 1 - docs/README.md | 20 ++++---- docs/getting-started/tutorials/first-taste.md | 51 +++++++------------ docs/getting-started/tutorials/pointers.md | 42 ++++++++------- .../getting-started/tutorials/verif-basics.md | 9 ++-- docs/getting-started/tutorials/welcome.md | 13 +++-- 6 files changed, 64 insertions(+), 72 deletions(-) diff --git a/Makefile b/Makefile index f9b70143..861e2454 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,6 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ # NOT WORKING? # _temp/tested/slf18_two_dice.c \ - MD = $(shell find docs -type f -name "*.md") CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) diff --git a/docs/README.md b/docs/README.md index 85367959..1f2b3635 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,16 +3,6 @@ _These tutorials and docs were developed by Christopher Pulte, Benjamin C. Pierce, and Cole Schlesinger, with contributions from Elizbeth Austell._ -??? info "BibTeX" - ``` - @misc{cn-tutorial, - author = {Christopher Pulte and Benjamin C. Pierce and Cole Schlesinger and Elizabeth Austell}, - title = {{CN Tutorial}}, - howpublished = "\url{https://rems-project.github.io/cn-tutorial/}", - year = {2025}, - } - ``` - CN is an extension of the C programming language for testing and verifying the correctness of C code, especially on low-level systems code. Compared to standard C, CN checks not only that expressions and statements follow the @@ -64,6 +54,16 @@ Some of the examples in this tutorial are adapted from Arthur Charguéraud’s e [Separation Logic Foundations](https://softwarefoundations.cis.upenn.edu) textbook, and one of the case studies is based on an extended exercise due to Bryan Parno. +??? info "BibTeX citation" + ``` + @misc{cn-tutorial, + author = {Christopher Pulte and Benjamin C. Pierce and Cole Schlesinger and Elizabeth Austell}, + title = {{CN Tutorial}}, + howpublished = "\url{https://rems-project.github.io/cn-tutorial/}", + year = {2025}, + } + ``` + ## Acknowledgment of Support and Disclaimer This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index e1cfc545..ead98851 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -57,35 +57,31 @@ exercises/min3/min3.broken.c How can we find out whether our implementation satisfies our specification? We can test it! -Running the command `cn test ` will produce an output along -these lines: - - -BCP: Refresh this: - +Running the command `cn test ` in a terminal will produce an output along +the following lines. To open a terminal inside VSCode (which will +ensure your paths are set up correctly, etc.), use `View > Terminal`. ``` $ cn test min3.broken.c -Compiled 'min3_test.c'. -Compiled 'min3-exec.c'. -Compiled 'cn.c'. - -Linked C *.o files. - -Using seed: 50c34e798b33622c -Testing min3::min3: 2 runs +Testing min3::min3: 1 runs FAILED -... - +************************ Failed at ************************* +function min3, file ./min3.broken-exec.c, line 55 original source location: /*@ ensures return <= x - ^~~~~~~~~~~ min3.c:2:13-4:28 -CN assertion failed. + ^~~~~~~~~~~ min3/min3.broken.c:2:13-4:28 + +********************** Failing input *********************** +unsigned int x = (unsigned int)(10); +unsigned int y = (unsigned int)(2); +unsigned int z = (unsigned int)(14); +min3(x, y, z); + +************************************************************ -Testing Summary: cases: 1, passed: 0, failed: 1, errored: 0, skipped: 0 ``` @@ -108,17 +104,9 @@ Here, `cn test` generates three integer inputs, runs `min3` on these inputs, and checks that the output satisfies the postcondition. It repeats this process until either some number (by default, 100) of tests succeed or else a failing test, called a _counterexample_, is -encountered. - -We can do -(what do we need to do??) - -to see our counterexample inputs: -``` -x = 13 -y = 4 -z = 9 -``` +encountered. In this case, the counterexample is printed out in +the form of a snipped of C code that will recreate the failing +situation. (The counterexample you will see if you run the tests yourself will most likely be different, due to randomness, but the debugging logic @@ -146,9 +134,6 @@ Now, if we run `cn test` again, the output should end with this message that the ``` Testing min3::min3: 100 runs PASSED - -Testing Summary: -cases: 1, passed: 1, failed: 0, errored: 0, skipped: 0 ``` Hooray! diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 55a48d57..bdb3aa64 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -39,22 +39,25 @@ the permission to access a region of memory. Let’s look at a simple example. The function `read` takes an integer pointer `p` and returns the pointee value. -```c title="exercises/read.c" +```c title="exercises/read.broken.c" --8<-- exercises/read.c --8<-- ``` Running `cn test` on this example produces an error that looks like this: - ``` Testing read::read: FAILED -function read, file ./read-exec.c, line 18 -************************************************************ -function read, file ./read-exec.c, line 18 + +************************ Failed at ************************* +function read, file ./read-exec.c, line 19 Load failed. - ==> 0x122592a09[0] (0x122592a09) not RW + ==> 0x12294ca70[0] (0x12294ca70) not owned +********************** Failing input *********************** + +unsigned int* p = (unsigned int*)(12294ca70); +read(p); ``` For the read `*p` to be safe, we need to know that the function has permission @@ -224,15 +227,22 @@ exercises/read.broken.c CN rejects this program with the following message: ``` -> cn test exercises/read.broken.c -... +Testing read::read: FAILED -... -Postcondition leak check failed, ownership leaked for pointer 0x1243d8a82 -... + +************************ Failed at ************************* +function read, file ./read.broken-exec.c, line 26 +Postcondition leak check failed, ownership leaked for pointer 0x1201e8a78 + +********************** Failing input *********************** + +void* p0 = malloc(4); +*((unsigned int*)p0) = 17; +unsigned int* p = (unsigned int*)(p0); +read(p); ``` -BCP: Explain what that means. Update if the output format changes. +BCP: Explain what that means. - -There is a design decision to consider here rems-project/cerberus#349 - - -_Exercise._ TODO (it would be nice to actually find a -bug!) +_Exercise._ TODO: it would be nice to add an +exercise that involves using the error messages to find a bug... diff --git a/docs/getting-started/tutorials/verif-basics.md b/docs/getting-started/tutorials/verif-basics.md index 0749f1d7..ec8255c4 100644 --- a/docs/getting-started/tutorials/verif-basics.md +++ b/docs/getting-started/tutorials/verif-basics.md @@ -5,7 +5,7 @@ Property-based testing is great for increasing our confidence that the function satisfies its specification, but we might also want to _verify_ this formally. Run `cn verify ` on the buggy -version to produce this output: +version to produce this output: ``` [1/1]: min3 -- fail @@ -27,11 +27,8 @@ Whereas `cn test` treats the function body as a black box, `cn verify` analyzes it directly, examining all possible paths through the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a -constraint that cannot be satisfied. - -## More stuff +constraint that cannot be satisfied. -Write me... +TODO: What else do we need to talk about in this introductory section? - diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 640fd01f..7f520520 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -41,7 +41,12 @@ examples; these can be downloaded from [here](link:exercises.zip). ## Acknowledgment of Support and Disclaimer -This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). - -Or DARPA? - +This material is based upon work supported by the Air Force Research +Laboratory (AFRL) and Defense Advanced Research Projects Agencies +(DARPA) under Contract No. FA8750-24-C-B044, a European Research +Council (ERC) Advanced Grant “ELVER” under the European Union’s +Horizon 2020 research and innovation programme (grant agreement +no. 789108), and additional funding from Google. The opinions, +findings, and conclusions or recommendations expressed in this +material are those of the authors and do not necessarily reflect the +views of AFRL or DARPA. From e7adf61b6dfdb27b689d63208c7472f08faed7c3 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 27 Mar 2025 13:23:12 -0400 Subject: [PATCH 072/158] Work on alloc.md --- docs/getting-started/tutorials/alloc.md | 71 +++++++------------ docs/getting-started/tutorials/morestuff.md | 14 ++++ docs/getting-started/tutorials/pointers.md | 2 +- docs/getting-started/tutorials/verif-alloc.md | 31 ++++++++ src/exercises/cn_malloc.h | 2 +- src/exercises/cn_malloc_unsigned_int.h | 11 +++ src/exercises/slf17_get_and_free.test.c | 34 +++++++++ 7 files changed, 116 insertions(+), 49 deletions(-) create mode 100644 docs/getting-started/tutorials/morestuff.md create mode 100644 docs/getting-started/tutorials/verif-alloc.md create mode 100644 src/exercises/cn_malloc_unsigned_int.h create mode 100644 src/exercises/slf17_get_and_free.test.c diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index 946ec713..f1c9f57a 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -1,10 +1,6 @@ # Allocating and Deallocating Memory - -BCP: Needs testing and verification variants. - - -XXXXXXXXXXXXXXXXXXX intro needed +Our next topic is programs that use dynamically allocated heap memory. ## W resources @@ -22,15 +18,18 @@ CN uses this distinction to prevent reads from uninitialised memory: right C-type. The load returns the `RW` resource unchanged. - A write at C-type `T` and pointer `p` needs only a -`W(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `W` resource -(it destroys it) and returns a new resource `RW(p)` with the -value written as the output. This means the resource returned from a -write records the fact that this memory cell is now initialised and -can be read from. - -BCP: Not sure I understand "returns a new resource `RW(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. - + `W(p)` (so, unlike reads, writes to uninitialised memory + are fine). The write consumes ownership of the `W` resource + (it destroys it) and returns a new resource `RW(p)` with the + value written as the output. This means the resource returned from a + write records the fact that this memory cell is now initialised and + can be read from. + + BCP: Not sure I understand "returns a new resource `RW(p)` with + the value written as the output" -- perhaps in part because I don't + understand what the output of a resource means when the resource is + not in the context o a take expression. + Since `RW` carries the same ownership as `W`, just with the additional information that the `RW` memory is initalised, a @@ -45,42 +44,37 @@ Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. ## Allocation - -BCP: Again, more text is needed to set up this discussion. Maybe the -first para should move up? - - At the moment, CN does not understand the `malloc` and `free` functions. They are a bit tricky because they rely on a bit of polymorphism and a typecast between `char*` -- the result type of `malloc` and argument type of `free` -- and the actual type of the object being allocated or deallocated. + +BCP: Fix this + However, for any given type, we can define a type-specific function that allocates heap storage with exactly that type. The implementation of this function cannot be checked by CN, but we can give just the spec, together with a promise to link against an external C library providing a correct (but not verified!) implementation: -```c title="exercises/malloc.h" +```c title="exercises/cn_malloc.h" --8<-- -exercises/malloc.h +exercises/cn_malloc.h --8<-- ``` -(Alternatively we can include an implementation written in arbitrary C -inside a CN file by marking it with the keyword `trusted` at the top -of its CN specification.) - -Similarly: - -```c title="exercises/free.h" +```c title="exercises/cn_malloc_unsigned_int.h" --8<-- -exercises/free.h +exercises/cn_malloc_unsigned_int.h --8<-- ``` Now we can write code that allocates and frees memory: + +BCP: It should also malloc some memory! + ```c title="exercises/slf17_get_and_free.c" --8<-- @@ -110,7 +104,7 @@ exercises/slf16_basic_succ_using_incr.c ### Exercises -BCP: There should be a non-ref-using version of this earlier, for comparison. +BCP: There should be a non-ref-using version of this earlier, for comparison. Prove a specification for the following program that reveals _only_ @@ -122,20 +116,3 @@ pointed to by its argument. exercises/slf_ref_greater.c --8<-- ``` - -### Side note - - -TODO: BCP: This is a bit random -- it's not clear people need to know about this alternate syntax, and it's awkwardly mixed with a semi-interesting example that's not relevant to this section. - - -Here is another syntax for external / unknown -functions, together with an example of a loose specification: - -```c title="exercises/slf18_two_dice.c" ---8<-- -exercises/slf18_two_dice.c ---8<-- -``` - - diff --git a/docs/getting-started/tutorials/morestuff.md b/docs/getting-started/tutorials/morestuff.md new file mode 100644 index 00000000..67390507 --- /dev/null +++ b/docs/getting-started/tutorials/morestuff.md @@ -0,0 +1,14 @@ +# Additional / Homeless Material + +### Side note + +Here is another syntax for external / unknown +functions, together with an example of a loose specification: + +```c title="exercises/slf18_two_dice.c" +--8<-- +exercises/slf18_two_dice.c +--8<-- +``` + + diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index bdb3aa64..352de7c9 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -39,7 +39,7 @@ the permission to access a region of memory. Let’s look at a simple example. The function `read` takes an integer pointer `p` and returns the pointee value. -```c title="exercises/read.broken.c" +```c title="exercises/read.c" --8<-- exercises/read.c --8<-- diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md new file mode 100644 index 00000000..f5ac625c --- /dev/null +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -0,0 +1,31 @@ +# (Verification) Allocating and Deallocating Memory + +## Verification with malloc and free + + +BCP: Needs text + + +```c title="exercises/malloc.h" +--8<-- +exercises/malloc.h +--8<-- +``` + +(Alternatively we can include an implementation written in arbitrary C +inside a CN file by marking it with the keyword `trusted` at the top +of its CN specification.) + +Similarly: + +```c title="exercises/free.h" +--8<-- +exercises/free.h +--8<-- +``` + +```c title="exercises/slf17_get_and_free.c" +--8<-- +exercises/slf17_get_and_free.c +--8<-- +``` diff --git a/src/exercises/cn_malloc.h b/src/exercises/cn_malloc.h index 65048287..c598a0c3 100644 --- a/src/exercises/cn_malloc.h +++ b/src/exercises/cn_malloc.h @@ -1,4 +1,4 @@ #include extern void* cn_malloc(size_t size); -extern void cn_free_sized(void *ptr, size_t size); +extern void cn_free_sized(void *ptr, size_t size); diff --git a/src/exercises/cn_malloc_unsigned_int.h b/src/exercises/cn_malloc_unsigned_int.h new file mode 100644 index 00000000..619ccd4f --- /dev/null +++ b/src/exercises/cn_malloc_unsigned_int.h @@ -0,0 +1,11 @@ +unsigned int *malloc__unsigned_int() +/*@ ensures take R = W(return); @*/ +{ + return cn_malloc(sizeof(unsigned int)); +} + +void free__unsigned_int (unsigned int *p) +/*@ requires take P = W(p); @*/ +{ + cn_free_sized(p, sizeof(unsigned int)); +} diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c new file mode 100644 index 00000000..5d19a05b --- /dev/null +++ b/src/exercises/slf17_get_and_free.test.c @@ -0,0 +1,34 @@ +#include "cn_malloc.h" +#include "cn_malloc_unsigned_int.h" + +/* ------------- */ + +unsigned int get_and_free (unsigned int *p) +/*@ requires take P = RW(p); + ensures return == P; +@*/ +{ + unsigned int v = *p; + free__unsigned_int (p); + return v; +} + +unsigned int *malloc_and_set (unsigned int x) +/*@ ensures take P = RW(return); + P == x; +@*/ +{ + unsigned int *p = malloc__unsigned_int (); + *p = x; + return p; +} + +/* BCP: Why doesn't this compile? */ +// unsigned int tester() { +// /*@ requires true; +// ensures return = 42; +// @*/ +// unsigned int *p = malloc_and_set (42); +// unsigned int v = get_and_free (p); +// return v; +// } From 0b075d4bffa83291e99dc2f478b4096ab9412470 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 28 Mar 2025 07:11:01 -0400 Subject: [PATCH 073/158] More rearranging and writing --- Makefile | 5 + docs/getting-started/tutorials/README.md | 25 ++-- docs/getting-started/tutorials/alloc.md | 134 +++++++----------- docs/getting-started/tutorials/first-taste.md | 15 ++ docs/getting-started/tutorials/lists.md | 65 +++------ docs/getting-started/tutorials/morestuff.md | 45 +++++- docs/getting-started/tutorials/pointers.md | 5 +- docs/getting-started/tutorials/predicates.md | 33 +---- docs/getting-started/tutorials/verif-alloc.md | 57 ++++++-- docs/getting-started/tutorials/verif-lists.md | 14 +- .../{numeric.md => verif-numeric.md} | 0 .../00008_overload_dyn_method.c | 6 +- src/exercises/greater.c | 9 ++ src/exercises/list/append.test.c | 4 +- src/exercises/list/append.verif.c | 4 +- src/exercises/list/append2.c | 16 +-- src/exercises/list/append2.test.c | 38 +++++ src/exercises/list/c_types.h | 4 + src/exercises/list/c_types.test.h | 5 - src/exercises/list/c_types.verif.h | 5 - src/exercises/list/copy.c | 4 +- src/exercises/list/headers.test.h | 1 + src/exercises/list/headers.verif.h | 1 + src/exercises/list/mergesort.verif.c | 22 +-- src/exercises/list/rev.c | 14 +- src/exercises/queue/headers.test.h | 1 + src/exercises/queue/headers.verif.h | 1 + src/exercises/slf17_get_and_free.test.c | 23 ++- ..._and_free.c => slf17_get_and_free.verif.c} | 0 src/exercises/slf_greater.test.c | 17 +++ src/exercises/slf_incr2.c | 6 +- src/exercises/slf_incr2.test.c | 6 +- src/old/tutorial.md | 10 +- 33 files changed, 325 insertions(+), 270 deletions(-) rename docs/getting-started/tutorials/{numeric.md => verif-numeric.md} (100%) create mode 100644 src/exercises/greater.c create mode 100644 src/exercises/list/append2.test.c create mode 100644 src/exercises/list/c_types.h rename src/exercises/{slf17_get_and_free.c => slf17_get_and_free.verif.c} (100%) create mode 100644 src/exercises/slf_greater.test.c diff --git a/Makefile b/Makefile index 861e2454..dfbd459b 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/slf_incr2_noalias.c \ _temp/tested/slf10_basic_ref.c \ _temp/tested/add_2.c \ + _temp/tested/greater.c \ _temp/tested/add_two_array.c \ _temp/tested/transpose.c \ _temp/tested/read2.c \ @@ -78,6 +79,10 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/slf0_basic_incr.signed.c \ _temp/tested/slf15_basic_succ_using_incr_attempt_.c +# Extra dependencies +_temp/tested/list/*.c : src/exercises/list/*.h +_temp/verified/list/*.c : src/exercises/list/*.h + # NOT WORKING? # _temp/tested/slf18_two_dice.c \ diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 351d6ced..e653156e 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,35 +4,38 @@ ## A Tour of CN - [A first taste of CN: Specification and testing](first-taste.md) -- [   (Verification) +- [      (Verification) A first taste of verification](verif-basics.md) - [Working with pointers](pointers.md) -- [   (Verification) +- [      (Verification) Pointers to structured objects, verified](compound.md) - [Arrays and loops](arrays.md) -- [   (Verification) +- [      (Verification) Arrays and loops, verified](verif-arrays.md) - [Allocating and deallocating memory](alloc.md) -- [More on numeric types](numeric.md) +-       (Verification) + [Allocating and deallocating memory, verified](verif-alloc.md) - [Defining predicates](predicates.md) - [Lists](lists.md) -- [   (Verification) - Lists](verif-lists.md) -- [   (Verification) +- [      (Verification) + Lists, verified](verif-lists.md) +- [      (Verification) Case analysis](verif-splitcase.md) -- [   (Verification) +- [      (Verification) Working with external lemmas](verif-external.md) +- [      (Verification) + [More on numeric types](verif-numeric.md) ## Case studies - [Imperative queues](../case-studies/imperative-queues.md) -- [   (Verification) +- [      (Verification) Imperative queues, verified](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) -- [   (Verification) +- [      (Verification) Doubly-linked lists, verified](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) -- [   (Verification) +- [      (Verification) Airport simulation, verified](../case-studies/verif-the-runway.md) ## TODOs diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index f1c9f57a..920d6d46 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -2,14 +2,57 @@ Our next topic is programs that use dynamically allocated heap memory. +## Malloc and free + +Heap-using programs in CN can be written in almost exactly the same +way as in vanilla C. The only difference is that, instead of calling +`malloc` and `free`, programs should call `cn_malloc` and `cn_free_sized`. +These are CN-specific versions of the usual `malloc` and `free` that +do some testing-related bookkeeping in addition to their main job of +allocating or deallocating heap memory. The second argument to +`cn_free_sized` is the size of the structure being freed, same as the +argument to `cn_malloc`. + +```c title="exercises/cn_malloc.h" +--8<-- +exercises/cn_malloc.h +--8<-- +``` + +Using `cn_malloc` and `cn_free`, we can write higher-level programs +that manipulate the heap, as usual. + +```c title="exercises/slf17_get_and_free.test.c" +--8<-- +exercises/slf17_get_and_free.test.c +--8<-- +``` + +BCP: The `tester` function here does not parse -- not sure why. + + + +### Exercises + +Write a specification for the following program that reveals _only_ +that it returns a pointer to a number that is greater than the number +pointed to by its argument. + +```c title="exercises/slf_greater.test.c" +--8<-- +exercises/slf_greater.test.c +--8<-- +``` + ## W resources -Aside from the `RW` resources seen so far, CN has another -built-in type of resource called `W`. Given a C-type `T` and -pointer `p`, `W(p)` asserts the same ownership as -`RW(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `RW`, `W` memory is not assumed -to be initialised. +In low-level C code, it is sometimes useful to pass around memory that +has been allocated but not yet initialized. CN provides an alternate +form of resource, written `W`, to address this situation. Given a +C-type `T` and pointer `p`, `W(p)` asserts the same ownership as +`RW(p)`: ownership of a memory cell at `p` the size of type `T`. +However, but, in contrast to `RW`, `W` memory is not assumed to be +initialised. CN uses this distinction to prevent reads from uninitialised memory: @@ -24,12 +67,6 @@ CN uses this distinction to prevent reads from uninitialised memory: value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. - - BCP: Not sure I understand "returns a new resource `RW(p)` with - the value written as the output" -- perhaps in part because I don't - understand what the output of a resource means when the resource is - not in the context o a take expression. - Since `RW` carries the same ownership as `W`, just with the additional information that the `RW` memory is initalised, a @@ -42,77 +79,6 @@ already-initialised memory cell to be over-written again. Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. -## Allocation - -At the moment, CN does not understand the `malloc` and `free` -functions. They are a bit tricky because they rely on a bit of -polymorphism and a typecast between `char*` -- the result type of -`malloc` and argument type of `free` -- and the actual type of the -object being allocated or deallocated. - - -BCP: Fix this - -However, for any given type, we can define a type-specific function -that allocates heap storage with exactly that type. The -implementation of this function cannot be checked by CN, but we can -give just the spec, together with a promise to link against an -external C library providing a correct (but not verified!) implementation: - -```c title="exercises/cn_malloc.h" ---8<-- -exercises/cn_malloc.h ---8<-- -``` - -```c title="exercises/cn_malloc_unsigned_int.h" ---8<-- -exercises/cn_malloc_unsigned_int.h ---8<-- -``` - -Now we can write code that allocates and frees memory: - -BCP: It should also malloc some memory! - - -```c title="exercises/slf17_get_and_free.c" ---8<-- -exercises/slf17_get_and_free.c ---8<-- -``` - -We can also define a "safer", ML-style version of `malloc` that -handles both allocation and initialization: - -```c title="exercises/ref.h" ---8<-- -exercises/ref.h ---8<-- -``` - -TODO: BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does... +BCP: An example and/or an exercise would be nice! - -```c title="exercises/slf16_basic_succ_using_incr.c" ---8<-- -exercises/slf16_basic_succ_using_incr.c ---8<-- -``` - -### Exercises - - -BCP: There should be a non-ref-using version of this earlier, for comparison. - - -Prove a specification for the following program that reveals _only_ -that it returns a pointer to a number that is greater than the number -pointed to by its argument. - -```c title="exercises/slf_ref_greater.c" ---8<-- -exercises/slf_ref_greater.c ---8<-- -``` diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index ead98851..061c0082 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -210,3 +210,18 @@ the inputs `x` and `n`. Check that `cn test` succeeds. exercises/id_by_div/id_by_div_n.broken.c --8<-- ``` + +_Exercise: A loose specification for `greater`_: Write a specification for this +function that says that the result is larger than the argument passed +to the function but that does not reveal the precise value of the +result. (I.e., the same specification should work for a function that +adds `1000` instead of `42`.) Be careful of overflow. +```c title="exercises/greater.c" +--8<-- +exercises/greater.c +--8<-- +``` + + + diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index 03de625d..c5300482 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -1,20 +1,22 @@ # Lists - -BCP: Maybe this should be a case study? - - - -BCP: Better intro needed - - Now it's time to look at some more interesting heap structures. -To begin with, here is a C definition for linked list cells, together -with allocation and deallocation functions: +To begin with, here is a C definition for (singly) linked list cells: + +```c title="exercises/list/c_types.h" +--8<-- +exercises/list/c_types.h +--8<-- +``` +Here are typed allocation and deallocation functions for this type. +(We provide separate functions for these rather than just calling +`malloc` and `free` directly in the interest of sharing as much code +as possible with the verification-focused variants of these examples.) -BCP: break sllist out into its own separate .h file and look at it first +BCP: ... but maybe we'd get the same amount of sharing if we directly +used malloc? We should check. ```c title="exercises/list/c_types.test.h" @@ -25,8 +27,10 @@ exercises/list/c_types.test.h To write specifications for C functions that manipulate lists, we need to define a CN "predicate" that describes specification-level list -structures, as one would do in ML, Haskell, or Coq. We use the -datatype `List` for CN-level lists. +structures. We use the datatype `List` for CN-level lists. + + BCP: Industrial developers will need a _lot_ +more help than that! Intuitively, the `SLList_At` predicate walks over a singly-linked pointer structure in the C heap and extracts an `RW` version of @@ -41,10 +45,6 @@ exercises/list/cn_types.h We can also write _functions_ on CN-level lists by ordinary functional programming (in a slightly strange, unholy-union-of-C-and-Rust syntax): - -BCP: Surely we've made that point already? - - ```c title="exercises/list/hdtl.h" --8<-- @@ -71,12 +71,6 @@ exercises/list/headers.test.h --8<-- ``` - -TODO: BCP: The 'return != NULL' should not be needed, but to remove it -we need to change the callers of all the allocation functions to check -for NULL and exit (which requires adding a spec for exit). - - ### Append With this basic infrastructure in place, we can start specifying and @@ -103,10 +97,6 @@ exercises/list/append.test.c Here is an allocating list copy function. - -BCP: `L_` should probably be `L_post` - - ```c title="exercises/list/copy.c" --8<-- exercises/list/copy.c @@ -136,9 +126,9 @@ exercises/list/mergesort.test.c _Allocating append_. Fill in an appropriate specification for `IntList_append2`. -```c title="exercises/list/append2.c" +```c title="exercises/list/append2.test.c" --8<-- -exercises/list/append2.c +exercises/list/append2.test.c --8<-- ``` @@ -164,23 +154,6 @@ exercises/list/free.c _Length with an accumulator_. Add annotations as appropriate: - -BCP: Removing / forgetting the unfold in this one gives a truly - - - bizarre error message saying that the constraint "n == (n + length(L1))" - - - is unsatisfiable... - - - -Sainati: when I went through the tutorial, the file provided for this exercise was already "complete" in that - - - it already had all the necessary annotations present for CN to verify it - - ```c title="exercises/slf_length_acc.c" --8<-- exercises/slf_length_acc.c diff --git a/docs/getting-started/tutorials/morestuff.md b/docs/getting-started/tutorials/morestuff.md index 67390507..3f51928a 100644 --- a/docs/getting-started/tutorials/morestuff.md +++ b/docs/getting-started/tutorials/morestuff.md @@ -1,6 +1,45 @@ -# Additional / Homeless Material +# Additional / Homeless -### Side note +This file collects some material that may or may not be useful long term. + +## A safer allocation idiom + +We can also define a "safer", ML-style version of `malloc` that +handles both allocation and initialization: + +BCP: Are these worth the trouble to present? C programmers will not find them +interesting, I guess. + + +```c title="exercises/ref.h" +--8<-- +exercises/ref.h +--8<-- +``` + + +TODO: BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does... + + +```c title="exercises/slf16_basic_succ_using_incr.c" +--8<-- +exercises/slf16_basic_succ_using_incr.c +--8<-- +``` + +### Exercises + +Write a specification for the following program that reveals _only_ +that it returns a pointer to a number that is greater than the number +pointed to by its argument. + +```c title="exercises/slf_ref_greater.c" +--8<-- +exercises/slf_ref_greater.c +--8<-- +``` + +## Alternate syntax for external functions Here is another syntax for external / unknown functions, together with an example of a loose specification: @@ -10,5 +49,3 @@ functions, together with an example of a loose specification: exercises/slf18_two_dice.c --8<-- ``` - - diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 352de7c9..df8436cc 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,6 +1,7 @@ # Pointers and Simple Ownership - + well, except for some of the resource inference stuff So far we’ve only considered functions manipulating numeric values. Specifications become more interesting when _pointers_ are diff --git a/docs/getting-started/tutorials/predicates.md b/docs/getting-started/tutorials/predicates.md index 81b3394b..c87cff56 100644 --- a/docs/getting-started/tutorials/predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -1,12 +1,7 @@ # Defining Predicates - Maybe we should show how to define predicates earlier -- - e.g., with numeric ranges... - - - -TODO: BCP: The text becomes a bit sketchy from here on! But hopefully there's +BCP: The text becomes a bit sketchy from here on! But hopefully there's still enough structure here to make sense of the examples... @@ -33,26 +28,10 @@ exercises/slf_incr2_alias.c This version does correctly state that the final values of `p` and `q` are,m respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. - -Sainati: I think it would be useful here to add an explanation for how CN's type checking works. - - - For example, in the definition of BothOwned here, how is CN able to prove that `take pv = RW(p);` - - - type checks, since all we know about `p` in the definition of the predicate is that it's a pointer? - - A better way is to define a _predicate_ that captures both the aliased and the non-aliased cases together and use it in the pre- and postconditions: - Sainati: I think it would be useful here to -add an explanation for how CN's type checking works. For example, in -the definition of BothOwned here, how is CN able to prove that `take -pv = RW(p);` type checks, since all we know about `p` -in the definition of the predicate is that it's a pointer? - ```c title="exercises/slf_incr2.test.c" --8<-- exercises/slf_incr2.test.c @@ -64,13 +43,5 @@ BCP: Needs quite a few more words. -BCP: "BothOwned" is a pretty awkward name. - - - -BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types. +BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types. - - - - diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md index f5ac625c..2ffe7471 100644 --- a/docs/getting-started/tutorials/verif-alloc.md +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -1,10 +1,30 @@ -# (Verification) Allocating and Deallocating Memory +# Allocating and Deallocating Memory, Verified -## Verification with malloc and free +## Verifying programs with malloc and free - -BCP: Needs text - +Verifying programs that allocate and deallocate heap memory is a bit +different from testing such programs, in two respects: + +On one hand, there is no need to link against the nonstandard +`cn_malloc` and `cn_free` functions: programs can just use the +standard `malloc` and `free`. + +However, at the moment, CN's verification machinery does not +understand the types of the `malloc` and `free` functions, which are a +bit tricky because they rely on a bit of polymorphism and a typecast +between `char*` -- the result type of `malloc` and argument type of +`free` -- and the actual type of the object being allocated or +deallocated. + +To work around this shortcoming, verifying programs with heap +allocation can follow one of two strategies. + +### First strategy + +The simplest way to allocate and free storage is to define custom +allocation and deallocation functions for each type that might be +stored in the heap. These are defined as `extern`s, with no bodies, +which instructs CN just to trust their specifications. ```c title="exercises/malloc.h" --8<-- @@ -12,20 +32,31 @@ exercises/malloc.h --8<-- ``` -(Alternatively we can include an implementation written in arbitrary C -inside a CN file by marking it with the keyword `trusted` at the top -of its CN specification.) - -Similarly: - ```c title="exercises/free.h" --8<-- exercises/free.h --8<-- ``` -```c title="exercises/slf17_get_and_free.c" +```c title="exercises/slf17_get_and_free.verif.c" +--8<-- +exercises/slf17_get_and_free.verif.c +--8<-- +``` + +### Second strategy + +Alternatively we can include an actual implementation of +`malloc__unsigned_int` and `free__unsigned_int` written in arbitrary C +inside a CN file by marking them with the keyword `trusted` at the top +of their CN specifications. + + +BCP: Make up a real example... + + +```c title="exercises/malloc_trusted.verif.c" --8<-- -exercises/slf17_get_and_free.c +exercises/malloc_trusted.verif.c --8<-- ``` diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index 60db6581..7061eda0 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -1,17 +1,11 @@ -# Lists +# Lists, verified -BCP: Maybe this should be a case study? +BCP: intro needed - -BCP: Better intro needed - - -Now it's time to look at some more interesting heap structures. - -To begin with, here is a C definition for linked list cells, together -with allocation and deallocation functions: +As before, we need slightly different functions for allocating and +deallocating linked list cells: ```c title="exercises/list/c_types.verif.h" --8<-- diff --git a/docs/getting-started/tutorials/numeric.md b/docs/getting-started/tutorials/verif-numeric.md similarity index 100% rename from docs/getting-started/tutorials/numeric.md rename to docs/getting-started/tutorials/verif-numeric.md diff --git a/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c b/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c index 41d3762a..a9a9d5cf 100644 --- a/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c +++ b/src/example-archive/java_program_verification_challenges/broken/error-cerberus/00008_overload_dyn_method.c @@ -36,7 +36,7 @@ processing a method invocation at compile-time ([13, Section //#include /*@ -predicate { u32 pv, u32 qv } BothOwned (pointer p, pointer q) +predicate { u32 pv, u32 qv } TakeBoth (pointer p, pointer q) { if (p == q) { take pv = RW(p); @@ -71,8 +71,8 @@ int ColorPoint_equal(ColorPoint *self, ColorPoint *other) { // Wrapper functions for handling inheritance int Point_equal_wrapper(Point *self, Point *other) - /*@ requires take vs0 = BothOwned(self,other); - ensures take vs1 = BothOwned(self,other); + /*@ requires take vs0 = TakeBoth(self,other); + ensures take vs1 = TakeBoth(self,other); @*/ { // Direct call to the function based on actual type diff --git a/src/exercises/greater.c b/src/exercises/greater.c new file mode 100644 index 00000000..f0a557ac --- /dev/null +++ b/src/exercises/greater.c @@ -0,0 +1,9 @@ +unsigned int greater (unsigned int p) +/* --BEGIN-- */ +/*@ requires p < 10000u32; + ensures return > p; +@*/ +/* --END-- */ +{ + return p+42; +} diff --git a/src/exercises/list/append.test.c b/src/exercises/list/append.test.c index dd28c08e..cdd2990d 100644 --- a/src/exercises/list/append.test.c +++ b/src/exercises/list/append.test.c @@ -3,8 +3,8 @@ struct sllist* IntList_append(struct sllist* xs, struct sllist* ys) /*@ requires take L1 = SLList_At(xs); - take L2 = SLList_At(ys); @*/ -/*@ ensures take L3 = SLList_At(return); + take L2 = SLList_At(ys); + ensures take L3 = SLList_At(return); L3 == Append(L1, L2); @*/ { if (xs == 0) { diff --git a/src/exercises/list/append.verif.c b/src/exercises/list/append.verif.c index 132555b6..8a0f7ec1 100644 --- a/src/exercises/list/append.verif.c +++ b/src/exercises/list/append.verif.c @@ -3,8 +3,8 @@ struct sllist* IntList_append(struct sllist* xs, struct sllist* ys) /*@ requires take L1 = SLList_At(xs); - take L2 = SLList_At(ys); @*/ -/*@ ensures take L3 = SLList_At(return); + take L2 = SLList_At(ys); + ensures take L3 = SLList_At(return); L3 == Append(L1, L2); @*/ { if (xs == 0) { diff --git a/src/exercises/list/append2.c b/src/exercises/list/append2.c index 07d56606..0c04765b 100644 --- a/src/exercises/list/append2.c +++ b/src/exercises/list/append2.c @@ -19,14 +19,14 @@ struct sllist* IntList_copy (struct sllist *xs) struct sllist* IntList_append2 (struct sllist *xs, struct sllist *ys) /* --BEGIN-- */ -/*@ requires take Xs = SLList_At(xs); @*/ -/*@ requires take Ys = SLList_At(ys); @*/ -/*@ ensures take Xs_post = SLList_At(xs); @*/ -/*@ ensures take Ys_post = SLList_At(ys); @*/ -/*@ ensures take Ret = SLList_At(return); @*/ -/*@ ensures Ret == Append(Xs, Ys); @*/ -/*@ ensures Xs == Xs_post; @*/ -/*@ ensures Ys == Ys_post; @*/ +/*@ requires take Xs = SLList_At(xs); + take Ys = SLList_At(ys); + ensures take Xs_post = SLList_At(xs); + take Ys_post = SLList_At(ys); + take Ret = SLList_At(return); + Ret == Append(Xs, Ys); + Xs == Xs_post; + Ys == Ys_post; @*/ /* --END-- */ { if (xs == 0) { diff --git a/src/exercises/list/append2.test.c b/src/exercises/list/append2.test.c new file mode 100644 index 00000000..d66e0e87 --- /dev/null +++ b/src/exercises/list/append2.test.c @@ -0,0 +1,38 @@ +#include "./headers.test.h" +#include "./append.h" + +struct sllist* IntList_copy (struct sllist *xs) +/*@ requires take Xs = SLList_At(xs); + ensures take Xs_post = SLList_At(xs); + take R = SLList_At(return); + Xs == Xs_post; + Xs == R; +@*/ +{ + if (xs == 0) { + return slnil(); + } else { + struct sllist *new_tail = IntList_copy(xs->tail); + return slcons(xs->head, new_tail); + } +} + +struct sllist* IntList_append2 (struct sllist *xs, struct sllist *ys) +/* --BEGIN-- */ +/*@ requires take Xs = SLList_At(xs); + take Ys = SLList_At(ys); + ensures take Xs_post = SLList_At(xs); + take Ys_post = SLList_At(ys); + take Ret = SLList_At(return); + Ret == Append(Xs, Ys); + Xs == Xs_post; + Ys == Ys_post; @*/ +/* --END-- */ +{ + if (xs == 0) { + return IntList_copy(ys); + } else { + struct sllist *new_tail = IntList_append2(xs->tail, ys); + return slcons(xs->head, new_tail); + } +} diff --git a/src/exercises/list/c_types.h b/src/exercises/list/c_types.h new file mode 100644 index 00000000..9493e15e --- /dev/null +++ b/src/exercises/list/c_types.h @@ -0,0 +1,4 @@ +struct sllist { + int head; + struct sllist* tail; +}; diff --git a/src/exercises/list/c_types.test.h b/src/exercises/list/c_types.test.h index 9c35e214..16548d5e 100644 --- a/src/exercises/list/c_types.test.h +++ b/src/exercises/list/c_types.test.h @@ -1,10 +1,5 @@ #include "../cn_malloc.h" -struct sllist { - int head; - struct sllist* tail; -}; - struct sllist *malloc__sllist() /*@ ensures take R = W(return); @*/ { diff --git a/src/exercises/list/c_types.verif.h b/src/exercises/list/c_types.verif.h index daa8b750..49a0e71b 100644 --- a/src/exercises/list/c_types.verif.h +++ b/src/exercises/list/c_types.verif.h @@ -1,8 +1,3 @@ -struct sllist { - int head; - struct sllist* tail; -}; - extern struct sllist *malloc__sllist(); /*@ spec malloc__sllist(); requires true; diff --git a/src/exercises/list/copy.c b/src/exercises/list/copy.c index 96ce023c..28f9567b 100644 --- a/src/exercises/list/copy.c +++ b/src/exercises/list/copy.c @@ -2,9 +2,9 @@ struct sllist* slcopy (struct sllist *l) /*@ requires take L = SLList_At(l); - ensures take L_ = SLList_At(l); + ensures take L_post = SLList_At(l); take Ret = SLList_At(return); - L == L_; + L == L_post; L == Ret; @*/ { diff --git a/src/exercises/list/headers.test.h b/src/exercises/list/headers.test.h index 828baf0d..ec734f6e 100644 --- a/src/exercises/list/headers.test.h +++ b/src/exercises/list/headers.test.h @@ -1,6 +1,7 @@ #ifndef _LIST_H #define _LIST_H +#include "./c_types.h" #include "./c_types.test.h" #include "./cn_types.h" #include "./hdtl.h" diff --git a/src/exercises/list/headers.verif.h b/src/exercises/list/headers.verif.h index 6bc5f478..8049840a 100644 --- a/src/exercises/list/headers.verif.h +++ b/src/exercises/list/headers.verif.h @@ -1,6 +1,7 @@ #ifndef _LIST_H #define _LIST_H +#include "./c_types.h" #include "./c_types.verif.h" #include "./cn_types.h" #include "./hdtl.h" diff --git a/src/exercises/list/mergesort.verif.c b/src/exercises/list/mergesort.verif.c index d7df0d0c..611ca521 100644 --- a/src/exercises/list/mergesort.verif.c +++ b/src/exercises/list/mergesort.verif.c @@ -55,10 +55,10 @@ struct sllist_pair { }; struct sllist_pair split_list(struct sllist *xs) -/*@ requires take Xs = SLList_At(xs); @*/ -/*@ ensures take Ys = SLList_At(return.fst); @*/ -/*@ ensures take Zs = SLList_At(return.snd); @*/ -/*@ ensures {fst: Ys, snd: Zs} == Split_list(Xs); @*/ +/*@ requires take Xs = SLList_At(xs); + ensures take Ys = SLList_At(return.fst); + take Zs = SLList_At(return.snd); + {fst: Ys, snd: Zs} == Split_list(Xs); @*/ { if (xs == 0) { /*@ unfold Split_list(Xs); @*/ @@ -82,10 +82,10 @@ struct sllist_pair split_list(struct sllist *xs) } struct sllist* merge(struct sllist *xs, struct sllist *ys) -/*@ requires take Xs = SLList_At(xs); @*/ -/*@ requires take Ys = SLList_At(ys); @*/ -/*@ ensures take Zs = SLList_At(return); @*/ -/*@ ensures Zs == merge(Xs, Ys); @*/ +/*@ requires take Xs = SLList_At(xs); + take Ys = SLList_At(ys); + ensures take Zs = SLList_At(return); + Zs == merge(Xs, Ys); @*/ { if (xs == 0) { /*@ unfold merge(Xs, Ys); @*/ @@ -111,9 +111,9 @@ struct sllist* merge(struct sllist *xs, struct sllist *ys) } struct sllist* merge_sort(struct sllist *xs) -/*@ requires take Xs = SLList_At(xs); @*/ -/*@ ensures take Ys = SLList_At(return); @*/ -/*@ ensures Ys == merge_sort(Xs); @*/ +/*@ requires take Xs = SLList_At(xs); + ensures take Ys = SLList_At(return); + Ys == merge_sort(Xs); @*/ { if (xs == 0) { /*@ unfold merge_sort(Xs); @*/ diff --git a/src/exercises/list/rev.c b/src/exercises/list/rev.c index ed22410b..844ecf25 100644 --- a/src/exercises/list/rev.c +++ b/src/exercises/list/rev.c @@ -4,10 +4,10 @@ #include "./rev_lemmas.h" struct sllist* rev_aux(struct sllist* l1, struct sllist* l2) -/*@ requires take L1 = SLList_At(l1); @*/ -/*@ requires take L2 = SLList_At(l2); @*/ -/*@ ensures take R = SLList_At(return); @*/ -/*@ ensures R == Append(RevList(L2), L1); @*/ +/*@ requires take L1 = SLList_At(l1); + take L2 = SLList_At(l2); + ensures take R = SLList_At(return); + R == Append(RevList(L2), L1); @*/ { if (l2 == 0) { /*@ unfold RevList(L2); @*/ @@ -23,9 +23,9 @@ struct sllist* rev_aux(struct sllist* l1, struct sllist* l2) } struct sllist* rev(struct sllist* l1) -/*@ requires take L1 = SLList_At(l1); @*/ -/*@ ensures take L1_Rev = SLList_At(return); @*/ -/*@ ensures L1_Rev == RevList(L1); @*/ +/*@ requires take L1 = SLList_At(l1); + ensures take L1_Rev = SLList_At(return); + L1_Rev == RevList(L1); @*/ { /*@ apply Append_Nil_RList(RevList(L1)); @*/ return rev_aux (0, l1); diff --git a/src/exercises/queue/headers.test.h b/src/exercises/queue/headers.test.h index 7a9e27f1..5b65c5c7 100644 --- a/src/exercises/queue/headers.test.h +++ b/src/exercises/queue/headers.test.h @@ -1,3 +1,4 @@ +#include "../list/c_types.h" #include "../list/c_types.test.h" #include "../list/cn_types.h" #include "../list/hdtl.h" diff --git a/src/exercises/queue/headers.verif.h b/src/exercises/queue/headers.verif.h index 18f4041e..b6bc8034 100644 --- a/src/exercises/queue/headers.verif.h +++ b/src/exercises/queue/headers.verif.h @@ -1,3 +1,4 @@ +#include "../list/c_types.h" #include "../list/c_types.verif.h" #include "../list/cn_types.h" #include "../list/hdtl.h" diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c index 5d19a05b..fd9e6e1a 100644 --- a/src/exercises/slf17_get_and_free.test.c +++ b/src/exercises/slf17_get_and_free.test.c @@ -1,7 +1,14 @@ #include "cn_malloc.h" -#include "cn_malloc_unsigned_int.h" -/* ------------- */ +unsigned int *malloc_and_set (unsigned int x) +/*@ ensures take P = RW(return); + P == x; +@*/ +{ + unsigned int *p = cn_malloc(sizeof(unsigned int)); + *p = x; + return p; +} unsigned int get_and_free (unsigned int *p) /*@ requires take P = RW(p); @@ -9,20 +16,10 @@ unsigned int get_and_free (unsigned int *p) @*/ { unsigned int v = *p; - free__unsigned_int (p); + cn_free_sized(p, sizeof(unsigned int)); return v; } -unsigned int *malloc_and_set (unsigned int x) -/*@ ensures take P = RW(return); - P == x; -@*/ -{ - unsigned int *p = malloc__unsigned_int (); - *p = x; - return p; -} - /* BCP: Why doesn't this compile? */ // unsigned int tester() { // /*@ requires true; diff --git a/src/exercises/slf17_get_and_free.c b/src/exercises/slf17_get_and_free.verif.c similarity index 100% rename from src/exercises/slf17_get_and_free.c rename to src/exercises/slf17_get_and_free.verif.c diff --git a/src/exercises/slf_greater.test.c b/src/exercises/slf_greater.test.c new file mode 100644 index 00000000..fa34d72f --- /dev/null +++ b/src/exercises/slf_greater.test.c @@ -0,0 +1,17 @@ +#include "cn_malloc.h" + +unsigned int *greater_abstract (unsigned int *p) +/* --BEGIN-- */ +/*@ requires take P = RW(p); + P < 4294967295u32; + ensures take P_post = RW(p); + take R = RW(return); + P == P_post; + P <= R; +@*/ +/* --END-- */ +{ + unsigned int* q = cn_malloc(sizeof(unsigned int)); + *q = *p + 1; + return q; +} diff --git a/src/exercises/slf_incr2.c b/src/exercises/slf_incr2.c index 6488d4e4..f6995983 100644 --- a/src/exercises/slf_incr2.c +++ b/src/exercises/slf_incr2.c @@ -1,5 +1,5 @@ /*@ -predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) +predicate { u32 P, u32 Q } TakeBoth (pointer p, pointer q) { if (ptr_eq(p,q)) { take PX = RW(p); @@ -14,8 +14,8 @@ predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) @*/ void incr2(unsigned int *p, unsigned int *q) -/*@ requires take PQ = BothOwned(p,q); - ensures take PQ_post = BothOwned(p,q); +/*@ requires take PQ = TakeBoth(p,q); + ensures take PQ_post = TakeBoth(p,q); PQ_post.P == (!ptr_eq(p,q) ? (PQ.P + 1u32) : (PQ.P + 2u32)); PQ_post.Q == (!ptr_eq(p,q) ? (PQ.Q + 1u32) : PQ_post.P); @*/ diff --git a/src/exercises/slf_incr2.test.c b/src/exercises/slf_incr2.test.c index 65b8bf36..cafff376 100644 --- a/src/exercises/slf_incr2.test.c +++ b/src/exercises/slf_incr2.test.c @@ -1,5 +1,5 @@ /*@ -predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) +predicate { u32 P, u32 Q } TakeBoth (pointer p, pointer q) { if (ptr_eq(p,q)) { take PX = RW(p); @@ -14,8 +14,8 @@ predicate { u32 P, u32 Q } BothOwned (pointer p, pointer q) @*/ void incr2(unsigned int *p, unsigned int *q) -/*@ requires take PQ = BothOwned(p,q); - ensures take PQ_post = BothOwned(p,q); +/*@ requires take PQ = TakeBoth(p,q); + ensures take PQ_post = TakeBoth(p,q); PQ_post.P == (!ptr_eq(p,q) ? (PQ.P + 1u32) : (PQ.P + 2u32)); PQ_post.Q == (!ptr_eq(p,q) ? (PQ.Q + 1u32) : PQ_post.P); @*/ diff --git a/src/old/tutorial.md b/src/old/tutorial.md index d76230b9..c0de0f8e 100644 --- a/src/old/tutorial.md +++ b/src/old/tutorial.md @@ -1053,7 +1053,7 @@ exercises/slf_incr2_alias.c This version does correctly state that the final values of `p` and `q` are,m respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. - + A better way is to define a _predicate_ that captures both the aliased @@ -1061,7 +1061,7 @@ and the non-aliased cases together and use it in the pre- and postconditions: - + ```c title="exercises/slf_incr2.c" @@ -1070,7 +1070,7 @@ exercises/slf_incr2.c --8<-- ``` - + @@ -1111,9 +1111,9 @@ exercises/free.h Now we can write code that allocates and frees memory: -```c title="exercises/slf17_get_and_free.c" +```c title="exercises/slf17_get_and_free.verif.c" --8<-- -exercises/slf17_get_and_free.c +exercises/slf17_get_and_free.verif.c --8<-- ``` From a89845b9a221c3954d345acc02a35bc63a86d9b3 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 28 Mar 2025 14:31:01 -0400 Subject: [PATCH 074/158] add comments --- docs/getting-started/tutorials/first-taste.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 061c0082..74c66bb9 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -221,6 +221,17 @@ adds `1000` instead of `42`.) Be careful of overflow. exercises/greater.c --8<-- ``` + +JWS: What is the envisioned solution to this exercise? I don't see how +to write a precondition without a) knowing what value is added +or b) knowing how to specify the max int. + + + +JWS: Can you decide a consistent way to label exercises? There are at least +three styles in this chapter. I prefer _Exercise._ (e.g. no Exercise sections, +no names.) because it's nice and short and I don't feel like the name adds. + From 6c211ec459089f11b027877464c684aa0af457cc Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 28 Mar 2025 16:31:54 -0400 Subject: [PATCH 075/158] more comments --- docs/getting-started/tutorials/arrays.md | 16 +++++++++++-- docs/getting-started/tutorials/compound.md | 15 ++++++------ docs/getting-started/tutorials/pointers.md | 28 ---------------------- 3 files changed, 22 insertions(+), 37 deletions(-) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index ca34e3b7..e73f9958 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -8,6 +8,10 @@ To support reasoning about code manipulating arrays and computed pointers, CN ha each (i32 i; 0i32 <= i && i < 10i32) { RW(array_shift(p,i)) } ``` + +JWS: `i32` or `u32`? `u32` is used in the example below... +And is it `` or ``? It's inconsistent too... + In detail, this can be read as follows: @@ -21,7 +25,8 @@ In detail, this can be read as follows: Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. -In general, iterated resource specifications take the form + + ### First array example @@ -55,7 +60,14 @@ The CN precondition requires - that `i` lies within the range of RW indices. On exit the array ownership is returned again. + +JWS: Is it intentional that there's no post-condition about the return value? + BCP: Do several more examples (e.g., maybe working up to sorting?). + + +JWS: I don't actually know how something like sorting can be specified in CN. Any pointers? + \ No newline at end of file diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index ebfb6b68..29c87bbd 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -3,11 +3,12 @@ Verifying CN programs involving structured objects raises a number of new issues. -## Compound RW and W resources +## Compound RW resources -While one might like to think of a struct as a single (compound) object that is manipulated as a whole, C permits more flexible struct manipulation: given a struct pointer, programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. - -CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `RW` and `W` are defined inductively on the structure of the C-type `T`. +Given a struct pointer, C programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `RW` and `W` are defined inductively on the structure of the C-type `T`. + +JWS: We moved the discussion of W resources to the alloc/malloc chapter, so this stuff is out of sync. + For struct types `T`, the `RW` resource is defined as the collection of `RW` resources for its members (as well as `W` resources for any padding bytes in-between them). The resource `W`, similarly, is made up of `W` resources for all members (and padding bytes). @@ -34,7 +35,7 @@ To handle the required resource inference, CN "`eagerly`" decomposes all `struct We can see this if, for instance, we experimentally change the `transpose` example from above to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of the `transpose` function, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) -BCP: Recheck that what we say here matches what it actually looks like +BCP: Recheck that what we say here matches what it actually looks like ```c title="exercises/transpose.broken.c" @@ -73,9 +74,9 @@ exercises/transpose2.c ``` -BCP: Some more things to think about including... +BCP: Some more things to think about including... - Something about CN's version of the frame rule (see -bcp_framerule.c, though the example is arguably a bit unnatural). +bcp_framerule.c, though the example is arguably a bit unnatural). - Examples from Basic.v with allocation - there are lots of interesting ones! CP: Agreed. For now continuing with arrays, but will return to this later. diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index df8436cc..379293ba 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,33 +1,5 @@ # Pointers and Simple Ownership - -BCP: Check that we've done everything in the outline - Rough notes / updated outline: - - - read.c - - unannotated version fails tests - - need to explain how to figure out WHY testing fails! - - explain ownership (copy/move from verification tutorial) - - version with proper spec works better! - - read.broken.c demonstrates linearity of resource usage - - exercises: - - quadruple_mem - - abs_mem (this doesn't work with unsigned ints, but we can - use the other examples from the previous section) - - slf0_basic_incr_signed.c - shows the difference between W and RW - - exercises - - zero.c - - basic_inplace_double.c involves UB, so skip it or (maybe - better) replace with something that doesn't - - maybe something about swapping pointers? - - - add_read (but changing it to swapping or something, to avoid UB - issues) - - - everything up through pointers to compound objects seems to work - well, except for some of the resource inference stuff - So far we’ve only considered functions manipulating numeric values. Specifications become more interesting when _pointers_ are involved, because the safety of memory accesses via pointers has to be From f9904c5cfb9ed32fd67fd13c74b681b5967d1b1e Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 28 Mar 2025 16:45:18 -0400 Subject: [PATCH 076/158] add comment --- docs/getting-started/tutorials/verif-arrays.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index a1c379cd..c54e4123 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -120,7 +120,7 @@ TODO: BCP: I wrote the following, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfecdt understanding of how -the numeric stuff works. +the numeric stuff works. void swap_array (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; @@ -150,9 +150,14 @@ In order to verify code with loops, CN requires the user to supply loop invarian Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. -BCP: Rename to array_init.c +BCP: Rename to array_init.c + +JWS: Should this change be propagated everywhere e.g. also changing the function name, changing other function names starting with `init_`, changing `swap_array` to `array_swap`, etc.? + + + ```c title="exercises/init_array.c" --8<-- exercises/init_array.c @@ -232,10 +237,10 @@ As before, we also have to instruct CN to `focus` ownership of individual array - finally, we add `focus RW, j;` to allow CN to "`attach`" this resource to the iterated `RW` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `focus` only for the "`reverse`" direction. -BCP: That last bit is mysterious. +BCP: That last bit is mysterious. -Dhruv: See long explanation and issue here: rems-project/cerberus#498 +Dhruv: See long explanation and issue here: rems-project/cerberus#498 ### Exercises From 5967120aa752fb3b8dc5f64073ca1ad4fc8e1ee8 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 28 Mar 2025 20:23:37 -0400 Subject: [PATCH 077/158] Trivial --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index fd1cd130..c3e219a3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ View the tutorial here: https://rems-project.github.io/cn-tutorial/ - ## Acknowledgment of Support and Disclaimer This material is based upon work supported by the Air Force Research Laboratory From c4bf207fe33559cb72d45271ba418cadf0889f18 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 28 Mar 2025 20:28:33 -0400 Subject: [PATCH 078/158] Renaming --- src/exercises/free.h | 8 ++++---- src/exercises/malloc.h | 8 ++++---- src/exercises/malloc_alt.h | 8 ++++---- src/exercises/slf16_basic_succ_using_incr.c | 2 +- src/exercises/slf17_get_and_free.verif.c | 2 +- src/exercises/slf_length_acc.c | 2 +- src/exercises/slf_ref_greater.c | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/exercises/free.h b/src/exercises/free.h index 9da5813c..9fca1c68 100644 --- a/src/exercises/free.h +++ b/src/exercises/free.h @@ -1,12 +1,12 @@ -extern void freeInt (int *p); -/*@ spec freeInt(pointer p); +extern void free__int (int *p); +/*@ spec free__int(pointer p); requires take P = W(p); ensures true; @*/ -extern void freeUnsignedInt (unsigned int *p); -/*@ spec freeUnsignedInt(pointer p); +extern void free__unsigned_int (unsigned int *p); +/*@ spec free__unsigned_int(pointer p); requires take P = W(p); ensures true; @*/ diff --git a/src/exercises/malloc.h b/src/exercises/malloc.h index d0439c88..389d1016 100644 --- a/src/exercises/malloc.h +++ b/src/exercises/malloc.h @@ -1,11 +1,11 @@ -extern int *mallocInt (); -/*@ spec mallocInt(); +extern int *malloc__int (); +/*@ spec malloc__int(); requires true; ensures take R = W(return); @*/ -extern unsigned int *mallocUnsignedInt (); -/*@ spec mallocUnsignedInt(); +extern unsigned int *malloc__unsigned_int (); +/*@ spec malloc__unsigned_int(); requires true; ensures take R = W(return); @*/ diff --git a/src/exercises/malloc_alt.h b/src/exercises/malloc_alt.h index e1068995..cf0cf8e0 100644 --- a/src/exercises/malloc_alt.h +++ b/src/exercises/malloc_alt.h @@ -1,12 +1,12 @@ -extern int *mallocInt (); -/*@ spec mallocInt() +extern int *malloc__int (); +/*@ spec malloc__int() requires true ensures take v = W(return) @*/ -extern unsigned int *mallocUnsignedInt (); -/*@ spec mallocUnsignedInt() +extern unsigned int *malloc__unsigned_int (); +/*@ spec malloc__unsigned_int() requires true ensures take v = W(return) @*/ diff --git a/src/exercises/slf16_basic_succ_using_incr.c b/src/exercises/slf16_basic_succ_using_incr.c index e9e595ce..cd0ac9a2 100644 --- a/src/exercises/slf16_basic_succ_using_incr.c +++ b/src/exercises/slf16_basic_succ_using_incr.c @@ -8,6 +8,6 @@ unsigned int succ_using_incr (unsigned int n) unsigned int *p = refUnsignedInt(n); incr(p); unsigned int x = *p; - freeUnsignedInt(p); + free__unsigned_int(p); return x; } diff --git a/src/exercises/slf17_get_and_free.verif.c b/src/exercises/slf17_get_and_free.verif.c index a194f69b..64589474 100644 --- a/src/exercises/slf17_get_and_free.verif.c +++ b/src/exercises/slf17_get_and_free.verif.c @@ -6,6 +6,6 @@ unsigned int get_and_free (unsigned int *p) @*/ { unsigned int v = *p; - freeUnsignedInt (p); + free__unsigned_int (p); return v; } diff --git a/src/exercises/slf_length_acc.c b/src/exercises/slf_length_acc.c index d229f24e..e019a773 100644 --- a/src/exercises/slf_length_acc.c +++ b/src/exercises/slf_length_acc.c @@ -42,6 +42,6 @@ unsigned int IntList_length_acc (struct sllist *xs) unsigned int *p = refUnsignedInt(0); IntList_length_acc_aux(xs, p); unsigned int x = *p; - freeUnsignedInt(p); + free__unsigned_int(p); return x; } diff --git a/src/exercises/slf_ref_greater.c b/src/exercises/slf_ref_greater.c index ca2a16fe..87fd53c6 100644 --- a/src/exercises/slf_ref_greater.c +++ b/src/exercises/slf_ref_greater.c @@ -11,7 +11,7 @@ unsigned int *ref_greater_abstract (unsigned int *p) @*/ /* --END-- */ { - unsigned int* q = mallocUnsignedInt(); + unsigned int* q = malloc__unsigned_int(); *q = *p + 1; return q; } From a296c3d644c8352a6b7579a3d8613f0f668cc17d Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 31 Mar 2025 12:34:09 -0400 Subject: [PATCH 079/158] Responses to Jessica --- docs/getting-started/tutorials/arrays.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index e73f9958..bc7f92a6 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -12,6 +12,10 @@ each (i32 i; 0i32 <= i && i < 10i32) JWS: `i32` or `u32`? `u32` is used in the example below... And is it `` or ``? It's inconsistent too... + +BCP: We should just use `u32` and `` until we get to the +chapter about other numeric types. + In detail, this can be read as follows: @@ -63,11 +67,15 @@ On exit the array ownership is returned again. JWS: Is it intentional that there's no post-condition about the return value? + +BCP: Nope! + BCP: Do several more examples (e.g., maybe working up to sorting?). - JWS: I don't actually know how something like sorting can be specified in CN. Any pointers? - \ No newline at end of file + + BCP: Good question. Let's ask on Mattermost. + From 34cf9a1ed0adc1b89af66ed3f38e8d9226758391 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 31 Mar 2025 12:47:33 -0400 Subject: [PATCH 080/158] Minor reformat --- docs/getting-started/tutorials/README.md | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index e653156e..ed4f779b 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,38 +4,38 @@ ## A Tour of CN - [A first taste of CN: Specification and testing](first-taste.md) -- [      (Verification) - A first taste of verification](verif-basics.md) +- [(V) + A first taste of verification](verif-basics.md) - [Working with pointers](pointers.md) -- [      (Verification) +- [(V) Pointers to structured objects, verified](compound.md) - [Arrays and loops](arrays.md) -- [      (Verification) +- [(V) Arrays and loops, verified](verif-arrays.md) - [Allocating and deallocating memory](alloc.md) --       (Verification) +- (V) [Allocating and deallocating memory, verified](verif-alloc.md) - [Defining predicates](predicates.md) - [Lists](lists.md) -- [      (Verification) +- [(V) Lists, verified](verif-lists.md) -- [      (Verification) +- [(V) Case analysis](verif-splitcase.md) -- [      (Verification) - Working with external lemmas](verif-external.md) -- [      (Verification) +- (V) [More on numeric types](verif-numeric.md) +- [(V) + Working with external lemmas](verif-external.md) ## Case studies - [Imperative queues](../case-studies/imperative-queues.md) -- [      (Verification) +- [(V) Imperative queues, verified](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) -- [      (Verification) +- [(V) Doubly-linked lists, verified](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) -- [      (Verification) +- [(V) Airport simulation, verified](../case-studies/verif-the-runway.md) ## TODOs From 9a61a6c10af3b7296ffab9b7f3dfb7fb7dac7a92 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 31 Mar 2025 14:17:09 -0400 Subject: [PATCH 081/158] save wip on compound.md --- docs/getting-started/tutorials/compound.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index 29c87bbd..971bc6c1 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -5,18 +5,12 @@ of new issues. ## Compound RW resources -Given a struct pointer, C programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `RW` and `W` are defined inductively on the structure of the C-type `T`. - -JWS: We moved the discussion of W resources to the alloc/malloc chapter, so this stuff is out of sync. - - -For struct types `T`, the `RW` resource is defined as the collection of `RW` resources for its members (as well as `W` resources for any padding bytes in-between them). The resource `W`, similarly, is made up of `W` resources for all members (and padding bytes). - -To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. +Given a struct pointer, C programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. CN therefore cannot treat resources for compound C types like structs as indivisible units. -Recall the function `zero` from our earlier exercise. It takes an `unsigned int` pointer to uninitialised memory, with `W` ownership, and initialises the value to zero, returning an `RW` resource with output `0`. +Instead, `RW` is defined inductively on the structure of the C-type `T`. +To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the resources of its members, and it can recompose the struct later, as needed. The following example illustrates this. -Now consider the function `init_point`, shown below, which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. +Suppose we have a function `zero` that initializes a pointer to 0. Now consider the function `init_point` which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. ```c title="exercises/init_point.c" --8<-- @@ -24,15 +18,15 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `W(p)`. The `zero` function, however, works on `unsigned int` pointers and requires `W` ownership. +As stated in its precondition, `init_point` receives ownership `RW(p)`. The `zero` function, however, works on `unsigned int` pointers and requires `RW` ownership. -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `W(p)` into a `W` for member `x` and a `W` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `RW` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `RW(p)`, CN combines these back into a compound resource. The resulting `RW` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. +CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `RW(p)` into a `RW` for member `x` and likewise for member `y`. Later, the reverse happens. Since the postcondition of `init_point` requires ownership `RW(p)`, CN combines these back into a compound resource. The resulting pointee value `P_post` is a struct composed of the zeroed member values for `x` and `y`. ## Resource inference To handle the required resource inference, CN "`eagerly`" decomposes all `struct` resources into resources for the struct members, and "`lazily`" re-composes them as needed. -We can see this if, for instance, we experimentally change the `transpose` example from above to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of the `transpose` function, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) +We can see this if we experimentally change the previous `transpose` example to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of `transpose`, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) BCP: Recheck that what we say here matches what it actually looks like From 31b4219e1f10c0b2d2fbdd3068f6ed4e09c9bb18 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 31 Mar 2025 14:24:59 -0400 Subject: [PATCH 082/158] more edits to compound --- docs/getting-started/tutorials/compound.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index 971bc6c1..a6f0922c 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -32,6 +32,17 @@ We can see this if we experimentally change the previous `transpose` example to BCP: Recheck that what we say here matches what it actually looks like + +JWS: It appears quite different now. Seems like we can now step through the function (so is the assert still necessary?) +and the "Available resources" at the assert line are +RW(&temp_y)(P.y) +RW(&temp_x)(P.x) +RW(&ARG0)(p) +RW(&p->y)(P.y) +RW(&p->x)(P.x) +...I would just edit the text but I'm not sure how this output aligns with the one described below + + ```c title="exercises/transpose.broken.c" --8<-- exercises/transpose.broken.c @@ -57,9 +68,11 @@ When the function returns, the two member resources are recombined "`on demand`" _Init point._ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. -_Transpose (again)._ Recreate the `transpose` function from before, -using the `swap` function verified earlier. - +_Transpose (again)._ Recreate the `transpose` function from before, now +using the `swap` function. + +JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work? + ```c title="exercises/transpose2.c" --8<-- From 670453c04bf28f545d59499a175e5ed79a798b54 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 31 Mar 2025 16:05:19 -0400 Subject: [PATCH 083/158] Misc fixes --- Makefile | 2 +- README.md | 1 + docs/README.md | 5 ++-- docs/getting-started/tutorials/README.md | 2 +- docs/getting-started/tutorials/arrays.md | 2 +- docs/getting-started/tutorials/first-taste.md | 25 +++++-------------- .../getting-started/tutorials/verif-basics.md | 3 --- .../{compound.md => verif-pointers.md} | 0 src/exercises/between.c | 11 ++++++++ src/exercises/greater.c | 9 ------- 10 files changed, 24 insertions(+), 36 deletions(-) rename docs/getting-started/tutorials/{compound.md => verif-pointers.md} (100%) create mode 100644 src/exercises/between.c delete mode 100644 src/exercises/greater.c diff --git a/Makefile b/Makefile index dfbd459b..461d3fb8 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/slf_incr2_noalias.c \ _temp/tested/slf10_basic_ref.c \ _temp/tested/add_2.c \ - _temp/tested/greater.c \ + _temp/tested/between.c \ _temp/tested/add_two_array.c \ _temp/tested/transpose.c \ _temp/tested/read2.c \ diff --git a/README.md b/README.md index c3e219a3..b4906849 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Dependencies: ```bash # Install Material for MkDocs pip install mkdocs-material +pip install mkdocs-macros-plugin # Build the tutorial make diff --git a/docs/README.md b/docs/README.md index 1f2b3635..a230c30f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -57,8 +57,9 @@ extended exercise due to Bryan Parno. ??? info "BibTeX citation" ``` @misc{cn-tutorial, - author = {Christopher Pulte and Benjamin C. Pierce and Cole Schlesinger and Elizabeth Austell}, - title = {{CN Tutorial}}, + author = "Christopher Pulte and Benjamin C. Pierce and Cole + Schlesinger and Jessica Shi and Elizabeth Austell", + title = "{CN Tutorial}", howpublished = "\url{https://rems-project.github.io/cn-tutorial/}", year = {2025}, } diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index ed4f779b..ebdfdb31 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -8,7 +8,7 @@ A first taste of verification](verif-basics.md) - [Working with pointers](pointers.md) - [(V) - Pointers to structured objects, verified](compound.md) + Pointers to structured objects, verified](verif-pointers.md) - [Arrays and loops](arrays.md) - [(V) Arrays and loops, verified](verif-arrays.md) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index bc7f92a6..a98c3cea 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -75,7 +75,7 @@ BCP: Nope! examples (e.g., maybe working up to sorting?). -JWS: I don't actually know how something like sorting can be specified in CN. Any pointers? +JWS: I don't actually know how something like sorting can be specified in CN. Any pointers? BCP: Good question. Let's ask on Mattermost. diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 74c66bb9..1066100d 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -211,28 +211,15 @@ exercises/id_by_div/id_by_div_n.broken.c --8<-- ``` -_Exercise: A loose specification for `greater`_: Write a specification for this -function that says that the result is larger than the argument passed -to the function but that does not reveal the precise value of the +_Exercise: Write a specification for this +function that says that the result is between the first argument and +the second, but that does not reveal the precise value of the result. (I.e., the same specification should work for a function that -adds `1000` instead of `42`.) Be careful of overflow. -```c title="exercises/greater.c" +returns `p` or `(p+q)/2` instead of `q`.) +```c title="exercises/between.c" --8<-- -exercises/greater.c +exercises/between.c --8<-- ``` - -JWS: What is the envisioned solution to this exercise? I don't see how -to write a precondition without a) knowing what value is added -or b) knowing how to specify the max int. - - -JWS: Can you decide a consistent way to label exercises? There are at least -three styles in this chapter. I prefer _Exercise._ (e.g. no Exercise sections, -no names.) because it's nice and short and I don't feel like the name adds. - - - diff --git a/docs/getting-started/tutorials/verif-basics.md b/docs/getting-started/tutorials/verif-basics.md index ec8255c4..0bb06088 100644 --- a/docs/getting-started/tutorials/verif-basics.md +++ b/docs/getting-started/tutorials/verif-basics.md @@ -29,6 +29,3 @@ the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. - -TODO: What else do we need to talk about in this introductory section? - diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/verif-pointers.md similarity index 100% rename from docs/getting-started/tutorials/compound.md rename to docs/getting-started/tutorials/verif-pointers.md diff --git a/src/exercises/between.c b/src/exercises/between.c new file mode 100644 index 00000000..bb3e5a4d --- /dev/null +++ b/src/exercises/between.c @@ -0,0 +1,11 @@ +unsigned int between (unsigned int p, unsigned int q) +/* --BEGIN-- */ + /*@ + requires p <= q; + ensures return >= p; + return <= q; + @*/ +/* --END-- */ +{ + return q; +} diff --git a/src/exercises/greater.c b/src/exercises/greater.c deleted file mode 100644 index f0a557ac..00000000 --- a/src/exercises/greater.c +++ /dev/null @@ -1,9 +0,0 @@ -unsigned int greater (unsigned int p) -/* --BEGIN-- */ -/*@ requires p < 10000u32; - ensures return > p; -@*/ -/* --END-- */ -{ - return p+42; -} From 501a5257e9ebf8f6105364d25ad3cfb800948c68 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 31 Mar 2025 16:08:29 -0400 Subject: [PATCH 084/158] save changes to arrays and compound --- docs/getting-started/tutorials/arrays.md | 20 +++----------------- src/exercises/array_load.test.c | 11 ++++++----- src/exercises/init_point.c | 4 ++-- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index bc7f92a6..1ab4d715 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -5,21 +5,13 @@ Another common datatype in C is arrays. Reasoning about memory ownership for arr To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `unsigned` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: ```c -each (i32 i; 0i32 <= i && i < 10i32) +each (u32 i; i < 10i32) { RW(array_shift(p,i)) } ``` - -JWS: `i32` or `u32`? `u32` is used in the example below... -And is it `` or ``? It's inconsistent too... - - -BCP: We should just use `u32` and `` until we get to the -chapter about other numeric types. - In detail, this can be read as follows: -- for each integer `i` of CN type `i32`, … +- for each index `i` of CN type `u32`, … - if `i` is between `0` and `10`, … @@ -63,13 +55,7 @@ The CN precondition requires - ownership of the array on entry — one `RW` resource for each array index between `0` and `n` — and - that `i` lies within the range of RW indices. -On exit the array ownership is returned again. - -JWS: Is it intentional that there's no post-condition about the return value? - - -BCP: Nope! - +On exit the array ownership is returned again. The postcondition also asserts that the return value of the function is indeed equal to the value of the array at index `i`. BCP: Do several more examples (e.g., maybe working up to sorting?). diff --git a/src/exercises/array_load.test.c b/src/exercises/array_load.test.c index f3c145b2..a82d4e8a 100644 --- a/src/exercises/array_load.test.c +++ b/src/exercises/array_load.test.c @@ -1,9 +1,10 @@ -int read (unsigned int *p, unsigned int n, unsigned int i) -/*@ requires take A = each(u32 j; 0u32 <= j && j < n) { - RW(array_shift(p,j)) }; +unsigned int read (unsigned int *p, unsigned int n, unsigned int i) +/*@ requires take A = each(u32 j; j < n) + { RW(array_shift(p,j)) }; i < n; - ensures take A_post = each(u32 j; 0u32 <= j && j < n) { - RW(array_shift(p,j)) }; + ensures take A_post = each(u32 j; j < n) + { RW(array_shift(p,j)) }; + return == A[i]; @*/ { return p[i]; diff --git a/src/exercises/init_point.c b/src/exercises/init_point.c index 659ec522..640e0b77 100644 --- a/src/exercises/init_point.c +++ b/src/exercises/init_point.c @@ -1,5 +1,5 @@ void zero (unsigned int *coord) -/*@ requires take Coord = W(coord); +/*@ requires take Coord = RW(coord); ensures take Coord_post = RW(coord); Coord_post == 0u32; @*/ { @@ -9,7 +9,7 @@ void zero (unsigned int *coord) struct point { unsigned int x; unsigned int y; }; void init_point(struct point *p) -/*@ requires take P = W(p); +/*@ requires take P = RW(p); ensures take P_post = RW(p); P_post.x == 0u32; P_post.y == 0u32; From 82f1ec7479e42ca3c9279b053af3e5d871ed9b25 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 31 Mar 2025 16:10:13 -0400 Subject: [PATCH 085/158] Add mkdocs macros support --- main.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 main.py diff --git a/main.py b/main.py new file mode 100644 index 00000000..d7623b0d --- /dev/null +++ b/main.py @@ -0,0 +1,20 @@ +def define_env(env): + """ + This is the hook for the variables, macros and filters. + """ + + def common(mesg, color): + "Format a TODO (common)" + return "[[" + mesg + "]]" + + @env.macro + def todo(mesg): + "Format a TODO" + return common(mesg, "blue") + + @env.macro + def later(mesg): + "Format a TODO for later" + return common(mesg, "lightgray") + + From 4987416208a7344fd1200e864be1bf9e0de98fb1 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 31 Mar 2025 16:11:37 -0400 Subject: [PATCH 086/158] standardize exercise formatting in first few chapters --- docs/getting-started/tutorials/compound.md | 4 ++-- docs/getting-started/tutorials/first-taste.md | 14 ++++---------- docs/getting-started/tutorials/pointers.md | 16 ++++++++++++---- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/getting-started/tutorials/compound.md b/docs/getting-started/tutorials/compound.md index a6f0922c..8fe6890f 100644 --- a/docs/getting-started/tutorials/compound.md +++ b/docs/getting-started/tutorials/compound.md @@ -66,9 +66,9 @@ When the function returns, the two member resources are recombined "`on demand`" ### Exercises -_Init point._ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. +_Exercise:_ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. -_Transpose (again)._ Recreate the `transpose` function from before, now +_Exercise:_ Recreate the `transpose` function from before, now using the `swap` function. JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work? diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 74c66bb9..2d62fa9f 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -140,13 +140,13 @@ Hooray! ### Exercises -_Refining the specification of `min3`_: The specification we wrote is +_Exercise:_ The specification we wrote is a bit loose: It says the result value should be smaller than `x`, `y`, and `z`, but it does not say that it must be equal to one of these. For example, a function that always returns `0` would satisfy this spec specification. Improve it. -_Exercise._ Practice the workflow of specifying and testing the function `add`. +_Exercise:_ Practice the workflow of specifying and testing the function `add`. - Write a specification with the postcondition that `add` should return the sum of its inputs. Remember that CN supports standard @@ -201,7 +201,7 @@ the error message that results. ### Exercises -_Exercise._ Without changing the postcondition or implementation, fix +_Exercise:_ Without changing the postcondition or implementation, fix the specification in the following example by adding a precondition on the inputs `x` and `n`. Check that `cn test` succeeds. @@ -211,7 +211,7 @@ exercises/id_by_div/id_by_div_n.broken.c --8<-- ``` -_Exercise: A loose specification for `greater`_: Write a specification for this +_Exercise:_ Write a specification for this function that says that the result is larger than the argument passed to the function but that does not reveal the precise value of the result. (I.e., the same specification should work for a function that @@ -227,12 +227,6 @@ to write a precondition without a) knowing what value is added or b) knowing how to specify the max int. - -JWS: Can you decide a consistent way to label exercises? There are at least -three styles in this chapter. I prefer _Exercise._ (e.g. no Exercise sections, -no names.) because it's nice and short and I don't feel like the name adds. - - diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 379293ba..f7303dac 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -133,7 +133,9 @@ exercises/read2.c CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. -_Exercise._ Write a specification for `double_it`, which takes a pointer `p` and +### Exercises + +_Exercise:_ Write a specification for `double_it`, which takes a pointer `p` and returns double the pointee value. Running `cn test` on this correct implementation should succeed, ```c title="exercises/double_it.c" @@ -176,7 +178,9 @@ The precondition binds the initial pointee value to `P`. The postcondition binds the value _after_ function execution to `P_post`, and uses this to express that the value `p` points to is incremented by `incr`: `P_post == P + 1i32`. -_Exercise._ Write a specification for `inplace_double`, which takes a pointer +### Exercises + +_Exercise:_ Write a specification for `inplace_double`, which takes a pointer `p` and doubles the pointee value. Make sure your postcondition captures the function's intended behavior. @@ -256,7 +260,9 @@ only true when `p` and `q` are disjoint; otherwise, the write to `q` would override the write to `p`. In CN, we can make this assumption for free — no extra work is needed to assert that the pointers are disjoint. -_Exercise._ Write a specification for the function `transfer`, shown below. +### Exercises + +_Exercise:_ Write a specification for the function `transfer`, shown below. ```c title="exercises/slf8_basic_transfer.c" --8<-- @@ -293,5 +299,7 @@ how one may need to destructure the type (unions, struct fields and padding, arrays). The relationship is that for `take x = RW(expr)` we have `expr : pointer, x : to_basetype(ct)`. --> -_Exercise._ TODO: it would be nice to add an +### Exercises + +_Exercise:_ TODO: it would be nice to add an exercise that involves using the error messages to find a bug... From dbcd92f0ef993ffe4eed805f6ac8fe775ad07223 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 31 Mar 2025 16:18:05 -0400 Subject: [PATCH 087/158] Small fixes --- docs/getting-started/tutorials/pointers.md | 23 ++++++++----------- .../getting-started/tutorials/verif-basics.md | 2 ++ main.py | 2 +- mkdocs.yml | 5 +++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 379293ba..81c3a18f 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -214,19 +214,16 @@ void* p0 = malloc(4); unsigned int* p = (unsigned int*)(p0); read(p); ``` - -BCP: Explain what that means. - - - - -Given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the RW memory or otherwise dispose of it. In CN this is a type error. +The error from `cn test` report +tells us (1) in which function the error occurred, (2) what happened +("ownership leaked"), and (3) a failing input -- i.e., a snipped of C +code that will construct a heap state on which the test fails in this +way. +What went wrong here is that, given the above specification, `read` +leaks memory: it takes ownership, does not return it, but also does +not deallocate the RW memory or otherwise dispose of it. CN requires that every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the RW area of memory (as we shall see later). CN’s motivation for this choice is its focus on @@ -293,5 +290,5 @@ how one may need to destructure the type (unions, struct fields and padding, arrays). The relationship is that for `take x = RW(expr)` we have `expr : pointer, x : to_basetype(ct)`. --> -_Exercise._ TODO: it would be nice to add an -exercise that involves using the error messages to find a bug... +{{ todo("TODO: It would be nice to add an exercise that involves +using the error messages to find a bug.") }} diff --git a/docs/getting-started/tutorials/verif-basics.md b/docs/getting-started/tutorials/verif-basics.md index 0bb06088..b6dd5c74 100644 --- a/docs/getting-started/tutorials/verif-basics.md +++ b/docs/getting-started/tutorials/verif-basics.md @@ -29,3 +29,5 @@ the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. +{{ later("TODO: What else do we need to talk about in this introductory +section??") }} diff --git a/main.py b/main.py index d7623b0d..2484615b 100644 --- a/main.py +++ b/main.py @@ -10,7 +10,7 @@ def common(mesg, color): @env.macro def todo(mesg): "Format a TODO" - return common(mesg, "blue") + return common(mesg, "red") @env.macro def later(mesg): diff --git a/mkdocs.yml b/mkdocs.yml index 573c9536..7225d6f5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -48,7 +48,10 @@ theme: text: Roboto code: Roboto Mono - +plugins: + - search + - macros + # Extensions markdown_extensions: - abbr From cdbac60d12371cba92c31e31484f0b1a9a1e147c Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Mon, 31 Mar 2025 16:43:06 -0400 Subject: [PATCH 088/158] More polishing here and there --- Makefile | 4 +- .../getting-started/tutorials/verif-arrays.md | 61 ++++++++----------- .../tutorials/verif-numeric.md | 5 ++ .../tutorials/verif-pointers.md | 16 +++-- src/exercises/array_load.broken.c | 10 +++ .../{add_two_array.c => array_read_two.c} | 0 src/exercises/{swap_array.c => array_swap.c} | 2 +- 7 files changed, 54 insertions(+), 44 deletions(-) create mode 100644 src/exercises/array_load.broken.c rename src/exercises/{add_two_array.c => array_read_two.c} (100%) rename src/exercises/{swap_array.c => array_swap.c} (91%) diff --git a/Makefile b/Makefile index 461d3fb8..1c8910d8 100644 --- a/Makefile +++ b/Makefile @@ -53,14 +53,14 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/slf10_basic_ref.c \ _temp/tested/add_2.c \ _temp/tested/between.c \ - _temp/tested/add_two_array.c \ + _temp/tested/array_read_two.c \ _temp/tested/transpose.c \ _temp/tested/read2.c \ _temp/tested/read.c \ _temp/tested/slf1_basic_example_let.c \ _temp/tested/slf_incr2_alias.c \ _temp/tested/abs_mem.c \ - _temp/tested/swap_array.c \ + _temp/tested/array_swap.c \ _temp/tested/const_example.c \ _temp/tested/add.partial.c \ _temp/tested/init_point.c \ diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index c54e4123..0e3f2119 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -21,13 +21,16 @@ return p[i]; Resource needed: RW(array_shift(p, (u64)i)) ``` -The reason is that, when searching for a required resource, such as the `RW` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. +The reason is that, when searching for a required resource, such as +the `RW` resource for `p[i]` here, CN’s resource inference does not +consider iterated resources. Quantifiers, as used by iterated +resources, can make verification undecidable, so, in order to maintain +predictable type checking, CN delegates this aspect of the reasoning +to the user. - -BCP: This is more verification-relevant - - -To make the `RW` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`focus`" ownership for index `i` out of the iterated resource. +To make the `RW` resource required for accessing `p[i]` available to +CN’s resource inference, we have to explicitly "`focus`" ownership for +index `i` out of the iterated resource. ```c title="exercises/array_load.c" --8<-- @@ -35,7 +38,7 @@ exercises/array_load.c --8<-- ``` -Here the CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits the iterated resource into two: +The CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits the iterated resource into two: ```c each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) } @@ -85,44 +88,30 @@ the same — and that the value returned is `A[i]`. ### Exercises -_Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. +_Exercise:_ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. - -BCP: When we get around to renaming files in the examples directory, -we should call this one array_swap or something else beginning with -"array". Or put it in a subdirectory. - - -```c title="exercises/add_two_array.c" +```c title="exercises/array_read_two.c" --8<-- -exercises/add_two_array.c +exercises/array_read_two.c --8<-- ``` - -BCP: In this one I got quite tangled up in different kinds of integers, then got tangled up in (I think) putting the focus declarations in the wrong place. (I didn't save the not-working version, I'm afraid.) - - - -Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints - - -_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. +_Exercise:_ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. -```c title="exercises/swap_array.c" +```c title="exercises/array_swap.c" --8<-- -exercises/swap_array.c +exercises/array_swap.c --8<-- ``` -TODO: BCP: I wrote the following, which seemed natural but did not +BCP: I wrote the following, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps -this is just yet another symptom of my imperfecdt understanding of how +this is just yet another symptom of my imperfect understanding of how the numeric stuff works. - void swap_array (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) + void array_swap (unsigned int *p, unsigned int n, unsigned int i, unsigned int j) /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; 0i32 <= i && i < n; 0i32 <= j && j < n; @@ -157,6 +146,9 @@ BCP: Rename to array_init.c JWS: Should this change be propagated everywhere e.g. also changing the function name, changing other function names starting with `init_`, changing `swap_array` to `array_swap`, etc.? + +BCP: Yes! I've done a bit of it, but there's more. + ```c title="exercises/init_array.c" --8<-- @@ -174,9 +166,8 @@ solutions/init_array.c --8<-- ``` - -TODO: BCP: Concrete syntax: Why not write something like "unchanged {p,n}" or "unchanged: p,n"? - +{{ later("Concrete syntax: Why not write something like \"unchanged +{p,n}\" or \"unchanged: p,n\"?") }} The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. @@ -184,9 +175,7 @@ The second thing we need to do, however, is less straightforward. Recall that, a **Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. - -TODO: BCP: This seems like a good idea! - +{{ later("BCP: This seems like a good idea!") }} The final piece needed in the verification is an `focus` statement, as used in the previous examples: to separate the individual `RW` resource for index `j` out of the iterated `RW` resource and make it available to the resource inference, we specify `focus RW, j;`. diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 2feb7844..870683b6 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -307,3 +307,8 @@ Note that most binary operators in CN have higher precedence than the ternary op exercises/abs.c --8<-- ``` + + +Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints + + diff --git a/docs/getting-started/tutorials/verif-pointers.md b/docs/getting-started/tutorials/verif-pointers.md index 8fe6890f..b4149dc2 100644 --- a/docs/getting-started/tutorials/verif-pointers.md +++ b/docs/getting-started/tutorials/verif-pointers.md @@ -31,10 +31,9 @@ We can see this if we experimentally change the previous `transpose` example to BCP: Recheck that what we say here matches what it actually looks like - JWS: It appears quite different now. Seems like we can now step through the function (so is the assert still necessary?) -and the "Available resources" at the assert line are +and the `Available resources` at the assert line are RW(&temp_y)(P.y) RW(&temp_x)(P.x) RW(&ARG0)(p) @@ -42,6 +41,10 @@ RW(&p->y)(P.y) RW(&p->x)(P.x) ...I would just edit the text but I'm not sure how this output aligns with the one described below + +BCP: Someone just needs to look at it carefully and write down what's +true. I've lost track. :-) + ```c title="exercises/transpose.broken.c" --8<-- @@ -73,6 +76,10 @@ using the `swap` function. JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work? + +BCP: Maybe that's OK? Or maybe we can think of a more interesting variant... + + ```c title="exercises/transpose2.c" --8<-- @@ -80,13 +87,12 @@ exercises/transpose2.c --8<-- ``` - -BCP: Some more things to think about including... +{{ later(" BCP: Some more things to think about including... - Something about CN's version of the frame rule (see bcp_framerule.c, though the example is arguably a bit unnatural). - Examples from Basic.v with allocation - there are lots of interesting ones! CP: Agreed. For now continuing with arrays, but will return to this later. - +") }} diff --git a/src/exercises/array_load.broken.c b/src/exercises/array_load.broken.c new file mode 100644 index 00000000..618cc8ac --- /dev/null +++ b/src/exercises/array_load.broken.c @@ -0,0 +1,10 @@ +int read (int *p, int n, int i) +/*@ requires take A = each(i32 j; 0i32 <= j && j < n) { + RW(array_shift(p,j)) }; + 0i32 <= i && i < n; + ensures take A_post = each(i32 j; 0i32 <= j && j < n) { + RW(array_shift(p,j)) }; +@*/ +{ + return p[i]; +} diff --git a/src/exercises/add_two_array.c b/src/exercises/array_read_two.c similarity index 100% rename from src/exercises/add_two_array.c rename to src/exercises/array_read_two.c diff --git a/src/exercises/swap_array.c b/src/exercises/array_swap.c similarity index 91% rename from src/exercises/swap_array.c rename to src/exercises/array_swap.c index 41d5fa6c..d54ef43a 100644 --- a/src/exercises/swap_array.c +++ b/src/exercises/array_swap.c @@ -1,4 +1,4 @@ -void swap_array (int *p, int n, int i, int j) +void array_swap (int *p, int n, int i, int j) /* --BEGIN-- */ /*@ requires take a1 = each(i32 k; 0i32 <= k && k < n) { RW(array_shift(p,k)) }; 0i32 <= i && i < n; From de04c93e4a70ce257a3d1d9b0b88928ce556b19d Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Tue, 1 Apr 2025 00:38:19 -0400 Subject: [PATCH 089/158] finish draft of arrays chapter --- docs/getting-started/tutorials/arrays.md | 161 +++++++++++++++++++---- src/exercises/array_add3.test.c | 17 +++ src/exercises/array_load.test.c | 4 +- src/exercises/array_max.broken.c | 13 ++ src/exercises/array_sort.test.c | 22 ++++ src/exercises/array_write.test.c | 11 ++ 6 files changed, 203 insertions(+), 25 deletions(-) create mode 100644 src/exercises/array_add3.test.c create mode 100644 src/exercises/array_max.broken.c create mode 100644 src/exercises/array_sort.test.c create mode 100644 src/exercises/array_write.test.c diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index b8d40b2f..f966f085 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -4,8 +4,15 @@ Another common datatype in C is arrays. Reasoning about memory ownership for arr To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `unsigned` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: + +JWS: I think these should be `u64`s (per the warning), +but then the sizes `n` need to be cast to `u64` from `u32` +in the later example. Not sure what the cleanest route is here. + + + ```c -each (u32 i; i < 10i32) +each (u32 i; i < 10u32) { RW(array_shift(p,i)) } ``` @@ -21,28 +28,15 @@ In detail, this can be read as follows: Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. - - - -### First array example - -Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. +Let’s see how this applies to a simple array-manipulating function. Function `readi` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `readi` then returns the value of the `i`-th array cell. ```c title="exercises/array_load.test.c" --8<-- @@ -57,11 +51,132 @@ The CN precondition requires On exit the array ownership is returned again. The postcondition also asserts that the return value of the function is indeed equal to the value of the array at index `i`. - BCP: Do several more -examples (e.g., maybe working up to sorting?). - +### Writing to Arrays + +Consider this next function `writei`, which sets the value of the `i`-th array cell to be `val`. + +```c title="exercises/array_write.test.c" +--8<-- +exercises/array_write.test.c +--8<-- +``` + +The specification closely resembles that of `readi`, except for the last line, which now asserts that `A_post[i]`, the value of the array _after_ the function executes at index `i`, is equal to `val`. + +What if we additionally wanted to make assertions about values in the array _not_ being modified? In the prior `readi` example, we could add +```c +A == A_post +``` +to assert that the array before execution has the same values as the array after execution. In this `writei` example, we can replace the last line with +```c +A[i:v] == A_post +``` +to assert that the array before execution, with index `i` updated to `v`, has the same values as the array after execution. Note that the update syntax can be sequenced, e.g., `A[i:v1][j:v2]`. + +#### Exercises + +_Exercise:_ Write a specification for `array_swap`, which swaps the values of two cells of an int array. Assume that `i` and `j` are different. + +```c title="exercises/array_swap.c" +--8<- +exercises/array_swap.c +--8<-- +``` + +### Iterated Conditions + +Suppose we are writing a function that returns the maximum value in an array. Informally, we would want a postcondition that asserts that the returned value is greater than or equal to _each_ value in the array. Formally, for an array `A` of length `n`, we use an _iterated condition_ to write + +```c +each (u32 i; i < n) +{ return >= A[i] }; +``` + +Then, together with our usual conditions about ownership, as well as a precondition that the array is non-empty, we have this specification: + +```c +/*@ requires take A = each(u32 i; i < n) + { RW(array_shift(p,i)) }; + n > 0u32; + ensures take A_post = each(u32 i; i < n) + { RW(array_shift(p,i)) }; + each (u32 i; i < n) + { return >= A[i] }; + +@*/ +``` + +We next test this specification on this implementation of `array_max`. + +```c title="exercises/array_max.broken.c" +--8<-- +exercises/array_max.broken.c +--8<-- +``` + +If we run cn test, we get this error, and an associated counterexample + +``` +************************ Failed at ************************* +function array_max, file ./array_max2.broken-exec.c, line 36 +Load failed. + ==> 0x122534a74[0] (0x122534a74) not owned +``` + +This "not owned" error suggests that we are trying to access a region of memory that we do not have ownership over — an index out-of-bounds issue, perhaps. Indeed, if we inspect our implementation, we realize that we need to fix the `i <= n` to `i < n`. + + +If we run `cn test` again, we now get + +``` +************************ Failed at ************************* +function array_max, file ./array_max.broken-exec.c, line 117 +original source location: + each (u32 i; i < n) + ^~~~~~~~~~~~~~~~~~~ array_max.broken.c:7:13-8:32 + +********************** Failing input *********************** + +void* p0 = malloc(12); +*((unsigned int*)p0) = 18; +*((unsigned int*)((uintptr_t)p0 + 4)) = 0; +*((unsigned int*)((uintptr_t)p0 + 8)) = 17; +unsigned int* p = (unsigned int*)(p0); +unsigned int n = (unsigned int)(3); +array_max(p, n); + +************************************************************ + +``` + +Examining the generated counterexample, we see that the elements of the array are `{18, 0, 17}`, so the first element is the maximum. And if we generate counterexamples a few more times, we see that this pattern persists. Inspecting our implementation a bit further, we find and fix another bug: in the first line, we should initialize `max` to be `p[0]`, not `0`. + +(An additional debugging tip: if the generated counterexample arrays are too large, we can restrain them by adding a temporary precondition such as `n <= 3u32`, to force the array to be of length at most three, or some other suitable bound.) + -JWS: I don't actually know how something like sorting can be specified in CN. Any pointers? +^ JWS: I personally found this a useful hack, but I don't know if we want to advertise it as an officially sanctioned tip. (How close are folks to adding shrinking?) - BCP: Good question. Let's ask on Mattermost. + +Now, `cn test` will succeed! + +#### Exercises + +_Exercise:_ Write a specification for `array_add3`, which should add three to each array value. Your specification should succeed on this correct implementation, and fail when bugs are inserted (e.g., if four is added instead): + +```c title="exercises/array_add3.test.c" +--8<-- +exercises/array_add3.test.c +--8<-- +``` + +_Exercise:_ Write a specification for `array_sort`, which should sort an array into increasing order. Your specification should succeed on this correct implementation ([yes](https://arxiv.org/abs/2110.01111), it's correct), and fail when bugs are inserted: + + +JWS: One gnarly aspect of this is that you need to carefully avoid the `i + 1` in `i + 1 < n` overflowing. The version I got to work was to add a (seemingly redundant, but not actually) condition `i < n`. Slight variations, such as to assume a non-empty array, seems to make testing really really slow, and I'm not sure why. We should a) figure out what's the most elegant solution and b) give a hint to that effect. + +```c title="exercises/array_sort.test.c" +--8<-- +exercises/array_sort.test.c +--8<-- +``` \ No newline at end of file diff --git a/src/exercises/array_add3.test.c b/src/exercises/array_add3.test.c new file mode 100644 index 00000000..8214cbf4 --- /dev/null +++ b/src/exercises/array_add3.test.c @@ -0,0 +1,17 @@ +void array_add3 (unsigned int *p, unsigned int n) +/* --BEGIN-- */ +/*@ requires take A = each(u32 i; i < n) + { RW(array_shift(p,i)) }; + ensures take A_post = each(u32 i; i < n) + { RW(array_shift(p,i)) }; + each (u32 i; i < n) + { A_post[i] == A[i] + 3u32 }; + +@*/ +/* --END-- */ +{ + int i; + for (i = 0; i < n; i++) { + p[i] = p[i] + 3; + } +} \ No newline at end of file diff --git a/src/exercises/array_load.test.c b/src/exercises/array_load.test.c index a82d4e8a..b1787097 100644 --- a/src/exercises/array_load.test.c +++ b/src/exercises/array_load.test.c @@ -1,9 +1,9 @@ -unsigned int read (unsigned int *p, unsigned int n, unsigned int i) +unsigned int readi (unsigned int *p, unsigned int n, unsigned int i) /*@ requires take A = each(u32 j; j < n) { RW(array_shift(p,j)) }; i < n; ensures take A_post = each(u32 j; j < n) - { RW(array_shift(p,j)) }; + { RW(array_shift(p,j)) }; return == A[i]; @*/ { diff --git a/src/exercises/array_max.broken.c b/src/exercises/array_max.broken.c new file mode 100644 index 00000000..8245479e --- /dev/null +++ b/src/exercises/array_max.broken.c @@ -0,0 +1,13 @@ +unsigned int array_max (unsigned int *p, unsigned int n) +{ + int max = 0; + + int i; + for (i = 1; i <= n; i++) { + if (p[i] > max) { + max = p[i]; + } + } + + return max; +} \ No newline at end of file diff --git a/src/exercises/array_sort.test.c b/src/exercises/array_sort.test.c new file mode 100644 index 00000000..3dd6af7f --- /dev/null +++ b/src/exercises/array_sort.test.c @@ -0,0 +1,22 @@ +void array_sort (unsigned int *p, unsigned int n) +/* --BEGIN-- */ +/*@ requires take A = each(u32 i; i < n) + { RW(array_shift(p,i)) }; + ensures take A_post = each(u32 i; i < n) + { RW(array_shift(p,i)) }; + each (u32 i; i + 1u32 < n && i < n) + { A_post[i] <= A_post[i + 1u32] }; +@*/ +/* --END-- */ +{ + int i, j; + for (i = 0; i < n; i++) { + for (j = 0; j < n; j++) { + if (p[i] < p[j]) { + unsigned int temp = p[i]; + p[i] = p[j]; + p[j] = temp; + } + } + } +} \ No newline at end of file diff --git a/src/exercises/array_write.test.c b/src/exercises/array_write.test.c new file mode 100644 index 00000000..1e0c84f9 --- /dev/null +++ b/src/exercises/array_write.test.c @@ -0,0 +1,11 @@ +unsigned int writei (unsigned int *p, unsigned int n, unsigned int i, unsigned int v) +/*@ requires take A = each(u32 j; j < n) + { RW(array_shift(p,j)) }; + i < n; + ensures take A_post = each(u32 j; j < n) + { RW(array_shift(p,j)) }; + A_post[i] == v; +@*/ +{ + p[i] = v; +} From 7d891ec61f50feb35ba5b0bb9212f4708d90751a Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 09:49:08 -0400 Subject: [PATCH 090/158] Convert comments to new macro notation --- README.md | 3 +- .../case-studies/doubly-linked-lists.md | 18 ++-- .../case-studies/imperative-queues.md | 6 +- .../case-studies/the-runway.md | 10 +-- .../case-studies/verif-doubly-linked-lists.md | 10 +-- .../case-studies/verif-imperative-queues.md | 28 +++--- .../case-studies/verif-the-runway.md | 16 ++-- docs/getting-started/style-guide/README.md | 2 +- docs/getting-started/tutorials/alloc.md | 8 +- docs/getting-started/tutorials/arrays.md | 23 ++--- docs/getting-started/tutorials/block.md | 4 +- docs/getting-started/tutorials/lists.md | 15 ++-- docs/getting-started/tutorials/morestuff.md | 10 +-- .../getting-started/tutorials/overview-pbt.md | 4 +- docs/getting-started/tutorials/pointers.md | 42 ++++----- docs/getting-started/tutorials/predicates.md | 14 +-- docs/getting-started/tutorials/setup.md | 2 +- docs/getting-started/tutorials/todo.md | 4 +- docs/getting-started/tutorials/verif-alloc.md | 4 +- .../getting-started/tutorials/verif-arrays.md | 32 ++----- .../tutorials/verif-external.md | 50 ++++------- docs/getting-started/tutorials/verif-lists.md | 64 ++++---------- .../tutorials/verif-numeric.md | 86 +++++-------------- .../tutorials/verif-pointers.md | 33 +++---- .../tutorials/verif-splitcase.md | 8 +- docs/getting-started/tutorials/welcome.md | 4 +- .../broken/error-cerberus/00176.err2.c | 4 +- .../broken/error-cerberus/00181.err2.c | 8 +- .../broken/error-cerberus/00194.err2.c | 2 +- .../broken/error-cerberus/00205.err2.c | 2 +- .../broken/error-cerberus/00216.err2.c | 2 +- .../broken/error-cerberus/00220.err2.c | 2 +- .../broken/error-proof/00003_break.c | 2 +- 33 files changed, 184 insertions(+), 338 deletions(-) diff --git a/README.md b/README.md index b4906849..0277baf4 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,7 @@ Dependencies: ```bash # Install Material for MkDocs -pip install mkdocs-material -pip install mkdocs-macros-plugin +pip install mkdocs-material mkdocs-macros-plugin # Build the tutorial make diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 4ca18dac..167d4a6a 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -1,6 +1,6 @@ # Doubly-linked Lists -BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. +{{ todo("BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. ") }} A doubly linked list is a linked list where each node has a pointer to both the next node and the previous node. This allows for constant-time @@ -13,7 +13,7 @@ functions that manipulate doubly linked lists. ## Types -BCP: Does that work for testing? +{{ todo("BCP: Does that work for testing?") }} First, here is the C type definition: @@ -42,7 +42,7 @@ we first own the node that is passed in. Then we follow all of the all the `next` pointers to own everything forwards from the node, to construct the `left` and `right` fields. -BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? +{{ todo("BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? ") }} ```c title="exercises/dll/predicates.h" --8<-- @@ -54,8 +54,8 @@ Note that `Dll_at` takes ownership of the node passed in, and then calls `Own_Backwards` and `Own_Forwards`, which recursively take ownership of the rest of the list. -BCP: Has ptr_eq been explained? It's useful --- should be! +{{ todo("BCP: Has ptr_eq been explained? It's useful +-- should be! ") }} Also, notice that `Own_Forwards` and `Own_Backwards` include `ptr_eq` assertions for the `prev` and `next` pointers. This is to ensure that @@ -123,14 +123,14 @@ exercises/dll/add.test.c _Exercise_: Before reading on, see if you can figure out what specification is appropriate. -BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. +{{ todo("BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. ") }} Now, here is the annotated version of the `add` operation: -BCP: If we're not going to _discuss_ the +{{ todo("BCP: If we're not going to _discuss_ the solution, there's no need to include it here in-line, since people already know where to find the file. (But, of course, we should -discuss it!) +discuss it!) ") }} ```c title="solutions/dll/add.c" --8<-- @@ -180,7 +180,7 @@ exercises/dll/remove.test.c _Exercise_: Before reading on, see if you can figure out what specification is appropriate. -BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. +{{ todo("BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. ") }} Now, here is the annotated version of the `remove` operation: diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index e0e2c4a7..0ce356ff 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -67,9 +67,9 @@ walking down the cells from the front and gathering all the rest of them into a sequence. We take the result from `QueueAux` and `snoc` on the very last element. -BCP: Explain the asserts. (Why) are they useful +{{ todo("BCP: Explain the asserts. (Why) are they useful for testing? If they are not useful, make a testing-only version -that omits them! Ditto the QueueAux predicate below. +that omits them! Ditto the QueueAux predicate below.") }} Finally, the `QueueAux` predicate recurses down the list of cells and returns a list of their contents. @@ -173,4 +173,4 @@ exercises/queue/pop.c --8<-- ``` -BCP: Needs some more exercises? +{{ todo("BCP: Needs some more exercises?") }} diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 19b54299..99d020e1 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -1,11 +1,11 @@ # Airport Simulation -BCP: I'm nervous about this case study -- it +{{ todo("BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if others like it we can try to whip it into better shape... (Later: It seems people do like it, because it is more like SUT code than the other examples. So we -should make it better.) +should make it better.) ") }} Suppose we have been tasked with writing a program that simulates a runway at an airport. This airport is very small, so it only has one @@ -16,7 +16,7 @@ following informal specification: 1. The runway has two modes: departure mode and arrival mode. The two modes can never be active at the same time. Neither mode is active at the beginning of the day. -BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) +{{ todo("BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) ") }} 2. At any given moment, there is a waiting list of planes that need to land at the airport and planes that need to leave the @@ -76,8 +76,8 @@ following fields: or departed while planes are waiting for the other mode. This will help us keep track of the 3-plane limit as described in _(6)_. -BCP: Do we need these functions for the -testing version? Has function been explained earlier? +{{ todo("BCP: Do we need these functions for the +testing version? Has function been explained earlier? ") }} ```c title="exercises/runway/state.h" --8<-- diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md index b292b44c..f086e3d3 100644 --- a/docs/getting-started/case-studies/verif-doubly-linked-lists.md +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -1,8 +1,8 @@ # Doubly-linked Lists, Verified -Need updating after testing/verif split. +{{ todo("Need updating after testing/verif split.") }} -BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. +{{ todo("BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. ") }} A doubly linked list is a linked list where each node has a pointer to both the next node and the previous node. This allows for O(1) @@ -40,7 +40,7 @@ we first own the node that is passed in. Then we follow all of the all the `next` pointers to own everything forwards from the node, to construct the `left` and `right` fields. -BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? +{{ todo("BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? ") }} ```c title="exercises/dll/predicates.h" --8<-- @@ -114,7 +114,7 @@ exercises/dll/add_orig.broken.c _Exercise_: Before reading on, see if you can figure out what specification is appropriate and what other are needed. -BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. +{{ todo("BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. ") }} Now, here is the annotated version of the `add` operation: @@ -175,7 +175,7 @@ exercises/dll/remove_orig.broken.c _Exercise_: Before reading on, see if you can figure out what specification is appropriate and what annotations are needed. -BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. +{{ todo("BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. ") }} Now, here is the fully annotated version of the `remove` operation: diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md index c9fd65c8..19d316cb 100644 --- a/docs/getting-started/case-studies/verif-imperative-queues.md +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -1,6 +1,6 @@ # Imperative Queues, Verified -Need updating after testing/verif split. +{{ todo("Need updating after testing/verif split.") }} A queue is a linked list with O(1) operations for adding things to one end (the "back") and removing them from the other (the "front"). Here @@ -74,13 +74,13 @@ piece of information about an invariant of the representation: The `back` pointer always points to the very last cell in the list, so its `next` field will always be NULL. -BCP: First point where testing and -verification split. Remove most of the material above here. +{{ todo("BCP: First point where testing and +verification split. Remove most of the material above here.") }} -BCP: What about the second assert? +{{ todo("BCP: What about the second assert? ") }} -BCP: How to help people guess that these are -needed?? +{{ todo("BCP: How to help people guess that these are +needed?? ") }} Finally, the `QueueAux` predicate recurses down the list of cells and returns a list of their contents. @@ -171,8 +171,8 @@ elements, so we should expect that validating `push` is going to require some reasoning about this sequence. Here, in fact, is the lemma we need. -BCP: Not sure I can explain what "pointer" means here, or why we don't need to declare more specific types for these arguments to the lemma. - +{{ todo("BCP: Not sure I can explain what 'pointer' means here, or why we don't need to declare more specific types for these arguments to the lemma. ") }} +{{ todo("Dhruv: See above comments about strong updates: in a requires/ensures, the types are given by the arguments in scope, but here we don't have that.") }} ```c title="exercises/queue/push_lemma.h" --8<-- @@ -237,7 +237,7 @@ CN which of the branches of the `if` at the beginning of the unpacked immediately because it is unconditional, but `QueueFB` cannot.) -BCP: the word "unpack" is mysterious here. +{{ todo("BCP: the word 'unpack' is mysterious here. ") }} The guard/condition for `QueueFB` is `is_null(front)`, which is why we need to do a `split_case` on this value. On one branch of the @@ -282,14 +282,14 @@ clauses. (Taking them just in the `requires` clause would imply that they are consumed and deallocated when the lemma is applied -- not what we want!) -BCP: The thing about ghost values is mysterious. - +{{ todo("BCP: The thing about ghost values is mysterious. ") }} +{{ todo("How to say it better?") }} (The only reason we can't currently prove this lemma in CN is that we don't have `take`s in CN statements, because this is just a simple unfolding.) -BCP: Ugh. +{{ todo("BCP: Ugh. ") }} ## Exercises @@ -325,5 +325,5 @@ Can you generalize the `snoc_facts` lemma to handle both cases? You can get past the dereference with a `split_case` but formulating the lemma before the `return` will be a bit more complicated. -BCP: Again, this has not been shown to be -possible, but Dhruv believes it should be! +{{ todo("BCP: Again, this has not been shown to be +possible, but Dhruv believes it should be! ") }} diff --git a/docs/getting-started/case-studies/verif-the-runway.md b/docs/getting-started/case-studies/verif-the-runway.md index 91c6099a..e5a1cb41 100644 --- a/docs/getting-started/case-studies/verif-the-runway.md +++ b/docs/getting-started/case-studies/verif-the-runway.md @@ -1,6 +1,6 @@ # Airport Simulation, Verified -BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... +{{ todo("BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... ") }} Suppose we have been tasked with writing a program that simulates a runway at an airport. This airport is very small, so it only has one @@ -11,7 +11,7 @@ following informal specification: 1. The runway has two modes: departure mode and arrival mode. The two modes can never be active at the same time. Neither mode is active at the beginning of the day. -BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) +{{ todo("BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) ") }} 2. At any given moment, there is a waiting list of planes that need to land at the airport and planes that need to leave the @@ -135,7 +135,7 @@ This material is based upon work supported by the Air Force Research Laboratory - +") }} diff --git a/docs/getting-started/style-guide/README.md b/docs/getting-started/style-guide/README.md index 69e804fb..4c4dace2 100644 --- a/docs/getting-started/style-guide/README.md +++ b/docs/getting-started/style-guide/README.md @@ -1,6 +1,6 @@ # Style Guide -BCP: If we are agreed on the naming conventions suggested in /NAMING-CONVENTIONS.md, we could move that material here. +{{ todo("BCP: If we are agreed on the naming conventions suggested in /NAMING-CONVENTIONS.md, we could move that material here. ") }} !!! warning diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index 920d6d46..dfa3bd90 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -27,9 +27,7 @@ that manipulate the heap, as usual. exercises/slf17_get_and_free.test.c --8<-- ``` - -BCP: The `tester` function here does not parse -- not sure why. - +{{ todo("BCP: The `tester` function here does not parse -- not sure why.") }} ### Exercises @@ -79,6 +77,4 @@ already-initialised memory cell to be over-written again. Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. - -BCP: An example and/or an exercise would be nice! - +{{ todo("BCP: An example and/or an exercise would be nice!") }} diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index b8d40b2f..145054ee 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -21,8 +21,8 @@ In detail, this can be read as follows: Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. - - +- `RESOURCE` is any non-iterated CN resource. ") }} +{{ todo("BCP: Also: What is a CN type? What is a basetype?") }} ### First array example @@ -57,11 +54,7 @@ The CN precondition requires On exit the array ownership is returned again. The postcondition also asserts that the return value of the function is indeed equal to the value of the array at index `i`. - BCP: Do several more -examples (e.g., maybe working up to sorting?). - - -JWS: I don't actually know how something like sorting can be specified in CN. Any pointers? - - BCP: Good question. Let's ask on Mattermost. - +{{ todo(" BCP: Do several more +examples (e.g., maybe working up to sorting?).") }} +{{ todo("JWS: I don't actually know how something like sorting can be specified in CN. Any pointers?") }} +{{ todo(" BCP: Good question. Let's ask on Mattermost.") }} diff --git a/docs/getting-started/tutorials/block.md b/docs/getting-started/tutorials/block.md index c40740cc..3098b02e 100644 --- a/docs/getting-started/tutorials/block.md +++ b/docs/getting-started/tutorials/block.md @@ -20,9 +20,7 @@ are fine). The write consumes ownership of the `W` resource value written as the output. This means the resource returned from a write records the fact that this memory cell is now initialised and can be read from. - -BCP: Not sure I understand "returns a new resource `RW(p)` with the value written as the output" -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. - +{{ todo("BCP: Not sure I understand 'returns a new resource `RW(p)` with the value written as the output' -- perhaps in part because I don't understand what the output of a resource means when the resource is not in the context o a take expression. ") }} Since `RW` carries the same ownership as `W`, just with the additional information that the `RW` memory is initalised, a diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index c5300482..e6d452df 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -14,10 +14,8 @@ Here are typed allocation and deallocation functions for this type. (We provide separate functions for these rather than just calling `malloc` and `free` directly in the interest of sharing as much code as possible with the verification-focused variants of these examples.) - -BCP: ... but maybe we'd get the same amount of sharing if we directly -used malloc? We should check. - +{{ todo("BCP: ... but maybe we'd get the same amount of sharing if we directly +used malloc? We should check.") }} ```c title="exercises/list/c_types.test.h" --8<-- @@ -29,8 +27,8 @@ To write specifications for C functions that manipulate lists, we need to define a CN "predicate" that describes specification-level list structures. We use the datatype `List` for CN-level lists. - BCP: Industrial developers will need a _lot_ -more help than that! +{{ todo(" BCP: Industrial developers will need a _lot_ +more help than that! ") }} Intuitively, the `SLList_At` predicate walks over a singly-linked pointer structure in the C heap and extracts an `RW` version of @@ -105,10 +103,9 @@ exercises/list/copy.c ### Merge sort - BCP: This could use a gentler explanation +{{ todo(" BCP: This could use a gentler explanation (probably in pieces) We've heard from more than one reader that this -example is particularly hard to digest without some additional help - +example is particularly hard to digest without some additional help") }} Finally, here is a slightly tricky in-place version of merge sort that avoids allocating any new list cells in the splitting step by taking diff --git a/docs/getting-started/tutorials/morestuff.md b/docs/getting-started/tutorials/morestuff.md index 3f51928a..6c8ec790 100644 --- a/docs/getting-started/tutorials/morestuff.md +++ b/docs/getting-started/tutorials/morestuff.md @@ -6,10 +6,8 @@ This file collects some material that may or may not be useful long term. We can also define a "safer", ML-style version of `malloc` that handles both allocation and initialization: - -BCP: Are these worth the trouble to present? C programmers will not find them -interesting, I guess. - +{{ todo("BCP: Are these worth the trouble to present? C programmers will not find them +interesting, I guess.") }} ```c title="exercises/ref.h" --8<-- @@ -17,9 +15,7 @@ exercises/ref.h --8<-- ``` - -TODO: BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does... - +{{ todo("TODO: BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does...") }} ```c title="exercises/slf16_basic_succ_using_incr.c" --8<-- diff --git a/docs/getting-started/tutorials/overview-pbt.md b/docs/getting-started/tutorials/overview-pbt.md index 81f0f785..799bccad 100644 --- a/docs/getting-started/tutorials/overview-pbt.md +++ b/docs/getting-started/tutorials/overview-pbt.md @@ -32,9 +32,7 @@ It calls the function with this input and uses [Fulminate](overview-fulminate.md #### Understanding errors - -BCP: This is out of date: - +{{ todo("BCP: This is out of date:") }} Currently, the tool does not print out counterexamples, but this is [planned](https://github.com/rems-project/cerberus/issues/841). Until then, `tests.out` can be run with the `--trap` flag in a debugger. Since seeds are printed each time the tool runs, `--seed ` can be used to reproduce the test case. diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index e6794d35..4dc4cc89 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -43,13 +43,13 @@ Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type `T`. - - +are less confusingly presented as always required? ") }} - I mildly prefer the second. But I wonder whether the decision should be informed by some data about whether pointers to single words are common in real C code... ---> +") }} - - + annotations...?") }} In this example, we can ensure the safe execution of `read` by adding a precondition that requires ownership of `RW(p)`, as @@ -115,13 +115,11 @@ exercises/read2.c ??? note "Aside (for separation-logic experts)" _Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): - - Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. - + {{ todo(" Sainati: as a separation logic noob, I would love a more detailed explanation about what is going on here. + ") }} - - Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? - + {{ todo(" Why do we need to have v2 existentially quantified, for example, when p is only pointing to a single value? + ") }} ``` ∀p. @@ -164,10 +162,8 @@ We next have an example where data is written to a pointer. The function `incr` takes a pointer `p` and increments the value in the memory cell that it points to. - +{{ todo("BCP: unsigned! (there are both signed and unsigned versions at the +moment -- how do they relate?)") }} ```c title="exercises/slf0_basic_incr.c" --8<-- exercises/slf0_basic_incr.c @@ -233,9 +229,9 @@ _returned_ to the caller or else _destroyed_ by deallocating the RW area of memory (as we shall see later). CN’s motivation for this choice is its focus on low-level systems software in which memory is managed manually; in this context, memory leaks are typically very undesirable. - +the caller. ") }} ## Disjoint memory regions @@ -290,11 +286,11 @@ i.e., they are records with members `x` and `y`. The postcondition asserts the coordinates have been swapped by referring to the members of `P` and `P_post` individually. - +RW(expr)` we have `expr : pointer, x : to_basetype(ct)`. ") }} {{ todo("TODO: It would be nice to add an exercise that involves using the error messages to find a bug.") }} diff --git a/docs/getting-started/tutorials/predicates.md b/docs/getting-started/tutorials/predicates.md index c87cff56..4191db6d 100644 --- a/docs/getting-started/tutorials/predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -1,9 +1,7 @@ # Defining Predicates - -BCP: The text becomes a bit sketchy from here on! But hopefully there's -still enough structure here to make sense of the examples... - +{{ todo("BCP: The text becomes a bit sketchy from here on! But hopefully there's +still enough structure here to make sense of the examples...") }} Suppose we want to write a function that takes _two_ pointers to integers and increments the contents of both of them. @@ -38,10 +36,6 @@ exercises/slf_incr2.test.c --8<-- ``` - -BCP: Needs quite a few more words. - +{{ todo("BCP: Needs quite a few more words.") }} - -BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types. - +{{ todo("BCP: We haven't introduced CN records. In particular, C programmers may be surprised that we don't have to pre-declare record types.") }} diff --git a/docs/getting-started/tutorials/setup.md b/docs/getting-started/tutorials/setup.md index 3f61d8ad..be1d4add 100644 --- a/docs/getting-started/tutorials/setup.md +++ b/docs/getting-started/tutorials/setup.md @@ -2,7 +2,7 @@ ## Install CN -*Write me* +{{ todo("*Write me*") }} ## Download exercise sources diff --git a/docs/getting-started/tutorials/todo.md b/docs/getting-started/tutorials/todo.md index 71ad1528..b15d5106 100644 --- a/docs/getting-started/tutorials/todo.md +++ b/docs/getting-started/tutorials/todo.md @@ -117,7 +117,7 @@ Further topics: - cn_function - pack - bitwise functions (operators are not present in the logical language) -- "ownership" in Rust vs. CN +- 'ownership' in Rust vs. CN - tips amnd tricks -- cf. [](https://dafny.org/dafny/DafnyRef/DafnyRef.html#sec-verification) - more data structures to try out @@ -155,7 +155,7 @@ Misc things to do: - everyplace we do storage allocation, we should really allow the malloc call to return NULL if it wants to; the caller should explicitly check that it didn't get back NULL. This requires - defining an "exit" function" with trivial pre- and postconditions + defining an "exit" function with trivial pre- and postconditions (true / false). - In queue.c, when I tried /_@ unfold QueueAux (F.front, F.back, diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md index 2ffe7471..404a8bb3 100644 --- a/docs/getting-started/tutorials/verif-alloc.md +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -51,9 +51,7 @@ Alternatively we can include an actual implementation of inside a CN file by marking them with the keyword `trusted` at the top of their CN specifications. - -BCP: Make up a real example... - +{{ todo("BCP: Make up a real example...") }} ```c title="exercises/malloc_trusted.verif.c" --8<-- diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 0e3f2119..072f361e 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -104,8 +104,7 @@ exercises/array_swap.c --8<-- ``` - -BCP: I wrote the following, which seemed natural but did not +{{ todo("BCP: I wrote the following, which seemed natural but did not work -- I still don't fully understand why. I think this section will need some more examples / exercises to be fully digestible, or perhaps this is just yet another symptom of my imperfect understanding of how @@ -127,8 +126,7 @@ the numeric stuff works. unsigned int tmp = p[i]; p[i] = p[j]; p[j] = tmp; - } - + }") }} ### Loops @@ -138,17 +136,11 @@ In order to verify code with loops, CN requires the user to supply loop invarian Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. - -BCP: Rename to array_init.c - +{{ todo("BCP: Rename to array_init.c") }} - -JWS: Should this change be propagated everywhere e.g. also changing the function name, changing other function names starting with `init_`, changing `swap_array` to `array_swap`, etc.? - +{{ todo("JWS: Should this change be propagated everywhere e.g. also changing the function name, changing other function names starting with `init_`, changing `swap_array` to `array_swap`, etc.?") }} - -BCP: Yes! I've done a bit of it, but there's more. - +{{ todo("BCP: Yes! I've done a bit of it, but there's more.") }} ```c title="exercises/init_array.c" --8<-- @@ -225,12 +217,8 @@ As before, we also have to instruct CN to `focus` ownership of individual array - finally, we add `focus RW, j;` to allow CN to "`attach`" this resource to the iterated `RW` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `focus` only for the "`reverse`" direction. - -BCP: That last bit is mysterious. - - -Dhruv: See long explanation and issue here: rems-project/cerberus#498 - +{{ todo("BCP: That last bit is mysterious.") }} +{{ todo("Dhruv: See long explanation and issue here: rems-project/cerberus#498") }} ### Exercises @@ -242,7 +230,5 @@ exercises/init_array_rev.c --8<-- ``` - -A potential case study (involving nested iteration): - https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128 - +{{ todo("A potential case study (involving nested iteration): + https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128") }} diff --git a/docs/getting-started/tutorials/verif-external.md b/docs/getting-started/tutorials/verif-external.md index d118d876..2b6bc624 100644 --- a/docs/getting-started/tutorials/verif-external.md +++ b/docs/getting-started/tutorials/verif-external.md @@ -1,24 +1,16 @@ # Working with External Lemmas - -BCP: This section should also show what the proof of the lemmas -looks like on the Coq side! - - - -BCP: This needs to be filled in urgently!! - - - Dhruyv: There are some examples in the Cerberus repo tests? rems-project/cerberus@20d9d5c - - - -TODO: BCP: +{{ todo("BCP: This section should also show what the proof of the lemmas +looks like on the Coq side! ") }} + +{{ todo("BCP: This needs to be filled in urgently!! ") }} +{{ todo(" Dhruyv: There are some examples in the Cerberus repo tests? rems-project/cerberus@20d9d5c ") }} + +{{ todo("TODO: BCP: think about capitalization, etc., for lemma names push_lemma should be Push_lemma, I guess? Or lemma_push? snoc_facts should be lemma_Snoc or something -others? - +others?") }} ### List reverse @@ -52,12 +44,10 @@ Having stated these lemmas, we can now complete the specification and proof of `IntList_rev`. Note the two places where `apply` is used to tell the SMT solver where to pay attention to the lemmas. - -TODO: BCP: Why can't it always pay attention to them? (I guess -"performance", but at least it would be nice to be able to declare a +{{ todo("TODO: BCP: Why can't it always pay attention to them? (I guess +'performance', but at least it would be nice to be able to declare a general scope where a given set of lemmas might be needed, rather than -specifying exactly where to use them.) - +specifying exactly where to use them.)") }} ```c title="exercises/list/rev.c" --8<-- @@ -68,9 +58,7 @@ exercises/list/rev.c For comparison, here is another way to write the program, using a while loop instead of recursion, with its specification and proof. - -BCP: Why 0 instead of NULL?? (Is 0 better?) - +{{ todo("BCP: Why 0 instead of NULL?? (Is 0 better?) ") }} ```c title="exercises/list/rev_alt.c" --8<-- @@ -82,9 +70,7 @@ exercises/list/rev_alt.c **Sized stacks:** Fill in annotations where requested: - -BCP: type_synonym has not been introduced yet - +{{ todo("BCP: type_synonym has not been introduced yet ") }} ```c title="exercises/slf_sized_stack.c" --8<-- @@ -92,17 +78,13 @@ exercises/slf_sized_stack.c --8<-- ``` - - ====================================================================== - +{{ todo(" ====================================================================== ") }} ## More on CN Annotations - -TODO: Introduce all the different sorts of CN annotations (e.g., - `split_case`) individually with small examples and exercises. - +{{ todo("TODO: Introduce all the different sorts of CN annotations (e.g., + `split_case`) individually with small examples and exercises.") }} diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index 7061eda0..323815cc 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -1,8 +1,6 @@ # Lists, verified - -BCP: intro needed - +{{ todo("BCP: intro needed") }} As before, we need slightly different functions for allocating and deallocating linked list cells: @@ -13,15 +11,9 @@ exercises/list/c_types.verif.h --8<-- ``` - -BCP: Per discussion with Christopher, Cassia, and Daniel, the word "predicate" is quite confusing for newcomers (in logic, predicates do not return things!). A more neutral word might make for significantly easier onboarding. - - -Dhruv: Or no keyword? rems-project/cerberus#304 How about traversal? - - - BCP: No keyword sounds even better. But "traversal" in the interim is not bad. Or maybe "extractor" or something like that? - +{{ todo("BCP: Per discussion with Christopher, Cassia, and Daniel, the word 'predicate' is quite confusing for newcomers (in logic, predicates do not return things!). A more neutral word might make for significantly easier onboarding.") }} +{{ todo("Dhruv: Or no keyword? rems-project/cerberus#304 How about traversal?") }} +{{ todo(" BCP: No keyword sounds even better. But 'traversal' in the interim is not bad. Or maybe 'extractor' or something like that?") }} To write specifications for C functions that manipulate lists, we need to define a CN "predicate" that describes specification-level list @@ -67,11 +59,9 @@ exercises/list/headers.verif.h --8<-- ``` - -TODO: BCP: The 'return != NULL' should not be needed, but to remove it +{{ todo("TODO: BCP: The 'return != NULL' should not be needed, but to remove it we need to change the callers of all the allocation functions to check -for NULL and exit (which requires adding a spec for exit). - +for NULL and exit (which requires adding a spec for exit).") }} ### Append @@ -87,19 +77,15 @@ exercises/list/append.h --8<-- ``` - -BCP: Here's the first place where the verification version differs. -Tidy the file above and below! - +{{ todo("BCP: Here's the first place where the verification version differs. +Tidy the file above and below!") }} Here is a simple destructive `append` function. Note the two uses of the `unfold` annotation in the body, which are needed to help the CN typechecker. The `unfold` annotation is an instruction to CN to replace a call to a recursive (CN) function (in this case `append`) with its definition, and is necessary because CN is unable to automatically determine when and where to expand recursive definitions on its own. - -BCP: Can someone add a more technical explanation of why they are needed and exactly what they do? - +{{ todo("BCP: Can someone add a more technical explanation of why they are needed and exactly what they do?") }} ```c title="exercises/list/append.verif.c" --8<-- @@ -120,19 +106,15 @@ exercises/list/copy.c ### Merge sort - -BCP: This could use a gentler explanation (probably in pieces). But -much of it will be in lists.md, not here. - +{{ todo("BCP: This could use a gentler explanation (probably in pieces). But +much of it will be in lists.md, not here.") }} Finally, here is a slightly tricky in-place version of merge sort that avoids allocating any new list cells in the splitting step by taking alternate cells from the original list and linking them together into two new lists of roughly equal lengths. - -BCP: Nit: Merge multiple requires and ensures clauses into one - +{{ todo("BCP: Nit: Merge multiple requires and ensures clauses into one") }} ```c title="exercises/list/mergesort.c" --8<-- @@ -174,22 +156,12 @@ exercises/list/free.c _Length with an accumulator_. Add annotations as appropriate: - -BCP: Removing / forgetting the unfold in this one gives a truly - - - bizarre error message saying that the constraint "n == (n + length(L1))" - - - is unsatisfiable... - - - -Sainati: when I went through the tutorial, the file provided for this exercise was already "complete" in that - - - it already had all the necessary annotations present for CN to verify it - +{{ todo("BCP: Removing / forgetting the unfold in this one gives a truly") }} +{{ todo(" bizarre error message saying that the constraint `n == (n + length(L1))`") }} +{{ todo(" is unsatisfiable...") }} + +{{ todo("Sainati: when I went through the tutorial, the file provided for this exercise was already 'complete' in that") }} +{{ todo(" it already had all the necessary annotations present for CN to verify it") }} ```c title="exercises/slf_length_acc.c" --8<-- diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 870683b6..6a957182 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -50,21 +50,13 @@ solutions/add_0.c In detail: -- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. -BCP: I understand this reasoning, but I wonder whether it introduces more confusion than it avoids -- it means there are two ways of writing everything, and people have to remember whether the particular thing they are writing right now is C or CN... - - BCP: Hopefully we are moving toward unifying these notations anyway? - +- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`.{{ todo("BCP: I understand this reasoning, but I wonder whether it introduces more confusion than it avoids -- it means there are two ways of writing everything, and people have to remember whether the particular thing they are writing right now is C or CN... ") }}{{ todo(" BCP: Hopefully we are moving toward unifying these notations anyway? ") }} - To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. - Finally, we require this sum to be between the minimal and maximal `int` values. Integer constants, such as `-2147483648i64`, must specifiy their CN type (`i64`). - -BCP: We should use the new ' syntax (or whatever it turned out to be) for numeric constants - - -Dhruv: Yet to be implemented: rems-project/cerberus#337 - + {{ todo("BCP: We should use the new ' syntax (or whatever it turned out to be) for numeric constants ") }} + {{ todo("Dhruv: Yet to be implemented: rems-project/cerberus#337 ") }} Running CN on the annotated program passes without errors. This means that, with our specified precondition, `add` is safe to execute. @@ -97,9 +89,9 @@ coercion `(i64)`. ## Error reports -*Most of this material needs to be moved to +{{ todo("*Most of this material needs to be moved to the first section where we talk about verification, but it will need a -different example (not involving i32 or UB)...* +different example (not involving i32 or UB)...*") }} In the original example, CN reported a type error due to C undefined behavior. While that example was perhaps simple enough to guess the @@ -181,12 +173,8 @@ CN displays concrete values: For now, ignore the pointer values `{@0; 4}` for `x` and `{@0; 0}` for `y`. - -BCP: Where are these things discussed? Anywhere? (When) are they useful? - - -Dhruv: These are part of VIP memory model things I'm working on, which will hopefully be implemented and enabled in the next few weeks. - +{{ todo("BCP: Where are these things discussed? Anywhere? (When) are they useful? ") }} +{{ todo("Dhruv: These are part of VIP memory model things I'm working on, which will hopefully be implemented and enabled in the next few weeks. ") }} These concrete values are part of a _counterexample_: a concrete valuation of variables and pointers in the program that that leads to @@ -200,12 +188,8 @@ _Proof context._ The second section, below the error trace, lists the proof cont "`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. - -BCP: Again, where are these things discussed? Should they be? - - -Dhruv: Also VIP. - +{{ todo("BCP: Again, where are these things discussed? Should they be? ") }} +{{ todo("Dhruv: Also VIP. ") }} Finally, "`Constraints`" records all logical facts CN has learned along the path. This includes user-specified assumptions from preconditions or loop invariants, value ranges inferred from the C-types of variables, and facts learned during the type checking of the statements. Here -- when checking `add` without precondition -- the only constraints are those inferred from C-types in the code: @@ -213,34 +197,22 @@ Finally, "`Constraints`" records all logical facts CN has learned along the path `x` is a "`good`" `signed int` value (i.e. in range). Here `signed int` is the same type as `int`, CN just makes the sign explicit. - -BCP: Yikes! This seems potentially confusing - + {{ todo("BCP: Yikes! This seems potentially confusing ") }} For an integer type `T`, the type `good` requires the value to be in range of type `T`; for pointer types `T`, it also requires the pointer to be aligned. For structs and arrays, this extends in the obvious way to struct members or array cells. - -BCP: Is this information actually ever useful? Is it currently suppressed? - + {{ todo("BCP: Is this information actually ever useful? Is it currently suppressed? ") }} - `repr` requires representability (not alignment) at type `T`, so `repr(&ARGO)`, for instance, records that the pointer to `x` is representable at C-type `signed int*`; - `aligned(&ARGO, 4u64)`, moreover, states that it is 4-byte aligned. - -URGENT: BCP: Some of the above (especially the bit at the end) feels like TMI for many/most users, especially at this point in the tutorial. - - -Dhruv: Probably true, we actually even hide some of these by default. - - - BCP: I propose we hide the rest and move this discussion to somewhere else ("Gory Details" section of the tutorial, or better yet reference manual). - - -Dhruv: Thumbs up - +{{ todo("URGENT: BCP: Some of the above (especially the bit at the end) feels like TMI for many/most users, especially at this point in the tutorial. ") }} +{{ todo("Dhruv: Probably true, we actually even hide some of these by default. ") }} +{{ todo(" BCP: I propose we hide the rest and move this discussion to somewhere else ('Gory Details' section of the tutorial, or better yet reference manual). ") }} +{{ todo("Dhruv: Thumbs up ") }} ### Another arithmetic example @@ -248,9 +220,7 @@ Let’s apply what we know so far to another simple arithmetic example. The function `doubled`, shown below, takes an int `n`, defines `a` as `n` incremented, `b` as `n` decremented, and returns the sum of the two. - -BCP: Is it important to number the slf examples? If so, we should do it consistently, but IMO it is not. Better to rename them without numbers. - +{{ todo("BCP: Is it important to number the slf examples? If so, we should do it consistently, but IMO it is not. Better to rename them without numbers. ") }} ```c title="exercises/slf1_basic_example_let.signed.c" --8<-- @@ -268,24 +238,14 @@ solutions/slf1_basic_example_let.signed.c --8<-- ``` - -BCP: WHy n*+n\_ in some places and n\*2i32 in others? - - -Dhruv: Unlikely to be meaningful, either is fine. - +{{ todo("BCP: WHy n*+n\_ in some places and n\*2i32 in others? ") }} +{{ todo("Dhruv: Unlikely to be meaningful, either is fine. ") }} We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. - -BCP: How about renaming N to n64? - - -Dhruv: Sensible. - - - BCP: (someone do it on next pass) - +{{ todo("BCP: How about renaming N to n64? ") }} +{{ todo("Dhruv: Sensible. ") }} +{{ todo(" BCP: (someone do it on next pass) ") }} To capture the functional behaviour, the postcondition specifies that `return` is twice the value of `n`. @@ -308,7 +268,5 @@ exercises/abs.c --8<-- ``` - -Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints - +{{ todo("Sainati: I think it would be useful to have a int array version of this exercise as a worked example; I am not sure, for example, how one would express bounds requirements on the contents of an array in CN, as you would need to do here to ensure that p[i] + p[j] doesn’t overflow if p's contents are signed ints") }} diff --git a/docs/getting-started/tutorials/verif-pointers.md b/docs/getting-started/tutorials/verif-pointers.md index b4149dc2..642101dc 100644 --- a/docs/getting-started/tutorials/verif-pointers.md +++ b/docs/getting-started/tutorials/verif-pointers.md @@ -28,23 +28,17 @@ To handle the required resource inference, CN "`eagerly`" decomposes all `struct We can see this if we experimentally change the previous `transpose` example to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of `transpose`, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) - -BCP: Recheck that what we say here matches what it actually looks like - - -JWS: It appears quite different now. Seems like we can now step through the function (so is the assert still necessary?) +{{ todo("BCP: Recheck that what we say here matches what it actually looks like") }} +{{ todo("JWS: It appears quite different now. Seems like we can now step through the function (so is the assert still necessary?) and the `Available resources` at the assert line are RW(&temp_y)(P.y) RW(&temp_x)(P.x) RW(&ARG0)(p) RW(&p->y)(P.y) RW(&p->x)(P.x) -...I would just edit the text but I'm not sure how this output aligns with the one described below - - -BCP: Someone just needs to look at it carefully and write down what's -true. I've lost track. :-) - +...I would just edit the text but I'm not sure how this output aligns with the one described below") }} +{{ todo("BCP: Someone just needs to look at it carefully and write down what's +true. I've lost track. :-)") }} ```c title="exercises/transpose.broken.c" --8<-- @@ -58,10 +52,8 @@ The precondition of `transpose` asserts ownership of an `RW(p)` re - `RW(member_shift(p, y))` with output `P.y` - -BCP: We should verify that it really does say this. (It certainly -does not, after recent syntax changes...) - +{{ todo("BCP: We should verify that it really does say this. (It certainly +does not, after recent syntax changes...)") }} Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. @@ -73,12 +65,8 @@ _Exercise:_ Insert CN `assert(false)` statements in different statement position _Exercise:_ Recreate the `transpose` function from before, now using the `swap` function. - -JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work? - - -BCP: Maybe that's OK? Or maybe we can think of a more interesting variant... - +{{ todo("JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work?") }} +{{ todo("BCP: Maybe that's OK? Or maybe we can think of a more interesting variant...") }} ```c title="exercises/transpose2.c" @@ -92,7 +80,6 @@ exercises/transpose2.c bcp_framerule.c, though the example is arguably a bit unnatural). - Examples from Basic.v with allocation - there are lots of interesting ones! - CP: Agreed. For now continuing with arrays, but will return to this later. -") }} + CP: Agreed. For now continuing with arrays, but will return to this later.") }} diff --git a/docs/getting-started/tutorials/verif-splitcase.md b/docs/getting-started/tutorials/verif-splitcase.md index 87c4ab66..9473efd8 100644 --- a/docs/getting-started/tutorials/verif-splitcase.md +++ b/docs/getting-started/tutorials/verif-splitcase.md @@ -1,8 +1,6 @@ # (Verification) Case Analysis - -This section needs writing... - +{{ todo("This section needs writing...") }} To verify the `slf_incr2` example, we need one more CN annotation in the body of the @@ -13,6 +11,4 @@ exercises/slf_incr2.verif.c --8<-- ``` - -Explain `split-case` in detail and give more examples... - +{{ todo("Explain `split-case` in detail and give more examples...") }} diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 7f520520..432e90cb 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -9,11 +9,11 @@ This tutorial introduces CN through a series of examples and case studies, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. - +") }} CN can be used in two distinct ways: - The simpler way is as a framework for writing down formal diff --git a/src/example-archive/c-testsuite/broken/error-cerberus/00176.err2.c b/src/example-archive/c-testsuite/broken/error-cerberus/00176.err2.c index 5cc08bd9..bf66bff4 100644 --- a/src/example-archive/c-testsuite/broken/error-cerberus/00176.err2.c +++ b/src/example-archive/c-testsuite/broken/error-cerberus/00176.err2.c @@ -68,14 +68,14 @@ int main() for (i = 0; i < 16; i++) printf("%d ", array[i]); - printf("\n"); + printf(""); quicksort(0, 15); for (i = 0; i < 16; i++) printf("%d ", array[i]); - printf("\n"); + printf(""); return 0; } diff --git a/src/example-archive/c-testsuite/broken/error-cerberus/00181.err2.c b/src/example-archive/c-testsuite/broken/error-cerberus/00181.err2.c index 7c0893b1..deb3f229 100644 --- a/src/example-archive/c-testsuite/broken/error-cerberus/00181.err2.c +++ b/src/example-archive/c-testsuite/broken/error-cerberus/00181.err2.c @@ -51,15 +51,15 @@ void PrintAll() printf("A: "); for(i=0;i Date: Tue, 1 Apr 2025 09:54:23 -0400 Subject: [PATCH 091/158] Couple more macros --- docs/getting-started/tutorials/verif-numeric.md | 4 ++-- docs/getting-started/tutorials/welcome.md | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 6a957182..ac4ce2b9 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -29,7 +29,7 @@ exercises/add_0.c:3:10: error: Undefined behaviour return x+y; ~^~ an exceptional condition occurs during the evaluation of an expression (§6.5#5) -Consider the state in /var/folders/\_v/ndl32rvc8ph0000gn/T/state_393431.html +Consider the state in /.../state_393431.html ``` CN rejects the program because it has _undefined behaviour_ according to the C standard, meaning it is not safe to execute. CN points to the relevant source location, the addition `x+y`, and paragraph §6.5#5 of the standard, which specifies the undefined behaviour. It also includes a link to an HTML file with more details on the error to help in diagnosing the problem. @@ -238,7 +238,7 @@ solutions/slf1_basic_example_let.signed.c --8<-- ``` -{{ todo("BCP: WHy n*+n\_ in some places and n\*2i32 in others? ") }} +{{ todo("BCP: WHy n*+n\ _ in some places and n\*2i32 in others? ") }} {{ todo("Dhruv: Unlikely to be meaningful, either is fine. ") }} We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 432e90cb..80ba75bb 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -9,11 +9,8 @@ This tutorial introduces CN through a series of examples and case studies, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. -{{ todo(" -BCP: Once the structure of the tutorial stabilizes, we - could outline the material it covers in more detail... - -") }} +{{ later("BCP: Once the structure of the tutorial stabilizes, we + could outline the material it covers in more detail...") }} CN can be used in two distinct ways: - The simpler way is as a framework for writing down formal From aa46282ccd9a6937df53b470b424e17120435ea6 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 09:57:59 -0400 Subject: [PATCH 092/158] Nit --- docs/getting-started/tutorials/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index ebdfdb31..da0f64ed 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -42,8 +42,6 @@ - [TODO list and discussion](todo.md) -## OLD STUFF - From dff61d829c1633c565e6491101da52345306ffc4 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 10:05:56 -0400 Subject: [PATCH 093/158] More macroizing --- docs/getting-started/tutorials/morestuff.md | 2 +- docs/getting-started/tutorials/pointers.md | 4 ++-- docs/getting-started/tutorials/verif-basics.md | 2 +- docs/getting-started/tutorials/verif-external.md | 6 +++--- docs/getting-started/tutorials/verif-lists.md | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/getting-started/tutorials/morestuff.md b/docs/getting-started/tutorials/morestuff.md index 6c8ec790..d2e6d22b 100644 --- a/docs/getting-started/tutorials/morestuff.md +++ b/docs/getting-started/tutorials/morestuff.md @@ -15,7 +15,7 @@ exercises/ref.h --8<-- ``` -{{ todo("TODO: BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does...") }} +{{ todo("BCP: This example is a bit broken: the file `slf0_basic_incr.c` does not appear at all in the tutorial, though a slightly different version (with signed numbers) does...") }} ```c title="exercises/slf16_basic_succ_using_incr.c" --8<-- diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 4dc4cc89..603006e5 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -126,7 +126,7 @@ exercises/read2.c ∀v1. { p ↦ P } read(p) - { \return. ∃P_post. (p ↦ P_post) /\ return = P /\ P = P_post } + { \return. ∃P_post. (p ↦ P_post) and return = P and P = P_post } ``` CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. @@ -292,5 +292,5 @@ how one may need to destructure the type (unions, struct fields and padding, arrays). The relationship is that for `take x = RW(expr)` we have `expr : pointer, x : to_basetype(ct)`. ") }} -{{ todo("TODO: It would be nice to add an exercise that involves +{{ todo("It would be nice to add an exercise that involves using the error messages to find a bug.") }} diff --git a/docs/getting-started/tutorials/verif-basics.md b/docs/getting-started/tutorials/verif-basics.md index b6dd5c74..8004aa7d 100644 --- a/docs/getting-started/tutorials/verif-basics.md +++ b/docs/getting-started/tutorials/verif-basics.md @@ -29,5 +29,5 @@ the code until it either succeeds in constructing a formal proof that the function satisfies the specification, or it encounters a constraint that cannot be satisfied. -{{ later("TODO: What else do we need to talk about in this introductory +{{ later("What else do we need to talk about in this introductory section??") }} diff --git a/docs/getting-started/tutorials/verif-external.md b/docs/getting-started/tutorials/verif-external.md index 2b6bc624..633d168d 100644 --- a/docs/getting-started/tutorials/verif-external.md +++ b/docs/getting-started/tutorials/verif-external.md @@ -6,7 +6,7 @@ looks like on the Coq side! ") }} {{ todo("BCP: This needs to be filled in urgently!! ") }} {{ todo(" Dhruyv: There are some examples in the Cerberus repo tests? rems-project/cerberus@20d9d5c ") }} -{{ todo("TODO: BCP: +{{ todo("BCP: think about capitalization, etc., for lemma names push_lemma should be Push_lemma, I guess? Or lemma_push? snoc_facts should be lemma_Snoc or something @@ -44,7 +44,7 @@ Having stated these lemmas, we can now complete the specification and proof of `IntList_rev`. Note the two places where `apply` is used to tell the SMT solver where to pay attention to the lemmas. -{{ todo("TODO: BCP: Why can't it always pay attention to them? (I guess +{{ todo("BCP: Why can't it always pay attention to them? (I guess 'performance', but at least it would be nice to be able to declare a general scope where a given set of lemmas might be needed, rather than specifying exactly where to use them.)") }} @@ -84,7 +84,7 @@ exercises/slf_sized_stack.c ## More on CN Annotations -{{ todo("TODO: Introduce all the different sorts of CN annotations (e.g., +{{ todo("Introduce all the different sorts of CN annotations (e.g., `split_case`) individually with small examples and exercises.") }} diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index 323815cc..992cd7c3 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -59,7 +59,7 @@ exercises/list/headers.verif.h --8<-- ``` -{{ todo("TODO: BCP: The 'return != NULL' should not be needed, but to remove it +{{ todo("BCP: The 'return != NULL' should not be needed, but to remove it we need to change the callers of all the allocation functions to check for NULL and exit (which requires adding a spec for exit).") }} From 8a818cd4471e61e4c6601ce99fe0c62eab4eae7c Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 10:07:27 -0400 Subject: [PATCH 094/158] Remove very old tutorial --- src/old/asciidoc_to_md.md | 53 - src/old/asciidoctor.css | 424 ------- src/old/setup.m4 | 8 - src/old/style.css | 44 - src/old/tutorial.md | 2271 ------------------------------------- 5 files changed, 2800 deletions(-) delete mode 100644 src/old/asciidoc_to_md.md delete mode 100644 src/old/asciidoctor.css delete mode 100644 src/old/setup.m4 delete mode 100644 src/old/style.css delete mode 100644 src/old/tutorial.md diff --git a/src/old/asciidoc_to_md.md b/src/old/asciidoc_to_md.md deleted file mode 100644 index 9b65383d..00000000 --- a/src/old/asciidoc_to_md.md +++ /dev/null @@ -1,53 +0,0 @@ -# Converting ASCIIDOC to MD - -This tutorial was previously written using -[AsciiDoctor](https://asciidoctor.org). In order to preserve comments, we -manually converted from AsciiDoc to markdown. The following steps were applied -by hand. - -1. Remove `[abstract]\n--` -1. Remove metadata `:...:.*$` lines -1. Convert headers `=` -> `#` -1. Convert links `https://link.me[name]` -> `[name](https://link.me)` -1. Convert inline code `` `+...+` `` -> `` `...` `` -1. Convert code blocks `....` -> `` ``` `` -1. Convert include directives `include_example(path/to/file)` - ``` - - ` ` `c title="path/to/file" - - - 8 < - - - path/to/file - - - 8 < - - - ` ` ` - - ``` -1. Convert comments `//...` -> `` -1. Convert comment blocks - ``` - //// - comments... - //// - ``` - to - ``` - -1. Convert images `image::path/to/image[title]` -> `???` -1. Convert enumerated lists `. text` -> `1. text` -1. Convert code blocks - ``` - [source,c] - ---- - code - ---- - ``` -1. Convert indented list items - ``` - * list item with the following indented code W - + - [source,c] - ---- - code - ---- - ``` diff --git a/src/old/asciidoctor.css b/src/old/asciidoctor.css deleted file mode 100644 index 578ee416..00000000 --- a/src/old/asciidoctor.css +++ /dev/null @@ -1,424 +0,0 @@ -/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */ -/* Uncomment the following line when using as a custom stylesheet */ -/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */ -html{font-family:sans-serif;-webkit-text-size-adjust:100%} -a{background:none} -a:focus{outline:thin dotted} -a:active,a:hover{outline:0} -h1{font-size:2em;margin:.67em 0} -b,strong{font-weight:bold} -abbr{font-size:.9em} -abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none} -dfn{font-style:italic} -hr{height:0} -mark{background:#ff0;color:#000} -code,kbd,pre,samp{font-family:monospace;font-size:1em} -pre{white-space:pre-wrap} -q{quotes:"\201C" "\201D" "\2018" "\2019"} -small{font-size:80%} -sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} -sup{top:-.5em} -sub{bottom:-.25em} -img{border:0} -svg:not(:root){overflow:hidden} -figure{margin:0} -audio,video{display:inline-W} -audio:not([controls]){display:none;height:0} -fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} -legend{border:0;padding:0} -button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} -button,input{line-height:normal} -button,select{text-transform:none} -button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} -button[disabled],html input[disabled]{cursor:default} -input[type=checkbox],input[type=radio]{padding:0} -button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} -textarea{overflow:auto;vertical-align:top} -table{border-collapse:collapse;border-spacing:0} -*,::before,::after{box-sizing:border-box} -html,body{font-size:100%} -body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} -a:hover{cursor:pointer} -img,object,embed{max-width:100%;height:auto} -object,embed{height:100%} -img{-ms-interpolation-mode:bicubic} -.left{float:left!important} -.right{float:right!important} -.text-left{text-align:left!important} -.text-right{text-align:right!important} -.text-center{text-align:center!important} -.text-justify{text-align:justify!important} -.hide{display:none} -img,object,svg{display:inline-W;vertical-align:middle} -textarea{height:auto;min-height:50px} -select{width:100%} -.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} -div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0} -a{color:#2156a5;text-decoration:underline;line-height:inherit} -a:hover,a:focus{color:#1d4b8f} -a img{border:0} -p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} -p aside{font-size:.875em;line-height:1.35;font-style:italic} -h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} -h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} -h1{font-size:2.125em} -h2{font-size:1.6875em} -h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} -h4,h5{font-size:1.125em} -h6{font-size:1em} -hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em} -em,i{font-style:italic;line-height:inherit} -strong,b{font-weight:bold;line-height:inherit} -small{font-size:60%;line-height:inherit} -code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} -ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} -ul,ol{margin-left:1.5em} -ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0} -ul.circle{list-style-type:circle} -ul.disc{list-style-type:disc} -ul.square{list-style-type:square} -ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit} -ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} -dl dt{margin-bottom:.3125em;font-weight:bold} -dl dd{margin-bottom:1.25em} -blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} -blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} -@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} -h1{font-size:2.75em} -h2{font-size:2.3125em} -h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} -h4{font-size:1.4375em}} -table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal} -table thead,table tfoot{background:#f7f8f7} -table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} -table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} -table tr.even,table tr.alt{background:#f8f8f7} -table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6} -h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} -h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} -.center{margin-left:auto;margin-right:auto} -.stretch{width:100%} -.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} -.clearfix::after,.float-group::after{clear:both} -:not(pre).nobreak{word-wrap:normal} -:not(pre).nowrap{white-space:nowrap} -:not(pre).pre-wrap{white-space:pre-wrap} -:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} -pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} -pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} -pre>code{display:W} -pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} -em em{font-style:normal} -strong strong{font-weight:400} -.keyseq{color:rgba(51,51,51,.8)} -kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-W;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} -.keyseq kbd:first-child{margin-left:0} -.keyseq kbd:last-child{margin-right:0} -.menuseq,.menuref{color:#000} -.menuseq b:not(.caret),.menuref{font-weight:inherit} -.menuseq{word-spacing:-.02em} -.menuseq b.caret{font-size:1.25em;line-height:.8} -.menuseq i.caret{font-weight:bold;text-align:center;width:.45em} -b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} -b.button::before{content:"[";padding:0 3px 0 2px} -b.button::after{content:"]";padding:0 2px 0 3px} -p a>code:hover{color:rgba(0,0,0,.9)} -#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} -#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} -#header::after,#content::after,#footnotes::after,#footer::after{clear:both} -#content{margin-top:1.25em} -#content::before{content:none} -#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} -#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} -#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} -#header .details span:first-child{margin-left:-.125em} -#header .details span.email a{color:rgba(0,0,0,.85)} -#header .details br{display:none} -#header .details br+span::before{content:"\00a0\2013\00a0"} -#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} -#header .details br+span#revremark::before{content:"\00a0|\00a0"} -#header #revnumber{text-transform:capitalize} -#header #revnumber::after{content:"\00a0"} -#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} -#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} -#toc>ul{margin-left:.125em} -#toc ul.sectlevel0>li>a{font-style:italic} -#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} -#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} -#toc li{line-height:1.3334;margin-top:.3334em} -#toc a{text-decoration:none} -#toc a:active{text-decoration:underline} -#toctitle{color:#7a2518;font-size:1.2em} -@media screen and (min-width:768px){#toctitle{font-size:1.375em} -body.toc2{padding-left:15em;padding-right:0} -body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} -#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} -#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} -#toc.toc2>ul{font-size:.9em;margin-bottom:0} -#toc.toc2 ul ul{margin-left:0;padding-left:1em} -#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} -body.toc2.toc-right{padding-left:0;padding-right:15em} -body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} -@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} -#toc.toc2{width:20em} -#toc.toc2 #toctitle{font-size:1.375em} -#toc.toc2>ul{font-size:.95em} -#toc.toc2 ul ul{padding-left:1.25em} -body.toc2.toc-right{padding-left:0;padding-right:20em}} -#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px} -#content #toc>:first-child{margin-top:0} -#content #toc>:last-child{margin-bottom:0} -#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em} -#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44} -#content{margin-bottom:.625em} -.sect1{padding-bottom:.625em} -@media screen and (min-width:768px){#content{margin-bottom:1.25em} -.sect1{padding-bottom:1.25em}} -.sect1:last-child{padding-bottom:0} -.sect1+.sect1{border-top:1px solid #e7e7e9} -#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:W;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} -#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:W;padding-top:.1em} -#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} -#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} -#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} -details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} -details{margin-left:1.25rem} -details>summary{cursor:pointer;display:W;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent} -details>summary::-webkit-details-marker{display:none} -details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)} -details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)} -details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem} -.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} -table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} -.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} -.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} -.admonitionblock>table td.icon{text-align:center;width:80px} -.admonitionblock>table td.icon img{max-width:none} -.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} -.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere} -.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} -.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px} -.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px} -.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} -.exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0} -.exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} -.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em} -@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}} -@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}} -.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8} -.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} -.listingblock>.content{position:relative} -.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5} -.listingblock:hover code[data-lang]::before{display:W} -.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} -.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} -.listingblock pre.highlightjs{padding:0} -.listingblock pre.highlightjs>code{padding:1em;border-radius:4px} -.listingblock pre.prettyprint{border-width:0} -.prettyprint{background:#f7f7f8} -pre.prettyprint .linenums{line-height:1.45;margin-left:2em} -pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0} -pre.prettyprint li code[data-lang]::before{opacity:1} -pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none} -table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none} -table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal} -table.linenotable td.code{padding-left:.75em} -table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} -pre.pygments span.linenos{display:inline-W;margin-right:.75em} -.quoteblock{margin:0 1em 1.25em 1.5em;display:table} -.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em} -.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} -.quoteblock blockquote{margin:0;padding:0;border:0} -.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} -.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} -.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} -.verseblock{margin:0 1em 1.25em} -.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} -.verseblock pre strong{font-weight:400} -.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} -.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} -.quoteblock .attribution br,.verseblock .attribution br{display:none} -.quoteblock .attribution cite,.verseblock .attribution cite{display:W;letter-spacing:-.025em;color:rgba(0,0,0,.6)} -.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} -.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} -.quoteblock.abstract{margin:0 1em 1.25em;display:W} -.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} -.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf} -.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0} -.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} -.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0} -p.tableblock:last-child{margin-bottom:0} -td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere} -td.tableblock>.content>:last-child{margin-bottom:-1.25em} -table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} -table.grid-all>*>tr>*{border-width:1px} -table.grid-cols>*>tr>*{border-width:0 1px} -table.grid-rows>*>tr>*{border-width:1px 0} -table.frame-all{border-width:1px} -table.frame-ends{border-width:1px 0} -table.frame-sides{border-width:0 1px} -table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0} -table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0} -table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0} -table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0} -table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7} -th.halign-left,td.halign-left{text-align:left} -th.halign-right,td.halign-right{text-align:right} -th.halign-center,td.halign-center{text-align:center} -th.valign-top,td.valign-top{vertical-align:top} -th.valign-bottom,td.valign-bottom{vertical-align:bottom} -th.valign-middle,td.valign-middle{vertical-align:middle} -table thead th,table tfoot th{font-weight:bold} -tbody tr th{background:#f7f8f7} -tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} -p.tableblock>code:only-child{background:none;padding:0} -p.tableblock{font-size:1em} -ol{margin-left:1.75em} -ul li ol{margin-left:1.5em} -dl dd{margin-left:1.125em} -dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} -li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} -ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} -ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} -ul.unstyled,ol.unstyled{margin-left:0} -li>p:empty:only-child::before{content:"";display:inline-W} -ul.checklist>li>p:first-child{margin-left:-1em} -ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} -ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em} -ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} -ul.inline>li{margin-left:1.25em} -.unstyled dl dt{font-weight:400;font-style:normal} -ol.arabic{list-style-type:decimal} -ol.decimal{list-style-type:decimal-leading-zero} -ol.loweralpha{list-style-type:lower-alpha} -ol.upperalpha{list-style-type:upper-alpha} -ol.lowerroman{list-style-type:lower-roman} -ol.upperroman{list-style-type:upper-roman} -ol.lowergreek{list-style-type:lower-greek} -.hdlist>table,.colist>table{border:0;background:none} -.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} -td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} -td.hdlist1{font-weight:bold;padding-bottom:1.25em} -td.hdlist2{word-wrap:anywhere} -.literalblock+.colist,.listingblock+.colist{margin-top:-.5em} -.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} -.colist td:not([class]):first-child img{max-width:none} -.colist td:not([class]):last-child{padding:.25em 0} -.thumb,.th{line-height:0;display:inline-W;border:4px solid #fff;box-shadow:0 0 0 1px #ddd} -.imageblock.left{margin:.25em .625em 1.25em 0} -.imageblock.right{margin:.25em 0 1.25em .625em} -.imageblock>.title{margin-bottom:0} -.imageblock.thumb,.imageblock.th{border-width:6px} -.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} -.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-W;line-height:0} -.image.left{margin-right:.625em} -.image.right{margin-left:.625em} -a.image{text-decoration:none;display:inline-W} -a.image object{pointer-events:none} -sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} -sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} -#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} -#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} -#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} -#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} -#footnotes .footnote:last-of-type{margin-bottom:0} -#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} -div.unbreakable{page-break-inside:avoid} -.big{font-size:larger} -.small{font-size:smaller} -.underline{text-decoration:underline} -.overline{text-decoration:overline} -.line-through{text-decoration:line-through} -.aqua{color:#00bfbf} -.aqua-background{background:#00fafa} -.black{color:#000} -.black-background{background:#000} -.blue{color:#0000bf} -.blue-background{background:#0000fa} -.fuchsia{color:#bf00bf} -.fuchsia-background{background:#fa00fa} -.gray{color:#606060} -.gray-background{background:#7d7d7d} -.green{color:#006000} -.green-background{background:#007d00} -.lime{color:#00bf00} -.lime-background{background:#00fa00} -.maroon{color:#600000} -.maroon-background{background:#7d0000} -.navy{color:#000060} -.navy-background{background:#00007d} -.olive{color:#606000} -.olive-background{background:#7d7d00} -.purple{color:#600060} -.purple-background{background:#7d007d} -.red{color:#bf0000} -.red-background{background:#fa0000} -.silver{color:#909090} -.silver-background{background:#bcbcbc} -.teal{color:#006060} -.teal-background{background:#007d7d} -.white{color:#bfbfbf} -.white-background{background:#fafafa} -.yellow{color:#bfbf00} -.yellow-background{background:#fafa00} -span.icon>.fa{cursor:default} -a span.icon>.fa{cursor:inherit} -.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} -.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} -.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} -.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} -.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} -.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} -.conum[data-value]{display:inline-W;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} -.conum[data-value] *{color:#fff!important} -.conum[data-value]+b{display:none} -.conum[data-value]::after{content:attr(data-value)} -pre .conum[data-value]{position:relative;top:-.125em} -b.conum *{color:inherit!important} -.conum:not([data-value]):empty{display:none} -dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} -h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em} -p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} -p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem} -p{margin-bottom:1.25rem} -.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} -.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc} -.print-only{display:none!important} -@page{margin:1.25cm .75cm} -@media print{*{box-shadow:none!important;text-shadow:none!important} -html{font-size:80%} -a{color:inherit!important;text-decoration:underline!important} -a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} -a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-W;font-size:.875em;padding-left:.25em} -abbr[title]{border-bottom:1px dotted} -abbr[title]::after{content:" (" attr(title) ")"} -pre,blockquote,tr,img,object,svg{page-break-inside:avoid} -thead{display:table-header-group} -svg{max-width:100%} -p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} -h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} -#header,#content,#footnotes,#footer{max-width:none} -#toc,.sidebarblock,.exampleblock>.content{background:none!important} -#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} -body.book #header{text-align:center} -body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} -body.book #header .details{border:0!important;display:W;padding:0!important} -body.book #header .details span:first-child{margin-left:0!important} -body.book #header .details br{display:W} -body.book #header .details br+span::before{content:none!important} -body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} -body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} -.listingblock code[data-lang]::before{display:W} -#footer{padding:0 .9375em} -.hide-on-print{display:none!important} -.print-only{display:W!important} -.hide-for-print{display:none!important} -.show-for-print{display:inherit!important}} -@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem} -.sect1{padding:0!important} -.sect1+.sect1{border:0} -#footer{background:none} -#footer-text{color:rgba(0,0,0,.6);font-size:.9em}} -@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} \ No newline at end of file diff --git a/src/old/setup.m4 b/src/old/setup.m4 deleted file mode 100644 index eda26ac7..00000000 --- a/src/old/setup.m4 +++ /dev/null @@ -1,8 +0,0 @@ -changequote(`{{',`}}') - -define({{prefix_filename}},// {{$1}} -{{$2}}) - -define({{include_example}},```c -{{prefix_filename($1,builtin(include,$1))}} -```) diff --git a/src/old/style.css b/src/old/style.css deleted file mode 100644 index 1669a8c7..00000000 --- a/src/old/style.css +++ /dev/null @@ -1,44 +0,0 @@ -@import "asciidoctor.css"; - -body { - max-width: 1100px; - /* margin: auto; */ - font-family: sans-serif; - // font-size: 18px; -} - -#preamble .sectionbody .paragraph p { - // font-size: 18px; -} - -// h1 { font-size: 32px; margin-top: 4em; } -// h2 { font-size: 26px; margin-top: 2em; } -// h3 { font-size: 22px; margin-top: 2em; } - -h1, h2, h3, h4, h5 { - color: hsl(219, 50%, 50%); - font-family: sans-serif; - font-weight: bold; -} - -#toctitle { - color: black; -} - -.listingblock .title, .imageblock .title { - font-family: sans-serif; -} - -.sect1 { border-top-width: 0px; } - -body > .sourceCode { - padding: 5px; - border-radius: 5px; - border: 1px solid hsl(44, 7%, 80%); - background-color: hsl(44, 7%, 96%); -} - -.quoteblock.abstract p { - font-style: normal; - text-align: left; -} diff --git a/src/old/tutorial.md b/src/old/tutorial.md deleted file mode 100644 index c0de0f8e..00000000 --- a/src/old/tutorial.md +++ /dev/null @@ -1,2271 +0,0 @@ -# CN tutorial - -_By Christopher Pulte and Benjamin C. Pierce, with contributions from Elizabeth Austell._ - -CN is an extension of the C programming language for verifying the correctness of C code, especially on low-level systems code. Compared to standard C, CN checks not only that expressions and statements follow the correct typing discipline for C-types, but also that the C code executes _safely_ — does not raise C undefined behaviour — and _correctly_ — satisfying to strong, user-defined specifications. -This tutorial introduces CN through a series of examples, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. - -This tutorial is a work in progress -- your suggestions are greatly appreciated! - -**Origins.** -CN was first described in [CN: Verifying Systems C Code with Separation-Logic Refinement Types](https://dl.acm.org/doi/10.1145/3571194) by Christopher Pulte, Dhruv C. Makwana, Thomas Sewell, Kayvan Memarian, Peter Sewell, and Neel Krishnaswami. -To accurately handle the complex semantics of C, CN builds on the [Cerberus semantics for C](https://github.com/rems-project/cerberus/). -Some of the examples in this tutorial are adapted from Arthur Charguéraud’s excellent -[Separation Logic Foundations](https://softwarefoundations.cis.upenn.edu) textbook, and one of the case studies is based on an -extended exercise due to Bryan Parno. - --- - -**Acknowledgment of Support and Disclaimer.** -This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). - -## Installing CN - -To fetch and install CN, visit the [Cerberus repository](https://github.com/rems-project/cerberus) and follow the instructions in [backend/cn/README.md](https://github.com/rems-project/cerberus/blob/master/backend/cn/README.md). - -Once the installation is completed, type `cn --help` in your terminal to ensure CN is installed and found by your system. This should print the list of available options CN can be executed with. - -To apply CN to a C file, run `cn verify CFILE`. - -## Source files - -The source files for all the exercises and examples below can be downloaded -from [here](link:exercises.zip). - -## Basics - -### First example - -The simple arithmetic function: `add` shown below takes two `int` arguments, `x` and `y`, and returns their sum. - -```c title="exercises/add_0.c" ---8<-- -exercises/add_0.c ---8<-- -``` - -Running CN on the example produces an error message: - -``` -cn verify exercises/add_0.c -[1/1]: add -exercises/add_0.c:3:10: error: Undefined behaviour -return x+y; -~^~ -an exceptional condition occurs during the evaluation of an expression (§6.5#5) -Consider the state in /var/folders/\_v/ndl32rvc8ph0000gn/T/state_393431.html -``` - -CN rejects the program because it has _undefined behaviour_ according to the C standard, meaning it is not safe to execute. CN points to the relevant source location, the addition `x+y`, and paragraph §6.5#5 of the standard, which specifies the undefined behaviour. It also includes a link to an HTML file with more details on the error to help in diagnosing the problem. - -Inspecting this HTML report (as we do in a moment) gives us possible example values for `x` and `y` that cause the undefined behaviour and hint at the problem: for very large values for `x` and `y`, such as `1073741825` and `1073741824`, the sum of `x` and `y` can exceed the representable range of a C `int` value: `1073741825 + 1073741824 = 2^31+1`, so their sum is larger than the maximal `int` value, `2^31-1`. - -Here `x` and `y` are _signed integers_, and in C, signed integer _overflow_ is undefined behaviour (UB). Hence, `add` is only safe to execute for smaller values. Similarly, _large negative_ values of `x` and `y` can cause signed integer _underflow_, also UB in C. We therefore need to rule out too-large values for `x` and `y`, both positive and negative, which we do by writing a CN function specification. - -### First function specification - -Shown below is our first function specification, for `add`, with a precondition that constrains `x` and `y` such that the sum of `x` and `y` lies between `-2147483648` and `2147483647`, so within the representable range of a C `int` value. - -```c title="solutions/add_0.c" ---8<-- -solutions/add_0.c ---8<-- -``` - -In detail: - -- Function specifications are given using special `/*@ ... @*/` comments, placed in-between the function argument list and the function body. - - - -- The keyword `requires` starts the precondition, a list of one or more CN conditions separated by semicolons. - -- In function specifications, the names of the function arguments, here `x` and `y`, refer to their _initial values_. (Function arguments are mutable in C.) - -- `let Sum = (i64) x + (i64) y` is a let-binding, which defines `Sum` as the value `(i64) x + (i64) y` in the remainder of the function specification. - -- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`. - - - -- To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. - -- Finally, we require this sum to be between the minimal and maximal `int` values. Integer constants, such as `-2147483648i64`, must specifiy their CN type (`i64`). - - - -Running CN on the annotated program passes without errors. This means that, with our specified precondition, `add` is safe to execute. - -We may, however, wish to be more precise. So far, the specification gives no information to callers of `add` about its output. To describe its return value we add a postcondition to the specification using the `ensures` keyword. - -```c title="solutions/add_1.c" ---8<-- -solutions/add_1.c ---8<-- -``` - -Here we use the keyword `return`, which is only available in function -postconditions, to refer to the return value, and we equate it to `Sum` -as defined in the precondition, cast back to `i32` type: that is, `add` -returns the sum of `x` and `y`. - -Running CN confirms that this postcondition also holds. - -One final refinement of this example. CN defines constant functions `MINi32`, `MAXi64`, etc. so that specifications do not need to be littered with unreadable numeric constants. - -```c title="solutions/add_2.c" ---8<-- -solutions/add_2.c ---8<-- -``` - -Two things to note: (1) These are constant _functions_, so they -require a following `()`. And (2) The type of `MINi32()` is `i32`, so -if we want to use it as a 64-bit constant we need to add the explicit -coercion `(i64)`. - -### Error reports - -In the original example, CN reported a type error due to C undefined -behaviour. While that example was perhaps simple enough to guess the -problem and solution, this can become quite challenging as program and -specification complexity increases. Diagnosing errors is -therefore an important part of using CN. CN tries to help with this by -producing detailed error information, in the form of an HTML error -report. - -Let’s return to the type error from earlier -- `add` without -precondition -- and take a closer look at this report. - -_CN error report_ -![*CN error report: 0*](images/0_error.png) - -_Definitions and constraints not handled automatically_ - -CN checks that the code matches its specification with the help of an SMT -solver. CN passes a set of constraints along with program context to the SMT -solver, which either confirms that a given constraint will always hold in -that program context, provides a counterexample in which the constraint does -not hold, or times out. To avoid timeouts, CN avoids passing some definitions -to the solver, including recursive functions, some predicates with branching, -and constraints with `forall`. The error file displays in this section which -definitions and constraints CN did not pass to the solver. - -_Resources that do not satisfy predicate definitions_ - -Because CN does not pass certain definitions to the solver, it may return -spurious counterexamples that do not respect those definitions. Consider this -example: - -![*CN error report: string*](images/string_error.png) - -`String` is a predicate representing a null-terminated string. -In general, CN does not know how much to unfold the mutually recursive -predicates `String` and `StringAux`, so it does not pass their full -definition to the solver. This leads to a spurious counterexample: `sIn` is the -singleton string containing exactly the null character `0u8`. This is -impossible; the predicate leaves out the null when constructing the logical -representation of a string. To make clear that this is a bad counterexample, -the error file lists `String(s) (sIn)` under _Resources that do not satisfy -predicate definitions_. - - - -_Path to error._ The first section contains information about the -control-flow path leading to the error. - -When checking a C function, CN examines each possible control-flow -path individually. If it detects UB or a violation of user-defined -specifications, CN reports the problematic control-flow path as a -nested structure of statements: the path is split into sections that -group together statements between high-level control-flow positions -(e.g. function entry, the start of a loop, the invocation of a -`continue`, `break`, or `return` statement, etc.); within each -section, statements are listed by source code location; finally, per -statement, CN lists the typechecked sub-expressions, and the memory -accesses and function calls within these. - -In our example, there is only one possible control-flow path: entering -the function body (section "`function body`") and executing the W -from lines 2 to 4, followed by the return statement at line 3. The -entry for the latter contains the sequence of sub-expressions in the -return statement, including reads of the variables `x` and `y`. - -In C, local variables in a function, including its arguments, are -mutable, their addresses can be taken and passed as values. CN -therefore represents local variables as memory allocations that are -manipulated using memory reads and writes. Here, type checking the -return statement includes checking memory reads for `x` and `y`, -at their locations `&ARG0` and `&ARG1`. The path report lists -these reads and their return values: the read at `&ARG0` returns -`x` (that is, the value of `x` originally passed to `add`); the -read at `&ARG1` returns `y`. Alongside this symbolic information, -CN displays concrete values: - -- `1073741825i32 /* 0x40000001 */` for x (the first value is the decimal representation, the second, in `/*...*/` comments, the hex equivalent) and - -- `1073741824i32 /* 0x40000000 */` for `y`. - -For now, ignore the pointer values `{@0; 4}` for `x` and `{@0; 0}` for `y`. - - - - -These concrete values are part of a _counterexample_: a concrete -valuation of variables and pointers in the program that that leads to -the error. (The exact values may vary on your machine, depending on -the SMT solver -- i.e., the particular version of Z3, CVC5, or -whatever installed on your system.) - -_Proof context._ The second section, below the error trace, lists the proof context CN has reached along this control-flow path. - -"`Available resources`" lists the RW resources, as discussed in later sections. - -"`Variables`" lists counterexample values for program variables and pointers. In addition to `x` and `y`, assigned the same values as above, this includes values for their memory locations `&ARG0` and `&ARG1`, function pointers in scope, and the `__cn_alloc_history`, all of which we ignore for now. - - - - -Finally, "`Constraints`" records all logical facts CN has learned along the path. This includes user-specified assumptions from preconditions or loop invariants, value ranges inferred from the C-types of variables, and facts learned during the type checking of the statements. Here -- when checking `add` without precondition -- the only constraints are those inferred from C-types in the code: - -- For instance, `good(x)` says that the initial value of - `x` is a "`good`" `signed int` value (i.e. in range). Here - `signed int` is the same type as `int`, CN just makes the sign - explicit. - - - For an integer type `T`, the type `good` requires the value to - be in range of type `T`; for pointer types `T`, it also requires - the pointer to be aligned. For structs and arrays, this extends in the - obvious way to struct members or array cells. - - -- `repr` requires representability (not alignment) at type `T`, so `repr(&ARGO)`, for instance, records that the pointer to `x` is representable at C-type `signed int*`; - -- `aligned(&ARGO, 4u64)`, moreover, states that it is 4-byte aligned. - - - - - - -### Another arithmetic example - -Let’s apply what we know so far to another simple arithmetic example. - -The function `doubled`, shown below, takes an int `n`, defines `a` as `n` incremented, `b` as `n` decremented, and returns the sum of the two. - - - -```c title="exercises/slf1_basic_example_let.signed.c" ---8<-- -exercises/slf1_basic_example_let.signed.c ---8<-- -``` - -We would like to verify this is safe, and that `doubled` returns twice the value of `n`. Running CN on `doubled` leads to a type error: the increment of `a` has undefined behaviour. - -As in the first example, we need to ensure that `n+1` does not overflow and `n-1` does not underflow. Similarly `a+b` has to be representable at `int` type. - -```c title="solutions/slf1_basic_example_let.signed.c" ---8<-- -solutions/slf1_basic_example_let.signed.c ---8<-- -``` - - - - -We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. - - - - - -To capture the functional behaviour, the postcondition specifies that `return` is twice the value of `n`. - -### Exercises - -_Quadruple._ Specify the precondition needed to ensure safety of the C function `quadruple`, and a postcondition that describes its return value. - -```c title="exercises/slf2_basic_quadruple.signed.c" ---8<-- -exercises/slf2_basic_quadruple.signed.c ---8<-- -``` - -_Abs._ Give a specification to the C function `abs`, which computes the absolute value of a given `int` value. To describe the return value, use CN’s ternary "`_ ? _ : _`" operator. Given a boolean `b`, and expressions `e1` and `e2` of the same basetype, `b ? e1 : e2` returns `e1` if `b` holds and `e2` otherwise. -Note that most binary operators in CN have higher precedence than the ternary operator, so depending on your solution you may need to place the ternary expression in parentheses. - -```c title="exercises/abs.c" ---8<-- -exercises/abs.c ---8<-- -``` - -## Pointers and simple ownership - -So far we’ve only considered example functions manipulating integer values. Verification becomes more interesting and challenging when _pointers_ are involved, because the safety of memory accesses via pointers has to be verified. - -CN uses _separation logic resources_ and the concept of _ownership_ to reason about memory accesses. A resource is the permission to access a region of memory. Unlike logical constraints, resource ownership is _unique_, meaning resources cannot be duplicated. - -Let’s look at a simple example. The function `read` takes an `int` pointer `p` and returns the pointee value. - -```c title="exercises/read.c" ---8<-- -exercises/read.c ---8<-- -``` - -Running CN on this example produces the following error: - -``` -cn verify exercises/read.c -[1/1]: read -exercises/read.c:3:10: error: Missing resource for reading -return \*p; -^~ -Resource needed: RW(p) -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_403624.html -``` - -For the read `*p` to be safe, ownership of a resource is missing: a resource `RW(p)`. - -### RW resources - - - - - -Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts ownership of a memory cell at location `p` of the size of C-type `T`. It is CN’s equivalent of a points-to assertion in separation logic (indexed by C-types `T`). - -In this example we can ensure the safe execution of `read` by adding a precondition that requires ownership of `RW(p)`, as shown below. For now ignore the notation `take ... = RW(p)`. Since reading the pointer does not disturb its value, we also add a corresponding postcondition, whereby `read` returns ownership of `p` after it is finished executing, in the form of another `RW(p)` resource. - -```c title="solutions/read.c" ---8<-- -solutions/read.c ---8<-- -``` - -This specification means that: - -- any function calling `read` has to be able to provide a resource `RW(p)` to pass into `read`, and - -- the caller will receive back a resource `RW(p)` when `read` returns. - -### Resource outputs - -A caller of `read` may also wish to know that `read` actually returns the correct value, the pointee of `p`, and also that it does not change memory at location `p`. To phrase both we need a way to refer to the pointee of `p`. - - - -In CN, resources have _outputs_. Each resource outputs the information that can be derived from ownership of the resource. What information is returned is specific to the type of resource. A resource `RW(p)` (for some C-type `T`) outputs the _pointee value_ of `p`, since that can be derived from the resource ownership: assume you have a pointer `p` and the associated ownership, then this uniquely determines the pointee value of `p`. - - - - -CN uses the `take`-notation seen in the example above to bind the output of a resource to a new name. The precondition `take P = RW(p)` does two things: (1) it assert ownership of resource `RW(p)`, and (2) it binds the name `P` to the resource output, here the pointee value of `p` at the start of the function. Similarly, the postcondition introduces the name `P_post` for the pointee value on function return. - - - - - -That means we can use the resource outputs from the pre- and postcondition to strengthen the specification of `read` as planned. We add two new postconditions specifying - -1. that `read` returns `P` (the initial pointee value of `p`), and -1. that the pointee values `P` and `P_post` before and after execution of `read` (respectively) are the same. - -```c title="exercises/read2.c" ---8<-- -exercises/read2.c ---8<-- -``` - -_Aside._ In standard separation logic, the equivalent specification for `read` could have been phrased as follows (where `\return` binds the return value in the postcondition): - - - - - -``` -∀p. -∀v1. -{ p ↦ P } -read(p) -{ \return. ∃P_post. (p ↦ P_post) /\ return = P /\ P = P_post } -``` - -CN’s `take` notation is just an alternative syntax for quantification over the values of resources, but a useful one: the `take` notation syntactically restricts how these quantifiers can be used to ensure CN can always infer them. - -### Linear resource ownership - -In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. - -Let’s try the `read` example from earlier again, but with a postcondition that does not return the ownership: - -```c title="exercises/read.broken.c" ---8<-- -exercises/read.broken.c ---8<-- -``` - -CN rejects this program with the following message: - -``` -cn verify exercises/read.broken.c -[1/1]: read -build/exercises/read.broken.c:4:3: error: Left_Sublist-over unused resource 'RW(p)(v1)' -return \*p; -^~~~~~~~~~ -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_17eb4a.html -``` - -CN has typechecked the function and verified (1) that it is safe to -execute under the precondition (given ownership `RW(p)`) -and (2) that the function (vacuously) satisfies its postcondition. But -following the check of the postcondition it finds that not all -resources have been "`used up`". - -Indeed, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the RW memory or otherwise dispose of it. In CN this is a type error. - -CN’s resources are _linear_. This means not only that resources cannot be duplicated, but also that resources cannot simply be dropped or "`forgotten`". Every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the RW area of memory (as we shall see later). - -CN’s motivation for linear tracking of resources is its focus on -low-level systems software in which memory is managed manually; in -this context, memory leaks are typically very undesirable. As a -consequence, function specifications have to do precise bookkeeping of -their resource footprint and, in particular, return any unused -resources back to the caller. - -### Exercises - -_Quadruple_. Specify the function `quadruple_mem`, which is similar to the earlier `quadruple` function, except that the input is passed as an `int` pointer. Write a specification that takes ownership of this pointer on entry and returns this ownership on exit, leaving the pointee value unchanged. - -```c title="exercises/slf_quadruple_mem.c" ---8<-- -exercises/slf_quadruple_mem.c ---8<-- -``` - -_Abs_. Give a specification to the function `abs_mem`, which computes the absolute value of a number passed as an `int` pointer. - -```c title="exercises/abs_mem.c" ---8<-- -exercises/abs_mem.c ---8<-- -``` - -### W resources - -Aside from the `RW` resources seen so far, CN has another -built-in type of resource called `W`. Given a C-type `T` and -pointer `p`, `W(p)` asserts the same ownership as -`RW(p)` — ownership of a memory cell at `p` the size of type -`T` — but, in contrast to `RW`, `W` memory is not assumed -to be initialised. - -CN uses this distinction to prevent reads from uninitialised memory: - -- A read at C-type `T` and pointer `p` requires a resource - `RW(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `RW` resource unchanged. - -- A write at C-type `T` and pointer `p` needs only a -`W(p)` (so, unlike reads, writes to uninitialised memory -are fine). The write consumes ownership of the `W` resource -(it destroys it) and returns a new resource `RW(p)` with the -value written as the output. This means the resource returned from a -write records the fact that this memory cell is now initialised and -can be read from. - - -Since `RW` carries the same ownership as `W`, just with the -additional information that the `RW` memory is initalised, a -resource `RW(p)` is "`at least as good`" as `W(p)` — -an `RW(p)` resource can be used whenever `W(p)` is -needed. For instance CN’s type checking of a write to `p` requires a -`W(p)`, but if an `RW(p)` resource is what is -available, this can be used just the same. This allows an -already-initialised memory cell to be over-written again. - -Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. - -### Writing through pointers - -Let’s explore resources and their outputs in another example. The C function `incr` takes an `int` pointer `p` and increments the value in the memory cell that it poinbts to. - -```c title="exercises/slf0_basic_incr.signed.c" ---8<-- -exercises/slf0_basic_incr.signed.c ---8<-- -``` - -In the precondition we assert ownership of resource `RW(p)`, -binding its output/pointee value to `P`, and use `P` to specify -that `p` must point to a sufficiently small value at the start of -the function so as not to overflow when incremented. The postcondition -asserts ownership of `p` with output `P_post`, as before, and uses -this to express that the value `p` points to is incremented by -`incr`: `P_post == P + 1i32`. - -If we incorrectly tweaked this specification and used `W(p)` instead of `RW(p)` in the precondition, as below, then CN would reject the program. - -```c title="exercises/slf0_basic_incr.signed.broken.c" ---8<-- -exercises/slf0_basic_incr.signed.broken.c ---8<-- -``` - -CN reports: - -``` -build/solutions/slf0_basic_incr.signed.broken.c:6:11: error: Missing resource for reading -int n = \*p; -^~ -Resource needed: RW(p) -Consider the state in /var/folders/\_v/ndl32wpj4bb3y9dg11rvc8ph0000gn/T/state_5da0f3.html -``` - -The `RW(p)` resource required for reading is missing, since, per the precondition, only `W(p)` is available. Checking the linked HTML file confirms this. Here the section "`Available resources`" lists all resource ownership at the point of the failure: - -- `W(p)(u)`, i.e., ownership of uninitialised memory - at location `p`; the output is a `void`/`unit` value `u` - (specified in the second pair of parentheses) - -- `RW(&ARG0)(p)`, the ownership of (initialised) - memory at location `&ARG0`, i.e., the memory location where the - first function argument is stored; its output is the pointer `p` - (not to be confused with the pointee of `p`); and finally - -- `__CN_Alloc(&ARG0)(void)` is a resource that records allocation - information for location `&ARG0`; this is related to CN’s - memory-object semantics, which we ignore for the moment. - - - - -### Exercises - -_Zero._ Write a specification for the function `zero`, which takes a pointer to _uninitialised_ memory and initialises it to `0`. - -```c title="exercises/zero.c" ---8<-- -exercises/zero.c ---8<-- -``` - -_In-place double._ Give a specification for the function `inplace_double`, which takes an `int` pointer `p` and doubles the pointee value: specify the precondition needed to guarantee safe execution and a postcondition that captures the function’s behaviour. - -```c title="exercises/slf3_basic_inplace_double.c" ---8<-- -exercises/slf3_basic_inplace_double.c ---8<-- -``` - -### Multiple RW pointers - -When functions manipulate multiple pointers, we can assert their -ownership just like before. However -pointer ownership in CN is unique -- that is, simultaneously owning -`RW` or `W` resources for two pointers implies that these -pointers are disjoint. - -The following example shows the use of two `RW` resources for -accessing two different pointers by a function `add`, which reads -two `int` values in memory, at locations `p` and `q`, and -returns their sum. - - - -```c title="exercises/add_read.c" ---8<-- -exercises/add_read.c ---8<-- -``` - -OUTDATED: - -This time we use C’s `unsigned int` type. In C, over- and underflow of unsigned integers is not undefined behaviour, so we do not need any special preconditions to rule this out. Instead, when an arithmetic operation at `unsigned int` type goes outside the representable range, the value "`wraps around`". - -The CN variables `P` and `Q` (resp. `P_post` and `Q_post`) for the pointee values of `p` and `q` before (resp. after) the execution of `add` have CN basetype `u32`, so unsigned 32-bit integers, matching the C `unsigned int` type. Like C’s unsigned integer arithmetic, CN unsigned int values wrap around when exceeding the value range of the type. - -Hence, the postcondition `return == P + Q` holds also when the sum of `P` and `Q` is greater than the maximal `unsigned int` value. - - - - - -In the following we will sometimes use unsigned integer types to focus on specifying memory ownership, rather than the conditions necessary to show absence of C arithmetic undefined behaviour. - -### Exercises - -_Swap._ Specify the function `swap`, which takes two RW `unsigned int` pointers and swaps their values. - -```c title="exercises/swap.c" ---8<-- -exercises/swap.c ---8<-- -``` - -_Transfer._ Write a specification for the function `transfer`, shown below. - -```c title="exercises/slf8_basic_transfer.c" ---8<-- -exercises/slf8_basic_transfer.c ---8<-- -``` - -## Ownership of compound objects - -So far, our examples have worked with just integers and pointers, but larger programs typically also manipulate compound values, often represented using C struct types. Specifying functions manipulating structs works in much the same way as with basic types. - -For instance, the following example uses a `struct` `point` to represent a point in two-dimensional space. The function `transpose` swaps a point’s `x` and `y` coordinates. - -```c title="exercises/transpose.c" ---8<-- -exercises/transpose.c ---8<-- -``` - -Here the precondition asserts ownership for `p`, at type `struct -point`; the output `P_post` is a value of CN type `struct point`, -i.e. a record with members `i32` `x` and `i32` `y`. The -postcondition similarly asserts ownership of `p`, with output -`P_post`, and asserts the coordinates have been swapped, by referring to -the members of `P` and `P_post` individually. - - - - - -### Compound RW and W resources - -While one might like to think of a struct as a single (compound) object that is manipulated as a whole, C permits more flexible struct manipulation: given a struct pointer, programmers can construct pointers to _individual struct members_ and manipulate these as values, including even passing them to other functions. - -CN therefore cannot treat resources for compound C types like structs as primitive, indivisible units. Instead, `RW` and `W` are defined inductively on the structure of the C-type `T`. - -For struct types `T`, the `RW` resource is defined as the collection of `RW` resources for its members (as well as `W` resources for any padding bytes in-between them). The resource `W`, similarly, is made up of `W` resources for all members (and padding bytes). - -To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the member resources, and it can recompose the struct later, as needed. The following example illustrates this. - -Recall the function `zero` from our earlier exercise. It takes an `int` pointer to uninitialised memory, with `W` ownership, and initialises the value to zero, returning an `RW` resource with output `0`. - -Now consider the function `init_point`, shown below, which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. - -```c title="exercises/init_point.c" ---8<-- -exercises/init_point.c ---8<-- -``` - -As stated in its precondition, `init_point` receives ownership `W(p)`. The `zero` function, however, works on `int` pointers and requires `W` ownership. - -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `W(p)` into a `W` for member `x` and a `W` for member `y`. Later, the reverse happens: following the two calls to `zero`, as per `zero`’s precondition, `init_point` has ownership of two adjacent `RW` resources – ownership for the two struct member pointers, with the member now initialised. Since the postcondition of `init_point` requires ownership `RW(p)`, CN combines these back into a compound resource. The resulting `RW` resource has for an output the struct value `P_post` that is composed of the zeroed member values for `x` and `y`. - -### Resource inference - -To handle the required resource inference, CN "`eagerly`" decomposes all `struct` resources into resources for the struct members, and "`lazily`" re-composes them as needed. - -We can see this if, for instance, we experimentally change the `transpose` example from above to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of the `transpose` function, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) - - - -```c title="exercises/transpose.broken.c" ---8<-- -exercises/transpose.broken.c ---8<-- -``` - -The precondition of `transpose` asserts ownership of an `RW(p)` resource. The error report now instead lists under "`Available resources`" two resources: - -- `RW(member_shift(p, x))` with output `P.x` and - -- `RW(member_shift(p, y))` with output `P.y` - - - -Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. - -When the function returns, the two member resources are recombined "`on demand`" to satisfy the postcondition `RW(p)`. - -### Exercises - -_Init point._ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. - -_Transpose (again)._ Recreate the transpose function from before, now using the swap function verified earlier (for `struct upoint`, with unsigned member values). - -BCP: FIX!! - -```c title="exercises/transpose2.c" ---8<-- -exercises/transpose2.c ---8<-- -``` - - - -## Arrays and loops - -Another common datatype in C is arrays. Reasoning about memory ownership for arrays is more difficult than for the datatypes we have seen so far, for two reasons: (1) C allows the programmer to access arrays using _computed pointers_, and (2) the size of an array does not need to be known as a constant at compile time. - -To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `int` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: - - - -```c -each (i32 i; 0i32 <= i && i < 10i32) -{ RW(array_shift(p,i)) } -``` - -In detail, this can be read as follows: - -- for each integer `i` of CN type `i32`, … - -- if `i` is between `0` and `10`, … - -- assert ownership of a resource `RW` … - -- for cell `i` of the array with base-address `p`. - -Here `array_shift(p,i)` computes a pointer into the array at pointer `p`, appropriately offset for index `i`. - -In general, iterated resource specifications take the form - -```c -each (BT Q; GUARD) { RESOURCE } -``` - -comprising three parts: - -- `BT Q`, for some CN type `BT` and name `Q`, introduces the quantifier `Q` of basetype `BT`, which is bound in `GUARD` and `RESOURCE`; - -- `GUARD` is a boolean-typed expression delimiting the instances of `Q` for which ownership is asserted; and - -- `RESOURCE` is any non-iterated CN resource. - -### First array example - -Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. - -```c title="exercises/array_load.broken.c" ---8<-- -exercises/array_load.broken.c ---8<-- -``` - -The CN precondition requires - -- ownership of the array on entry — one `RW` resource for each array index between `0` and `n` — and -- that `i` lies within the range of RW indices. - -On exit the array ownership is returned again. - -This specification, in principle, should ensure that the access `p[i]` is safe. However, running CN on the example produces an error: CN is unable to find the required ownership for reading `p[i]`. - -``` -cn verify solutions/array_load.broken.c -[1/1]: read -build/solutions/array_load.broken.c:5:10: error: Missing resource for reading -return p[i]; -^~~~ -Resource needed: RW(array_shift(p, (u64)i)) -``` - -The reason is that, when searching for a required resource, such as the `RW` resource for `p[i]` here, CN’s resource inference does not consider iterated resources. Quantifiers, as used by iterated resources, can make verification undecidable, so, in order to maintain predictable type checking, CN delegates this aspect of the reasoning to the user. - -To make the `RW` resource required for accessing `p[i]` available to CN’s resource inference we have to explicitly "`focus`" ownership for index `i` out of the iterated resource. - -```c title="exercises/array_load.c" ---8<-- -exercises/array_load.c ---8<-- -``` - -Here the CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits the iterated resource into two: - -```c -each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) } -``` - -is split into - -1. the instantiation of the iterated resource at `i` - -```c -RW(array_shift(p,i)) -``` - -2. the remainder of the iterated resource, the ownership for all indices except `i` - -```c - each(i32 j; 0i32 <= j && j < n && j != i) - { RW(array_shift(p,j)) } -``` - -After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `focus` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. - -Following an `focus` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. - -So far the specification only guarantees safe execution but does not -specify the behaviour of `read`. To address this, let’s return to -the iterated resources in the function specification. When we specify -`take A = each ...` here, what is `A`? In CN, the output of an -iterated resource is a _map_ from indices to resource outputs. In this -example, where index `j` has CN type `i32` and the iterated -resource is `RW`, the output `A` is a map from `i32` -indices to `i32` values — CN type `map`. If the type of -`j` was `i64` and the resource `RW`, `A` would have -type `map`. - -We can use this to refine our specification with information about the functional behaviour of `read`. - -```c title="exercises/array_load2.c" ---8<-- -exercises/array_load2.c ---8<-- -``` - -We specify that `read` does not change the array — the outputs of `RW`, -`A` and `A_post`, taken before and after running the function, are -the same — and that the value returned is `A[i]`. - -### Exercises - -_Array read two._ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. - - - -```c title="exercises/add_two_array.c" ---8<-- -exercises/add_two_array.c ---8<-- -``` - - - -_Swap array._ Specify and verify `swap_array`, which swaps the values of two cells of an `int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. - -```c title="exercises/swap_array.c" ---8<-- -exercises/swap_array.c ---8<-- -``` - - - -### Loops - -The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. - -In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all RW resources and the constraints required to verify each iteration of the loop. - -Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. - - - -```c title="exercises/init_array.c" ---8<-- -exercises/init_array.c ---8<-- -``` - -If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `RW` resource -- one `RW` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. - -To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). - -```c title="solutions/init_array.c" ---8<-- -solutions/init_array.c ---8<-- -``` - - - -The main condition here is unsurprising: we specify ownership of an iterated resource for an array just like in the the pre- and postcondition. - -The second thing we need to do, however, is less straightforward. Recall that, as discussed at the start of the tutorial, function arguments in C are mutable. Although, in this example, it is obvious that `p` and `n` do not change, CN currently requires the loop invariant to explicitly state this, using special notation `{p} unchanged` (and similarly for `n`). - -**Note.** If we forget to specify `unchanged`, this can lead to confusing errors. In this example, for instance, CN would verify the loop against the loop invariant, but would be unable to prove a function postcondition seemingly directly implied by the loop invariant (lacking the information that the postcondition's `p` and `n` are the same as the loop invariant's). Future CN versions may handle loop invariants differently and treat variables as immutable by default. - - - -The final piece needed in the verification is an `focus` statement, as used in the previous examples: to separate the individual `RW` resource for index `j` out of the iterated `RW` resource and make it available to the resource inference, we specify `focus RW, j;`. - -With the `inv` and `focus` statements in place, CN accepts the function. - -### Second loop example - -The specification of `init_array` is overly strong: it requires an iterated `RW` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `W` resource for the array should also be sufficient. The modified specification is then as follows. - -```c title="exercises/init_array2.c" ---8<-- -exercises/init_array2.c ---8<-- -``` - -This specification _should_ hold: assuming ownership of an uninitialised array on entry, each iteration of the loop initialises one cell of the array, moving it from `W` to `RW` "`state`", so that on function return the full array is initialised. (Recall that stores only require `W` ownership of the written memory location, i.e., ownership of not-necessarily-initialised memory.) - -To verify this modified example we again need a loop Invariant. But -this time the loop invariant is more involved: since each iteration of -the loop initialises one more array cell, the loop invariant has to do -precise book-keeping of the initialisation status of the different -sections of the array. - -To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `RW` resource, for all other array indices we have the (unchanged) `W` ownership. - -```c title="solutions/init_array2.c" ---8<-- -solutions/init_array2.c ---8<-- -``` - -Let's go through this line-by-line: - -- We assert ownership of an iterated `RW` resource, one for each index `i` strictly smaller than loop variable `j`. - -- All remaining indices `i`, between `j` and `n` are still uninitialised, so part of the iterated `W` resource. - -- As in the previous example, we assert `p` and `n` are unchanged. - -- Finally, unlike in the previous example, this loop invariant involves `j`. We therefore also need to know that `j` does not exceed the array length `n`. Otherwise CN would not be able to prove that, on completing the last loop iteration, `j=n` holds. This, in turn, is needed to show that, when the function returns, ownership of the iterated `RW` resource --- as specified in the loop invariant --- is fully consumed by the function's post-condition and there is no left-over unused resource. - -As before, we also have to instruct CN to `focus` ownership of individual array cells out of the iterated resources: - -- to allow CN to focus the individual `W` to be written, we use `focus W, j;`; - -- the store returns a matching `RW` resource for index `j`; - -- finally, we add `focus RW, j;` to allow CN to "`attach`" this resource to the iterated `RW` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `focus` only for the "`reverse`" direction. - - - - -### Exercises - -**Init array reverse.** Verify the function `init_array_rev`, which has the same specification as `init_array2`, but initializes the array in decreasing index order (from right to left). - -```c title="exercises/init_array_rev.c" ---8<-- -exercises/init_array_rev.c ---8<-- -``` - - - - - -## Defining Predicates - - - - - - -Suppose we want to write a function that takes _two_ pointers to -integers and increments the contents of both of them. - -First, let's deal with the "normal" case where the two arguments do -not alias... - -```c title="exercises/slf_incr2_noalias.c" ---8<-- -exercises/slf_incr2_noalias.c ---8<-- -``` - -But what if they do alias? The clunky solution is to write a whole -different version of `incr2` with a different embedded specification... - -```c title="exercises/slf_incr2_alias.c" ---8<-- -exercises/slf_incr2_alias.c ---8<-- -``` - -This version does correctly state that the final values of `p` and `q` are,m respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. - - - - - -A better way is to define a _predicate_ that captures both the aliased -and the non-aliased cases together and use it in the pre- and -postconditions: - - - - - -```c title="exercises/slf_incr2.c" ---8<-- -exercises/slf_incr2.c ---8<-- -``` - - - - - - -## Allocating and Deallocating Memory - - - -At the moment, CN does not understand the `malloc` and `free` -functions. They are a bit tricky because they rely on a bit of -polymorphism and a typecast between `char*` -- the result type of -`malloc` and argument type of `free` -- and the actual type of the -object being allocated or deallocated. - -However, for any given type, we can define a type-specific function -that allocates heap storage with exactly that type. The -implementation of this function cannot be checked by CN, but we can -give just the spec, together with a promise to link against an -external C library providing a correct (but not verified!) implementation: - -```c title="exercises/malloc.h" ---8<-- -exercises/malloc.h ---8<-- -``` - -(Alternatively we can include an implementation written in arbitrary C -inside a CN file by marking it with the keyword `trusted` at the top -of its CN specification.) - -Similarly: - -```c title="exercises/free.h" ---8<-- -exercises/free.h ---8<-- -``` - -Now we can write code that allocates and frees memory: - -```c title="exercises/slf17_get_and_free.verif.c" ---8<-- -exercises/slf17_get_and_free.verif.c ---8<-- -``` - -We can also define a "safer", ML-style version of `malloc` that -handles both allocation and initialization: - -```c title="exercises/ref.h" ---8<-- -exercises/ref.h ---8<-- -``` - - - -```c title="exercises/slf16_basic_succ_using_incr.c" ---8<-- -exercises/slf16_basic_succ_using_incr.c ---8<-- -``` - -### Exercises - - - -Prove a specification for the following program that reveals _only_ -that it returns a pointer to a number that is greater than the number -pointed to by its argument. - -```c title="exercises/slf_ref_greater.c" ---8<-- -exercises/slf_ref_greater.c ---8<-- -``` - -### Side note - -Here is another syntax for external / unknown -functions, together with an example of a loose specification: - - - -```c title="exercises/slf18_two_dice.c" ---8<-- -exercises/slf18_two_dice.c ---8<-- -``` - -## Lists - - - -Now it's time to look at some more interesting heap structures. - -To begin with, here is a C definition for linked list cells, together -with allocation and deallocation functions: - - - -```c title="exercises/list/c_types.h" ---8<-- -exercises/list/c_types.h ---8<-- -``` - - - - - -To write specifications for C functions that manipulate lists, we need -to define a CN "predicate" that describes specification-level list -structures, as one would do in ML, Haskell, or Coq. We use the -datatype `List` for CN-level lists. - -Intuitively, the `SLList_At` predicate walks over a singly-linked -pointer structure in the C heap and extracts an `RW` version of -the CN-level list that it represents. - -```c title="exercises/list/cn_types.h" ---8<-- -exercises/list/cn_types.h ---8<-- -``` - -We can also write _functions_ on CN-level lists by ordinary functional -programming (in a slightly strange, unholy-union-of-C-and-Rust -syntax): - -```c title="exercises/list/hdtl.h" ---8<-- -exercises/list/hdtl.h ---8<-- -``` - -We use the `SLList_At` predicate to specify functions returning the -empty list and the cons of a number and a list. - -```c title="exercises/list/constructors.h" ---8<-- -exercises/list/constructors.h ---8<-- -``` - -Finally, we can collect all this stuff into a single header file. (We -add the usual C `#ifndef` gorp to avoid complaints from the compiler -if it happens to get included twice from the same source file later.) - -```c title="exercises/list/headers.verif.h" ---8<-- -exercises/list/headers.verif.h ---8<-- -``` - - - -### Append - -With this basic infrastructure in place, we can start specifying and -verifying list-manipulating functions. First, `append`. - -Here is its specification (in a separate file, because we'll want to -use it multiple times below.) - -```c title="exercises/list/append.h" ---8<-- -exercises/list/append.h ---8<-- -``` - -Here is a simple destructive `append` function. Note the two uses -of the `unfold` annotation in the body, which are needed to help the -CN typechecker. The `unfold` annotation is an instruction to CN to replace a call to a recursive (CN) function (in this case `append`) -with its definition, and is necessary because CN is unable to automatically determine when and where to expand recursive definitions on its own. - - - -```c title="exercises/list/append.c" ---8<-- -exercises/list/append.c ---8<-- -``` - -### List copy - -Here is an allocating list copy function with a pleasantly light -annotation burden. - -```c title="exercises/list/copy.c" ---8<-- -exercises/list/copy.c ---8<-- -``` - -### Merge sort - - - -Finally, here is a slightly tricky in-place version of merge sort that -avoids allocating any new list cells in the splitting step by taking -alternate cells from the original list and linking them together into -two new lists of roughly equal lengths. - - - - - -```c title="exercises/list/mergesort.c" ---8<-- -exercises/list/mergesort.c ---8<-- -``` - -### Exercises - -_Allocating append_. Fill in the CN annotations on -`IntList_append2`. (You will need some in the body as well as at -the top.) - -```c title="exercises/list/append2.c" ---8<-- -exercises/list/append2.c ---8<-- -``` - -Note that it would not make sense to do the usual -functional-programming trick of copying xs but sharing ys. (Why?) - -_Length_. Add annotations as appropriate: - -```c title="exercises/list/length.c" ---8<-- -exercises/list/length.c ---8<-- -``` - -_List deallocation_. Fill in the body of the following procedure and -add annotations as appropriate: - -```c title="exercises/list/free.c" ---8<-- -exercises/list/free.c ---8<-- -``` - -_Length with an accumulator_. Add annotations as appropriate: - - - - - - - - -```c title="exercises/slf_length_acc.c" ---8<-- -exercises/slf_length_acc.c ---8<-- -``` - -## Working with External Lemmas - - - -looks like on the Coq side! - - - - - - -### List reverse - -The specification of list reversal in CN relies on the familiar -recursive list reverse function, with a recursive helper. - -```c title="exercises/list/snoc.h" ---8<-- -exercises/list/snoc.h ---8<-- -``` - -```c title="exercises/list/rev.h" ---8<-- -exercises/list/rev.h ---8<-- -``` - -To reason about the C implementation of list reverse, we need to help -the SMT solver by enriching its knowledge base with a couple of facts -about lists. The proofs of these facts require induction, so in CN we -simply state them as lemmas and defer the proofs to Coq. - -```c title="exercises/list/rev_lemmas.h" ---8<-- -exercises/list/rev_lemmas.h ---8<-- -``` - -Having stated these lemmas, we can now complete the specification and -proof of `IntList_rev`. Note the two places where `apply` is used -to tell the SMT solver where to pay attention to the lemmas. - - - -```c title="exercises/list/rev.c" ---8<-- -exercises/list/rev.c ---8<-- -``` - -For comparison, here is another way to write the program, using a -while loop instead of recursion, with its specification and proof. - - - -```c title="exercises/list/rev_alt.c" ---8<-- -exercises/list/rev_alt.c ---8<-- -``` - -### Exercises - -**Sized stacks:** Fill in annotations where requested: - - - -```c title="exercises/slf_sized_stack.c" ---8<-- -exercises/slf_sized_stack.c ---8<-- -``` - - - - - - - -## CN Style - - - -This section gathers some advice on stylistic conventions and best -practices in CN. - -### Constants - -The syntax of the C language does not actually include constants. -Instead, the convention is to use the macro preprocessor to replace -symbolic names by their definitions before the C compiler ever sees -them. - -This raises a slight awkwardness in CN, because CN specifications and -annotations are written in C comments, so they are not transformed by -the preprocessor. However, we can approximate the effect of constant -_values_ by defining constant _functions_. We've been working with -some of these already, e.g., `MINi32()`, but it is also possible to -define our own constant functions. Here is the officially approved -idiom: - -```c title="exercises/const_example.c" ---8<-- -exercises/const_example.c ---8<-- -``` - -Here's how it works: - -- We first define a C macro `CONST` in the usual way. - -- The next two lines "import" this constant into CN by defining a CN - function `CONST()` whose body is the C function `c_CONST()`. The - body of `c_CONST` returns the value of the macro `CONST`. Notice - that the declaration of `CONST()` has no body. - -- The annotation `/*@ cn_function CONST; @*/` links - the two functions, `CONST()` and `cn_CONST()`. - -Of course, we could achieve the same effect by defining the CN -function `CONST()` directly... - -```c title="exercises/const_example_lessgood.c" ---8<-- -exercises/const_example_lessgood.c ---8<-- -``` - -...but this version repeats the number `1` in two places -- a -potential source of nasty bugs! - - - - - -## Case Studies - -To close out the tutorial, let's look at some larger examples. - -### Case Study: Imperative Queues - -A queue is a linked list with O(1) operations for adding things to one -end (the "back") and removing them from the other (the "front"). Here -are the C type definitions: - -```c title="exercises/queue/c_types.h" ---8<-- -exercises/queue/c_types.h ---8<-- -``` - -A queue consists of a pair of pointers, one pointing to the front -element, which is the first in a linked list of `queue_cell`s, -the other pointing directly to the last cell in this list. If the -queue is empty, both pointers are NULL. - -Abstractly, a queue just represents a list, so we can reuse the `List` -type from the list examples earlier in the tutorial. - -```c title="exercises/queue/cn_types_1.h" ---8<-- -exercises/queue/cn_types_1.h ---8<-- -``` - -Given a pointer to a `queue` struct, this predicate grabs ownership -of the struct, asserts that the `front` and `back` pointers must -either both be NULL or both be non-NULL, and then hands off to an -auxiliary predicate `QueueFB`. Note that `QueuePtr_At` returns a -`List` -- that is, the abstract view of a queue heap structure is -simply the sequence of elements that it contains. The difference -between a queue and a singly or doubly linked list is simply one of -concrete representation. - -`QueueFB` is where the interesting part starts. (Conceptually, -`QueueFB` is part of `QueuePTR`, but CN currently allows -conditional expressions only at the beginning of predicate -definitions, not after a `take`, so we need to make a separate -auxiliary predicate.) - -```c title="exercises/queue/cn_types_2.h" ---8<-- -exercises/queue/cn_types_2.h ---8<-- -``` - -First, we case on whether the `front` of the queue is NULL. If so, -then the queue is empty and we return the empty sequence. - -If the queue is not empty, we need to walk down the linked list of -elements and gather up all their values into a sequence. But we must -treat the last element of the queue specially, for two reasons. -First, since the `push` operation is going to follow the `back` -pointer directly to the last list cell without traversing all the -others, we need to `take` that element now rather than waiting to -get to it at the end of the recursion starting from the `front`. -Second, and relatedly, there will be two pointers to this final list -cell -- one from the `back` field and one from the `next` field of -the second to last cell (or the `front` pointer, if there is only -one cell in the list), so we need to be careful not to `take` this -cell twice. - -Accordingly, we begin by `take`-ing the tail cell and passing it -separately to the `QueueAux` predicate, which has the job of -walking down the cells from the front and gathering all the rest of -them into a sequence. We take the result from `QueueAux` and -`snoc` on the very last element. - -The `assert (is_null(B.next))` here gives the CN verifier a crucial -piece of information about an invariant of the representation: The -`back` pointer always points to the very last cell in the list, so -its `next` field will always be NULL. - - - -Finally, the `QueueAux` predicate recurses down the list of -cells and returns a list of their contents. - -```c title="exercises/queue/cn_types_3.h" ---8<-- -exercises/queue/cn_types_3.h ---8<-- -``` - -Its first argument (`f`) starts out at `front` and progresses -through the queue on recursive calls; its `b` argument is always a -pointer to the very last cell. - -When `f` and `b` are equal, we have reached the last cell and -there is nothing to do. We don't even have to build a singleton -list: that's going to happen one level up, in `QueueFB`. - -Otherwise, we `take` the fields of the `f`, make a recurive -call to `QueueAux` to process the rest of the cells, and cons the -`first` field of this cell onto the resulting sequence before -returning it. Again, we need to help the CN verifier by explicitly -informing it of the invariant that we know, that `C.next` cannot be -null if `f` and `b` are different. - -Now we need a bit of boilerplate: just as with linked lists, we need -to be able to allocate and deallocate queues and queue cells. There -are no interesting novelties here. - -```c title="exercises/queue/allocation.verif.h" ---8<-- -exercises/queue/allocation.verif.h ---8<-- -``` - - - -_Exercise_: The function for creating an empty queue just needs to set -both of its fields to NULL. See if you can fill in its specification. - -```c title="exercises/queue/empty.c" ---8<-- -exercises/queue/empty.c ---8<-- -``` - - - -The push and pop operations are more involved. Let's look at `push` -first. - -Here's the unannotated C code -- make sure you understand it. - -```c title="exercises/queue/push_orig.broken.c" ---8<-- -exercises/queue/push_orig.broken.c ---8<-- -``` - -_Exercise_: Before reading on, see if you can write down a reasonable -top-level specification for this operation. - -One thing you might find odd about this code is that there's a -`return` statement at the end of each branch of the conditional, -rather than a single `return` at the bottom. The reason for this is -that, when CN analyzes a function body containing a conditional, it -effectively _copies_ all the code after the conditional into each of -the branches. Then, if verification encounters an error related to -this code -- e.g., "you didn't establish the `ensures` conditions at -the point of returning -- the error message will be confusing because -it will not be clear which branch of the conditional it is associated -with. - -Now, here is the annotated version of the `push` operation. - -```c title="exercises/queue/push.c" ---8<-- -exercises/queue/push.c ---8<-- -``` - -The case where the queue starts out empty (`q->back == 0`) is easy. -CN can work it out all by itself. - -The case where the starting queue is nonempty is more interesting. -The `push` operation messes with the end of the sequence of queue -elements, so we should expect that validating `push` is going to -require some reasoning about this sequence. Here, in fact, is the -lemma we need. - - - - -```c title="exercises/queue/push_lemma.h" ---8<-- -exercises/queue/push_lemma.h ---8<-- -``` - -This says, in effect, that we have two choices for how to read out the -values in some chain of queue cells of length at least 2, starting -with the cell `front` and terminating when we get to the next cell -_following_ some given cell `p` -- call it `c`. We can either -gather up all the cells from `front` to `c`, or we can gather up -just the cells from `front` to `p` and then `snoc` on the single -value from `c`. - -When we apply this lemma, `p` will be the old `back` cell and -`c` will be the new one. But to prove it (by induction, of course), -we need to state it more generally, allowing `p` to be any internal -cell in the list starting at `front` and `c` its successor. - -The reason we need this lemma is that, to add a new cell at the end of -the queue, we need to reassign ownership of the old `back` cell. -In the precondition of `push`, we took ownership of this cell -separately from the rest; in the postcondition, it needs to be treated -as part of the rest (so that the new `back` cell can now be treated -specially). - -One interesting technicality is worth noting: After the assignment -`q->back = c`, we can no longer prove `QueueFB(q->front, -oldback)`, but we don't care about this, since we want to prove -`QueueFB(q->front, q->back)`. However, crucially, -`QueueAux(q->front, oldback)` is still true. - - - -Now let's look at the `pop` operation. Here is the un-annotated -version: - -```c title="exercises/queue/pop_orig.broken.c" ---8<-- -exercises/queue/pop_orig.broken.c ---8<-- -``` - -_Exercise_: Again, before reading on, see if you can write down a -plausible top-level specification. (For extra credit, see how far you -can get with verifying it!) - -Here is the fully annotated `pop` code: - -```c title="exercises/queue/pop.c" ---8<-- -exercises/queue/pop.c ---8<-- -``` - -There are three annotations to explain. Let's consider them in order. - -First, the `split_case` on `is_null(q->front)` is needed to tell -CN which of the branches of the `if` at the beginning of the -`QueueFB` predicate it can "unpack". (`QueuePtr_At` can be -unpacked immediately because it is unconditional, but `QueueFB` -cannot.) - - - -The guard/condition for `QueueFB` is `is_null(front)`, which is -why we need to do a `split_case` on this value. On one branch of the -`split_case` we have a contradiction: the fact that `before == -Nil{}` (from `QueueFB`) conflicts with `before != Nil` -from the precondition, so that case is immediate. On the other -branch, CN now knows that the queue is non-empty, as required, and type -checking proceeds. - -When `h == q->back`, we are in the case where the queue contains -just a single element, so we just need to NULL out its `front` and -`back` fields and deallocate the dead cell. The `unfold` -annotation is needed because the `snoc` function is recursive, so CN -doesn't do the unfolding automatically. - -Finally, when the queue contains two or more elements, we need to -deallocate the front cell, return its `first` field, and redirect -the `front` field of the queue structure to point to the next cell. -To push the verification through, we need a simple lemma about the -`snoc` function: - -```c title="exercises/queue/pop_lemma.h" ---8<-- -exercises/queue/pop_lemma.h ---8<-- -``` - -The crucial part of this lemma is the last three lines, which express -a simple, general fact about `snoc`: -if we form a sequence by calling `snoc` to add a final element -`B.first` to a sequence with head element `x` and tail `Q`, then the -head of the resulting sequence is still `x`, and its tail is `snoc -(Q, B.first)`. - -The `requires` clause and the first three lines of the `ensures` -clause simply set things up so that we can name the various values we -are talking about. Since these values come from structures in the -heap, we need to take ownership of them. And since lemmas in CN are -effectively just trusted functions that can also take in ghost values, -we need to take ownership in both the `requires` and `ensures` -clauses. (Taking them just in the `requires` clause would imply -that they are consumed and deallocated when the lemma is applied -- -not what we want!) - - - - -(The only reason we can't currently prove this lemma in CN is that we -don't have `take`s in CN statements, because this is just a simple -unfolding.) - - - -_Exercise_: -Investigate what happens when you make each of the following changes -to the queue definitions. What error does CN report? Where are the -telltale clues in the error report that suggest what the problem was? - -- Remove `assert (is_null(B.next));` from `InqQueueFB`. -- Remove `assert (is_null(B.next));` from `InqQueueAux`. -- Remove one or both of occurrences of `free_queue_cell(f)` in - `pop_queue`. -- Remove, in turn, each of the CN annotations in the bodies of - `pop_queue` and `push_queue`. - -_Exercise_: The conditional in the `pop` function tests whether or -not `f == b` to find out whether we have reached the last element of -the queue. Another way to get the same information would be to test -whether `f->next == 0`. Can you verify this version? -_Note_: I (BCP) have not worked out the details, so am not sure how hard -this is (or if it is even not possible, though I'd be surprised). -Please let me know if you get it working! - -_Exercise_: Looking at the code for the `pop` operation, -it might seem reasonable to move the identical assignments to `x` in both -branches to above the `if`. This doesn't "just work" because the -ownership reasoning is different. In the first case, ownership of -`h` comes from `QueueFB` (because `h == q->back`). In the -second case, it comes from `QueueAux` (because `h != -q->back`). - -Can you generalize the `snoc_facts` lemma to handle both cases? You -can get past the dereference with a `split_case` but formulating the -lemma before the `return` will be a bit more complicated. - - - -_Note_: Again, this has not been shown to be possible, but Dhruv -believes it should be! - - - - - -### Case Study: Doubly Linked Lists - - - -A doubly linked list is a linked list where each node has a pointer -to both the next node and the previous node. This allows for O(1) -operations for adding or removing nodes anywhere in the list. - -Because of all the sharing in this data structure, the separation -reasoning is a bit tricky. We'll give you the core definitions and -then invite you to help fill in the annotations for some of the -functions that manipulate doubly linked lists. - -First, here is the C type definition: - -```c title="exercises/dll/c_types.h" ---8<-- -exercises/dll/c_types.h ---8<-- -``` - -The idea behind the representation of this list is that we don't keep -track of the front or back, but rather we take any node in the list -and have a sequence to the left and to the right of that node. The `left` -and `right` are from the point of view of the node itself, so `left` -is kept in reverse order. Additionally, similarly to in the -`Imperative Queues` example, we can reuse the `List` type. - -```c title="exercises/dll/cn_types.h" ---8<-- -exercises/dll/cn_types.h ---8<-- -``` - -The predicate for this datatype is a bit complicated. The idea is that -we first own the node that is passed in. Then we follow all of the -`prev` pointers to own everything backwards from the node, and finally -all the `next` pointers to own everything forwards from the node, to -construct the `left` and `right` fields. - - - -```c title="exercises/dll/predicates.h" ---8<-- -exercises/dll/predicates.h ---8<-- -``` - -Note that `Dll_at` takes ownership of the node passed in, and then -calls `Own_Backwards` and `Own_Forwards`, which recursively take -ownership of the rest of the list. - -Also, notice that `Own_Forwards` and `Own_Backwards` include `ptr_eq` -assertions for the `prev` and `next` pointers. This is to ensure that -the nodes in the list are correctly doubly linked. For example, the -line `assert (ptr_eq(n.prev, prev_pointer));` in `Own_Forwards` -ensures that the current node correctly points backward to the -previous node in the list. The line `assert(ptr_eq(prev_node.next, -p));` ensures that the previous node correctly points forward to the -current node. - -Before we move on to the functions that manipulate doubly linked -lists, we need to define a few "getter" functions that will allow us -to access the fields of our `Dll` datatype. This will make the -specifications easier to write. - -```c title="exercises/dll/getters.h" ---8<-- -exercises/dll/getters.h ---8<-- -``` - -We also need some boilerplate for allocation and deallocation. - -```c title="exercises/dll/malloc_free.h" ---8<-- -exercises/dll/malloc_free.h ---8<-- -``` - -For convenience, we gather all of these files into a single header file. - -```c title="exercises/dll/headers.verif.h" ---8<-- -exercises/dll/headers.verif.h ---8<-- -``` - - - -Now we can move on to an initialization function. Since an empty list -is represented as a null pointer, we will look at initializing a -singleton list (or in other words, a list with only one item). - -```c title="exercises/dll/singleton.c" ---8<-- -exercises/dll/singleton.c ---8<-- -``` - - - -The `add` and `remove` functions are where it gets a little tricker. -Let's start with `add`. Here is the unannotated version: - -```c title="exercises/dll/add_orig.broken.c" ---8<-- -exercises/dll/add_orig.broken.c ---8<-- -``` - -_Exercise_: Before reading on, see if you can figure out what -specification is appropriate and what other are needed. - - - -Now, here is the annotated version of the `add` operation: - -```c title="exercises/dll/add.c" ---8<-- -exercises/dll/add.c ---8<-- -``` - -First, let's look at the pre- and post-conditions. The `requires` -clause is straightforward. We need to own the list centered around -the node that `n` points to. `Before` is a `Dll` -that is either empty, or it has a List to the left, -the current node that `n` points to, and a List to the right. -This corresponds to the state of the list when it is passed in. - -In the ensures clause, we again establish ownership of the list, but -this time it is centered around the added node. This means that -`After` is a `Dll` structure similar to `Before`, except that the node -`curr` is now the created node. The old `curr` is pushed into the left -part of the new list. The conditional operator in the `ensures` clause -is saying that if the list was empty coming in, it now is a singleton -list. Otherwise, the left left part of the list now has the data from -the old `curr` node, the new `curr` node is the added node, and the -right part of the list is the same as before. - -Now, let's look at the annotations in the function body. CN can -figure out the empty list case for itself, but it needs some help with -the non-empty list case. The `split_case` on `is_null(n->prev)` -tells CN to unpack the `Own_Backwards` predicate. Without this -annotation, CN cannot reason that we didn't lose the left half of the -list before we return, and will claim we are missing a resource for -returning. The `split_case` on `is_null(n->next->next)` is similar, -but for unpacking the `Own_Forwards` predicate. Note that we have to -go one more node forward to make sure that everything past `n->next` -is still RW at the end of the function. - -Now let's look at the `remove` operation. Traditionally, a `remove` -operation for a list returns the integer that was removed. However we -also want all of our functions to return a pointer to the -list. Because of this, we define a `struct` that includes an `int` -and a `node`. - -```c title="exercises/dll/dllist_and_int.h" ---8<-- -exercises/dll/dllist_and_int.h ---8<-- -``` - -Now we can look at the code for the `remove` operation. Here is the un-annotated version: - -```c title="exercises/dll/remove_orig.broken.c" ---8<-- -exercises/dll/remove_orig.broken.c ---8<-- -``` - -_Exercise_: Before reading on, see if you can figure out what -specification is appropriate and what annotations are needed. - - - -Now, here is the fully annotated version of the `remove` operation: - -```c title="exercises/dll/remove.c" ---8<-- -exercises/dll/remove.c ---8<-- -``` - -First, let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we -assign the node of that list to the identifier `del` -to make our spec more readable. So `Before` refers to the `Dll` when the function is called, and `del` refers to the node that will be deleted. - -Then in the `ensures` clause, we must take ownership -of the `node_and_int` struct as well as the `Dll` that -the node is part of. Here, `After` refers to the `Dll` -when the function returns. We ensure that the int that is returned is the value of the deleted node, as intended. Then we have a complicated nested ternary conditional that ensures that `After` is the same as `Before` except for the deleted node. Let's break down this conditional: - -- The first guard asks if both `del.prev` and `del.next` are null. In this case, we are removing the only node in the list, so the resulting list will be empty. The `else` branch of this conditional contains its own conditional. - -- For the following conditional, the guard checks if 'del.prev' is - _not_ null. This means that the returned node is `del.next`, - regardless of whether or not `del.prev` is null. If this is the - case, `After` is now centered around `del.next`, and the left part - of the list is the same as before. Since `del.next` was previously - the head of the right side, the right side loses its head in - `After`. This is where we get `After == Dll{left: -Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. - -- The final `else` branch is the case where `del.next` is null, but - `del.prev` is not null. In this case, the returned node is - `del.prev`. This branch follows the same logic as the one before it, - except now we are taking the head of the left side rather than the - right side. Now the right side is unchanged, and the left side is just - the tail, as seen shown in `After == Dll{left: -Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` - -The annotations in the function body are similar to in the `add` -function. Both of these `split_case` annotations are needed to unpack -the `Own_Forwards` and `Own_Backwards` predicates. Without them, CN -will not be able to reason that we didn't lose the left or right half -of the list before we return and will claim we are missing a resource -for returning. - - - -_Exercise_: There are many other functions that one might want to -implement for a doubly linked list. For example, one might want to -implement a function that appends one list to another, or a function -that reverses a list. Try implementing a few of these functions and -writing their specifications. - -_Exercise_: For extra practice, try coming up with one or two -variations on the Dll data structure itself (there are many!). - - - - - -### Case Study: Airport Simulation - - - -Suppose we have been tasked with writing a program that simulates a -runway at an airport. This airport is very small, so it only has one -runway, which is used for both takeoffs and landings. We want to -verify that the runway is always used safely, by checking the -following informal specification: - -1. The runway has two modes: departure mode and arrival mode. The two -modes can never be active at the same time. Neither mode is active -at the beginning of the day. - - -2. At any given moment, there is a waiting list of planes that need to - land at the airport and planes that need to leave the - airport. These are modeled with counters `W_A` for the number of - planes waiting to arrive, and `W_D` for the number of planes - waiting to depart. - -3. At any moment, a plane is either waiting to arrive, waiting to - depart, or on the runway. Once a plane has started arriving or - departing, the corresponding counter (`W_A` or `W_D`) is - decremented. There is no need to keep track of planes once they - have arrived or departed. Additionally, once a plane is waiting to - arrive or depart, it continues waiting until it has arrived or - departed. - -4. It takes 5 minutes for a plane to arrive or depart. During these 5 - minutes, no other plane may use the runway. We can keep track of - how long a plane has been on the runway with the - `Runway_Counter`. If the `Runway_Counter` is at 0, then there is - currently no plane using the runway, and it is clear for another - plane to begin arriving or departing. Once the `Runway_Counter` - reaches 5, we can reset it at the next clock tick. One clock tick - represents 1 minute. - -5. If there is at least one plane waiting to depart and no cars - waiting to arrive, then the runway is set to departure mode (and - vice versa for arrivals). - -6. If both modes of the runway are inactive and planes become ready to - depart and arrive simultaneously, the runway will activate arrival - mode first. If the runway is in arrival mode and there are planes - waiting to depart, no more than 3 planes may arrive from that time - point. When either no more planes are waiting to arrive or 3 planes - have arrived, the runway switches to departure mode. If the runway - is on arrival mode and no planes are waiting to depart, then the - runway may stay in arrival mode until a plane is ready to depart, - from which time the 3-plane limit is imposed (and vice versa for - departures). Put simply, if any planes are waiting for a mode that - is inactive, that mode will become active no more than 15 minutes - later (5 minutes for each of 3 planes). - -To encode all this in CN, we first need a way to describe the state of -the runway at a given time. We can use a _struct_ that includes the -following fields: - -- `ModeA` and `ModeD` to represent the arrival and departure modes, - respectively. We can define constants for `ACTIVE` and `INACTIVE`, - as described in the `Constants` section above. - -- `W_A` and `W_D` to represent the number of planes waiting to arrive - and depart, respectively. - -- `Runway_Time` to represent the time (in minutes) that a plane has - spent on the runway while arriving or departing. - -- `Plane_Counter` to represent the number of planes that have arrived - or departed while planes are waiting for the other mode. This will - help us keep track of the 3-plane limit as described in _(6)_. - -```c title="exercises/runway/state.h" ---8<-- -exercises/runway/state.h ---8<-- -``` - -Next, we need to specify what makes a state valid. We must define a -rigorous specification in order to ensure that the runway is always -safe and working as intended. Try thinking about what this might look -like before looking at the code below. - -```c title="exercises/runway/valid_state.h" ---8<-- -exercises/runway/valid_state.h ---8<-- -``` - -Let's walk through the specifications in `valid_state`: - -- The first two lines ensure that both modes in our model behave as intended: they can only be active or inactive. Any other value for these fields would be invalid. - -- The third line says that either arrival mode or departure mode must be inactive. This specification ensures that the runway is never in both modes at the same time. - -- The fourth line says that the number of planes waiting to arrive or depart must be non-negative. This makes sense: we can't have a negative number of planes! - -- The fifth line ensures that the runway time is between 0 and 5. This addresses how a plane takes 5 minutes on the runway as described in _(4)_. - -- The sixth line ensures that the plane counter is between 0 and 3. This is important for the 3-plane limit as described in _(6)_. - -- The seventh line refers to the state at the beginning of the day. If both modes are inactive, then the day has just begun, and thus no planes have departed yet. This is why the plane counter must be 0. - -- The eighth line says that if there is a plane on the runway, then one of the modes must be active. This is because a plane can only be on the runway if it is either arriving or departing. - -- The final two lines ensure that we are incrementing `Plane_Counter` only if there are planes waiting for the other mode, as described in _(6)_. - -Now that we have the tools to reason about the state of the runway formally, let's start writing some functions. - -First, let's look at an initialization function and functions to update `Plane_Counter`. Step through these yourself and make sure you understand the reasoning behind each specification. - -```c title="exercises/runway/funcs1.h" ---8<-- -exercises/runway/funcs1.h ---8<-- -``` - -_Exercise_: Now try adding your own specifications to the following -functions. Make sure that you specify a valid state as a pre- and -post-condition for every function. If you get stuck, the solution is -in the solutions folder. - -```c title="exercises/runway/funcs2.c" ---8<-- -exercises/runway/funcs2.c ---8<-- -``` - - - -## Acknowledgment of Support and Disclaimer - -This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). - - - - From 037fdfd511d59172fb5f06de75064ddf0b53f474 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 10:41:35 -0400 Subject: [PATCH 095/158] Some file renaming --- docs/getting-started/tutorials/arrays.md | 23 ++++++++---- docs/getting-started/tutorials/pointers.md | 14 ++----- .../getting-started/tutorials/verif-arrays.md | 37 ++++++++----------- .../tutorials/verif-numeric.md | 2 +- src/exercises/{init_array.c => array_init.c} | 2 +- .../{init_array2.c => array_init2.c} | 2 +- .../{init_array_rev.c => array_init_rev.c} | 2 +- 7 files changed, 38 insertions(+), 44 deletions(-) rename src/exercises/{init_array.c => array_init.c} (92%) rename src/exercises/{init_array2.c => array_init2.c} (94%) rename src/exercises/{init_array_rev.c => array_init_rev.c} (94%) diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index 08a043a7..a0f6c51c 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -152,10 +152,9 @@ array_max(p, n); Examining the generated counterexample, we see that the elements of the array are `{18, 0, 17}`, so the first element is the maximum. And if we generate counterexamples a few more times, we see that this pattern persists. Inspecting our implementation a bit further, we find and fix another bug: in the first line, we should initialize `max` to be `p[0]`, not `0`. (An additional debugging tip: if the generated counterexample arrays are too large, we can restrain them by adding a temporary precondition such as `n <= 3u32`, to force the array to be of length at most three, or some other suitable bound.) - - -^ JWS: I personally found this a useful hack, but I don't know if we want to advertise it as an officially sanctioned tip. (How close are folks to adding shrinking?) - +{{ later("JWS: I personally found this a useful hack, but I don't +know if we want to advertise it as an officially sanctioned tip. (How +close are folks to adding shrinking?)") }} Now, `cn test` will succeed! @@ -169,11 +168,19 @@ exercises/array_add3.test.c --8<-- ``` -_Exercise:_ Write a specification for `array_sort`, which should sort an array into increasing order. Your specification should succeed on this correct implementation ([yes](https://arxiv.org/abs/2110.01111), it's correct), and fail when bugs are inserted: +_Exercise:_ Write a specification for `array_sort`, which should sort +an array into increasing order. Your specification should succeed on +this correct implementation below +(yes, [it's correct](https://arxiv.org/abs/2110.01111)), and fail +when bugs are inserted: - -JWS: One gnarly aspect of this is that you need to carefully avoid the `i + 1` in `i + 1 < n` overflowing. The version I got to work was to add a (seemingly redundant, but not actually) condition `i < n`. Slight variations, such as to assume a non-empty array, seems to make testing really really slow, and I'm not sure why. We should a) figure out what's the most elegant solution and b) give a hint to that effect. - +{{ later("JWS: One gnarly aspect of this is that you need to carefully +avoid the `i + 1` in `i + 1 < n` overflowing. The version I got to +work was to add a (seemingly redundant, but not actually) condition `i +< n`. Slight variations, such as to assume a non-empty array, seem to +make testing really really slow, and I'm not sure why. We should a) +figure out what's the most elegant solution and b) give a hint to that +effect.") }} ```c title="exercises/array_sort.test.c" --8<-- diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 603006e5..73ad8484 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -162,8 +162,6 @@ We next have an example where data is written to a pointer. The function `incr` takes a pointer `p` and increments the value in the memory cell that it points to. -{{ todo("BCP: unsigned! (there are both signed and unsigned versions at the -moment -- how do they relate?)") }} ```c title="exercises/slf0_basic_incr.c" --8<-- exercises/slf0_basic_incr.c @@ -229,9 +227,9 @@ _returned_ to the caller or else _destroyed_ by deallocating the RW area of memory (as we shall see later). CN’s motivation for this choice is its focus on low-level systems software in which memory is managed manually; in this context, memory leaks are typically very undesirable. -{{ todo(" As a consequence, function specifications have to do precise bookkeeping of +As a consequence, function specifications have to do precise bookkeeping of their resource footprint and, in particular, return any unused resources back to -the caller. ") }} +the caller. ## Disjoint memory regions @@ -286,11 +284,5 @@ i.e., they are records with members `x` and `y`. The postcondition asserts the coordinates have been swapped by referring to the members of `P` and `P_post` individually. -{{ todo(" The reason `RW` needs a C-type annotation is so that it can (a) -figure out the size of the sub-heap being claimed and (b) figure out -how one may need to destructure the type (unions, struct fields and -padding, arrays). The relationship is that for `take x = -RW(expr)` we have `expr : pointer, x : to_basetype(ct)`. ") }} - -{{ todo("It would be nice to add an exercise that involves +{{ later("It would be nice to add an exercise that involves using the error messages to find a bug.") }} diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 072f361e..1836ed98 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -126,7 +126,8 @@ the numeric stuff works. unsigned int tmp = p[i]; p[i] = p[j]; p[j] = tmp; - }") }} + } +") }} ### Loops @@ -134,27 +135,21 @@ The array examples covered so far manipulate one or two individual cells of an a In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all RW resources and the constraints required to verify each iteration of the loop. -Let's take a look at a simple first example. The following function, `init_array`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. +Let's take a look at a simple first example. The following function, `array_init`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. -{{ todo("BCP: Rename to array_init.c") }} - -{{ todo("JWS: Should this change be propagated everywhere e.g. also changing the function name, changing other function names starting with `init_`, changing `swap_array` to `array_swap`, etc.?") }} - -{{ todo("BCP: Yes! I've done a bit of it, but there's more.") }} - -```c title="exercises/init_array.c" +```c title="exercises/array_init.c" --8<-- -exercises/init_array.c +exercises/array_init.c --8<-- ``` -If, for the moment, we focus just on proving safe execution of `init_array`, ignoring its functional behaviour, a specification might look as above: on entry, `init_array` takes ownership of an iterated `RW` resource -- one `RW` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `init_array` returns the ownership. +If, for the moment, we focus just on proving safe execution of `array_init`, ignoring its functional behaviour, a specification might look as above: on entry, `array_init` takes ownership of an iterated `RW` resource -- one `RW` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `array_init` returns the ownership. To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). -```c title="solutions/init_array.c" +```c title="solutions/array_init.c" --8<-- -solutions/init_array.c +solutions/array_init.c --8<-- ``` @@ -175,11 +170,11 @@ With the `inv` and `focus` statements in place, CN accepts the function. ### Second loop example -The specification of `init_array` is overly strong: it requires an iterated `RW` resource for the array on entry. If, as the name suggests, the purpose of `init_array` is to initialise the array, then a precondition asserting only an iterated `W` resource for the array should also be sufficient. The modified specification is then as follows. +The specification of `array_init` is overly strong: it requires an iterated `RW` resource for the array on entry. If, as the name suggests, the purpose of `array_init` is to initialise the array, then a precondition asserting only an iterated `W` resource for the array should also be sufficient. The modified specification is then as follows. -```c title="exercises/init_array2.c" +```c title="exercises/array_init2.c" --8<-- -exercises/init_array2.c +exercises/array_init2.c --8<-- ``` @@ -193,9 +188,9 @@ sections of the array. To do this, we partition the array ownership into two parts: for each index of the array the loop has already visited, we have an `RW` resource, for all other array indices we have the (unchanged) `W` ownership. -```c title="solutions/init_array2.c" +```c title="solutions/array_init2.c" --8<-- -solutions/init_array2.c +solutions/array_init2.c --8<-- ``` @@ -222,11 +217,11 @@ As before, we also have to instruct CN to `focus` ownership of individual array ### Exercises -**Init array reverse.** Verify the function `init_array_rev`, which has the same specification as `init_array2`, but initializes the array in decreasing index order (from right to left). +**Init array reverse.** Verify the function `array_init_rev`, which has the same specification as `array_init2`, but initializes the array in decreasing index order (from right to left). -```c title="exercises/init_array_rev.c" +```c title="exercises/array_init_rev.c" --8<-- -exercises/init_array_rev.c +exercises/array_init_rev.c --8<-- ``` diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index ac4ce2b9..91bd2342 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -238,7 +238,7 @@ solutions/slf1_basic_example_let.signed.c --8<-- ``` -{{ todo("BCP: WHy n*+n\ _ in some places and n\*2i32 in others? ") }} +{{ todo("BCP: WHy n*+n\\_ in some places and n\*2i32 in others? ") }} {{ todo("Dhruv: Unlikely to be meaningful, either is fine. ") }} We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. diff --git a/src/exercises/init_array.c b/src/exercises/array_init.c similarity index 92% rename from src/exercises/init_array.c rename to src/exercises/array_init.c index f1609062..c81a6006 100644 --- a/src/exercises/init_array.c +++ b/src/exercises/array_init.c @@ -1,4 +1,4 @@ -void init_array (char *p, unsigned int n) +void array_init (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { RW( array_shift(p, i)) }; ensures take A_post = each(u32 i; i < n) { diff --git a/src/exercises/init_array2.c b/src/exercises/array_init2.c similarity index 94% rename from src/exercises/init_array2.c rename to src/exercises/array_init2.c index 5f49e1eb..a32c13dd 100644 --- a/src/exercises/init_array2.c +++ b/src/exercises/array_init2.c @@ -1,4 +1,4 @@ -void init_array2 (char *p, unsigned int n) +void array_init2 (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { W( array_shift(p, i)) }; ensures take A_post = each(u32 i; i < n) { diff --git a/src/exercises/init_array_rev.c b/src/exercises/array_init_rev.c similarity index 94% rename from src/exercises/init_array_rev.c rename to src/exercises/array_init_rev.c index dbf9e98d..5d635325 100644 --- a/src/exercises/init_array_rev.c +++ b/src/exercises/array_init_rev.c @@ -1,4 +1,4 @@ -void init_array_rev (char *p, unsigned int n) +void array_init_rev (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { W( array_shift(p, i)) }; n > 0u32; From 4af3d6f019fccced764263c52b5a0449a8b40063 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 11:20:06 -0400 Subject: [PATCH 096/158] More tidying --- .../case-studies/imperative-queues.md | 12 +++---- docs/getting-started/tutorials/alloc.md | 3 +- docs/getting-started/tutorials/lists.md | 15 ++++---- .../getting-started/tutorials/verif-arrays.md | 12 ++++--- src/exercises/queue/empty.test.c | 14 ++++++++ src/exercises/slf17_get_and_free.test.c | 18 +++++----- src/exercises/temp.test.c | 34 +++++++++++++++++++ 7 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 src/exercises/queue/empty.test.c create mode 100644 src/exercises/temp.test.c diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 0ce356ff..9a41e3a7 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -39,9 +39,9 @@ conditional expressions only at the beginning of predicate definitions, not after a `take`, so we need to make a separate auxiliary predicate.) -```c title="exercises/queue/cn_types_2.h" +```c title="exercises/queue/cn_types_2.test.h" --8<-- -exercises/queue/cn_types_2.h +exercises/queue/cn_types_2.test.h --8<-- ``` @@ -110,9 +110,9 @@ exercises/queue/allocation.test.h _Exercise_: The function for creating an empty queue just needs to set both of its fields to NULL. See if you can fill in its specification. -```c title="exercises/queue/empty.c" +```c title="exercises/queue/empty.test.c" --8<-- -exercises/queue/empty.c +exercises/queue/empty.test.c --8<-- ``` @@ -167,9 +167,9 @@ plausible top-level specification and test its correctness. Here is the annotated `pop` code: -```c title="exercises/queue/pop.c" +```c title="exercises/queue/pop.test.c" --8<-- -exercises/queue/pop.c +exercises/queue/pop.test.c --8<-- ``` diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index dfa3bd90..cef90806 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -27,7 +27,6 @@ that manipulate the heap, as usual. exercises/slf17_get_and_free.test.c --8<-- ``` -{{ todo("BCP: The `tester` function here does not parse -- not sure why.") }} ### Exercises @@ -77,4 +76,4 @@ already-initialised memory cell to be over-written again. Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. -{{ todo("BCP: An example and/or an exercise would be nice!") }} +{{ todo("BCP: An example and/or an exercise about the W resource would be nice!") }} diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index e6d452df..5b815913 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -14,7 +14,7 @@ Here are typed allocation and deallocation functions for this type. (We provide separate functions for these rather than just calling `malloc` and `free` directly in the interest of sharing as much code as possible with the verification-focused variants of these examples.) -{{ todo("BCP: ... but maybe we'd get the same amount of sharing if we directly +{{ later("BCP: ... but maybe we'd get the same amount of sharing if we directly used malloc? We should check.") }} ```c title="exercises/list/c_types.test.h" @@ -104,7 +104,7 @@ exercises/list/copy.c ### Merge sort {{ todo(" BCP: This could use a gentler explanation -(probably in pieces) We've heard from more than one reader that this +(probably broken in pieces) We've heard from more than one reader that this example is particularly hard to digest without some additional help") }} Finally, here is a slightly tricky in-place version of merge sort that @@ -120,7 +120,7 @@ exercises/list/mergesort.test.c ### Exercises -_Allocating append_. Fill in an appropriate specification for +_Exercise_. Fill in an appropriate specification for `IntList_append2`. ```c title="exercises/list/append2.test.c" @@ -132,7 +132,7 @@ exercises/list/append2.test.c Note that it would not make sense to do the usual functional-programming trick of copying xs but sharing ys. (Why?) -_Length_. Add annotations as appropriate: +_Exercise_. Add annotations to the `length` function as appropriate: ```c title="exercises/list/length.c" --8<-- @@ -140,8 +140,8 @@ exercises/list/length.c --8<-- ``` -_List deallocation_. Fill in the body of the following procedure and -add annotations as appropriate: +_Exercise_. Fill in the body of the following list deallocation +procedure and add annotations as appropriate: ```c title="exercises/list/free.c" --8<-- @@ -149,7 +149,8 @@ exercises/list/free.c --8<-- ``` -_Length with an accumulator_. Add annotations as appropriate: +_Exercise_. Add annotations to the following "`length` with an +accumulator" function, as appropriate: ```c title="exercises/slf_length_acc.c" --8<-- diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 1836ed98..56ec4341 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -210,10 +210,12 @@ As before, we also have to instruct CN to `focus` ownership of individual array - the store returns a matching `RW` resource for index `j`; -- finally, we add `focus RW, j;` to allow CN to "`attach`" this resource to the iterated `RW` resource. CN issues a warning, because nothing is, in fact, extracted: we are using `focus` only for the "`reverse`" direction. - -{{ todo("BCP: That last bit is mysterious.") }} -{{ todo("Dhruv: See long explanation and issue here: rems-project/cerberus#498") }} +- finally, we add `focus RW, j;` to allow CN to "`attach`" this + resource to the iterated `RW` resource. CN issues a warning, because + nothing is, in fact, extracted: we are using `focus` only for the + "`reverse`" direction. {{ later("Dhruv: See long explanation and + issue here: rems-project/cerberus#498. BCP: Would it be useful to + bring any of that discussion here?") }} ### Exercises @@ -225,5 +227,5 @@ exercises/array_init_rev.c --8<-- ``` -{{ todo("A potential case study (involving nested iteration): +{{ later("Another potential example / case study, involving nested iteration: https://github.com/rems-project/cerberus/issues/848#issuecomment-2702085128") }} diff --git a/src/exercises/queue/empty.test.c b/src/exercises/queue/empty.test.c new file mode 100644 index 00000000..292a7e2e --- /dev/null +++ b/src/exercises/queue/empty.test.c @@ -0,0 +1,14 @@ +#include "./headers.test.h" + +struct queue* empty_queue () +/* --BEGIN-- */ +/*@ ensures take ret = QueuePtr_At(return); + ret == Nil{}; +@*/ +/* --END-- */ +{ + struct queue *p = malloc__queue(); + p->front = 0; + p->back = 0; + return p; +} diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c index fd9e6e1a..6e7ee59a 100644 --- a/src/exercises/slf17_get_and_free.test.c +++ b/src/exercises/slf17_get_and_free.test.c @@ -20,12 +20,12 @@ unsigned int get_and_free (unsigned int *p) return v; } -/* BCP: Why doesn't this compile? */ -// unsigned int tester() { -// /*@ requires true; -// ensures return = 42; -// @*/ -// unsigned int *p = malloc_and_set (42); -// unsigned int v = get_and_free (p); -// return v; -// } +unsigned int tester() +/*@ requires true; + ensures return == 41u32; +@*/ +{ + unsigned int *p = malloc_and_set (42); + unsigned int v = get_and_free (p); + return v; +} diff --git a/src/exercises/temp.test.c b/src/exercises/temp.test.c new file mode 100644 index 00000000..abc74fb5 --- /dev/null +++ b/src/exercises/temp.test.c @@ -0,0 +1,34 @@ +#include + +extern void* cn_malloc(size_t size); +extern void cn_free_sized(void *ptr, size_t size); + +unsigned int *malloc_and_set (unsigned int x) +/*@ ensures take P = RW(return); + P == x; +@*/ +{ + unsigned int *p = cn_malloc(sizeof(unsigned int)); + *p = x; + return p; +} + +unsigned int get_and_free (unsigned int *p) +/*@ requires take P = RW(p); + ensures return == P; +@*/ +{ + unsigned int v = *p; + cn_free_sized(p, sizeof(unsigned int)); + return v; +} + +unsigned int tester() +/*@ requires true; + ensures return == 41u32; +@*/ +{ + unsigned int *p = malloc_and_set (42); + unsigned int v = get_and_free (p); + return v; +} From 0656864f279ed53ce71a8eb70dd7c51a339f0162 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 11:20:56 -0400 Subject: [PATCH 097/158] Remove file added accidentally --- src/exercises/temp.test.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 src/exercises/temp.test.c diff --git a/src/exercises/temp.test.c b/src/exercises/temp.test.c deleted file mode 100644 index abc74fb5..00000000 --- a/src/exercises/temp.test.c +++ /dev/null @@ -1,34 +0,0 @@ -#include - -extern void* cn_malloc(size_t size); -extern void cn_free_sized(void *ptr, size_t size); - -unsigned int *malloc_and_set (unsigned int x) -/*@ ensures take P = RW(return); - P == x; -@*/ -{ - unsigned int *p = cn_malloc(sizeof(unsigned int)); - *p = x; - return p; -} - -unsigned int get_and_free (unsigned int *p) -/*@ requires take P = RW(p); - ensures return == P; -@*/ -{ - unsigned int v = *p; - cn_free_sized(p, sizeof(unsigned int)); - return v; -} - -unsigned int tester() -/*@ requires true; - ensures return == 41u32; -@*/ -{ - unsigned int *p = malloc_and_set (42); - unsigned int v = get_and_free (p); - return v; -} From 396017687760056b545e62b5a58e901ac13ac170 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 1 Apr 2025 16:18:19 -0400 Subject: [PATCH 098/158] Finished a first pass over the whole tutorial - lots still to do --- Makefile | 2 + .../case-studies/doubly-linked-lists.md | 26 +-- .../case-studies/imperative-queues.md | 79 +++---- .../case-studies/the-runway.md | 3 + .../case-studies/verif-doubly-linked-lists.md | 102 ++------- .../case-studies/verif-imperative-queues.md | 149 +++---------- .../case-studies/verif-the-runway.md | 209 +----------------- docs/getting-started/tutorials/lists.md | 6 +- .../tutorials/verif-external.md | 23 +- docs/getting-started/tutorials/verif-lists.md | 138 +++--------- .../tutorials/verif-numeric.md | 12 +- .../tutorials/verif-splitcase.md | 4 +- main.py | 10 + src/exercises/dll/predicates.h | 16 +- .../queue/{cn_types_1.h => cn_types_1.test.h} | 0 src/exercises/queue/cn_types_1.verif.h | 9 + src/exercises/queue/headers.test.h | 2 +- src/exercises/queue/headers.verif.h | 2 +- src/exercises/queue/push.test.c | 3 +- .../{slf_incr2.c => slf_incr2.verif.c} | 0 src/exercises/slf_length_acc.c | 6 + 21 files changed, 175 insertions(+), 626 deletions(-) rename src/exercises/queue/{cn_types_1.h => cn_types_1.test.h} (100%) create mode 100644 src/exercises/queue/cn_types_1.verif.h rename src/exercises/{slf_incr2.c => slf_incr2.verif.c} (100%) diff --git a/Makefile b/Makefile index 1c8910d8..c05028b7 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,8 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ # Extra dependencies _temp/tested/list/*.c : src/exercises/list/*.h _temp/verified/list/*.c : src/exercises/list/*.h +_temp/tested/queue/*.c : src/exercises/queue/*.h +_temp/verified/queue/*.c : src/exercises/queue/*.h # NOT WORKING? # _temp/tested/slf18_two_dice.c \ diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 167d4a6a..759883a5 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -1,6 +1,6 @@ # Doubly-linked Lists -{{ todo("BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. ") }} +{{ later("BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. ") }} A doubly linked list is a linked list where each node has a pointer to both the next node and the previous node. This allows for constant-time @@ -8,13 +8,11 @@ operations for adding or removing nodes anywhere in the list. Because of all the sharing in this data structure, the separation reasoning is a bit tricky. We'll give you the core definitions and -then invite you to help fill in the annotations for some of the +then invite you to help fill in the specifications for some of the functions that manipulate doubly linked lists. ## Types -{{ todo("BCP: Does that work for testing?") }} - First, here is the C type definition: ```c title="exercises/dll/c_types.h" @@ -42,8 +40,6 @@ we first own the node that is passed in. Then we follow all of the all the `next` pointers to own everything forwards from the node, to construct the `left` and `right` fields. -{{ todo("BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? ") }} - ```c title="exercises/dll/predicates.h" --8<-- exercises/dll/predicates.h @@ -51,21 +47,23 @@ exercises/dll/predicates.h ``` Note that `Dll_at` takes ownership of the node passed in, and then -calls `Own_Backwards` and `Own_Forwards`, which recursively take +calls `Take_Left` and `Take_Right`, which recursively take ownership of the rest of the list. {{ todo("BCP: Has ptr_eq been explained? It's useful -- should be! ") }} -Also, notice that `Own_Forwards` and `Own_Backwards` include `ptr_eq` +Also, notice that `Take_Right` and `Take_Left` include `ptr_eq` assertions for the `prev` and `next` pointers. This is to ensure that the nodes in the list are correctly doubly linked. For example, the -line `assert (ptr_eq(n.prev, prev_pointer));` in `Own_Forwards` +line `assert (ptr_eq(n.prev, prev_pointer));` in `Take_Right` ensures that the current node correctly points backward to the previous node in the list. The line `assert(ptr_eq(prev_node.next, p));` ensures that the previous node correctly points forward to the current node. +{{ todo("BCP: Are these asserts needed for testing? Try it and see!") }} + Before we move on to the functions that manipulate doubly linked lists, we need to define a few "getter" functions that will allow us to access the fields of our `Dll` datatype. This will make the @@ -132,9 +130,9 @@ solution, there's no need to include it here in-line, since people already know where to find the file. (But, of course, we should discuss it!) ") }} -```c title="solutions/dll/add.c" +```c title="solutions/dll/add.test.c" --8<-- -solutions/dll/add.c +solutions/dll/add.test.c --8<-- ``` @@ -163,9 +161,9 @@ also want all of our functions to return a pointer to the list. Because of this, we define a `struct` that includes an `int` and a `node`. -```c title="exercises/dll/dllist_and_int.h" +```c title="exercises/dll/dllist_and_int.test.h" --8<-- -exercises/dll/dllist_and_int.h +exercises/dll/dllist_and_int.test.h --8<-- ``` @@ -182,7 +180,7 @@ specification is appropriate. {{ todo("BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. ") }} -Now, here is the annotated version of the `remove` operation: +Now, here is the annotated version of `remove`: ```c title="solutions/dll/remove.test.c" --8<-- diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 9a41e3a7..b2813efb 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -16,28 +16,31 @@ the other pointing directly to the last cell in this list. If the queue is empty, both pointers are NULL. Abstractly, a queue just represents a list, so we can reuse the `List` -type from the list examples earlier in the tutorial. +type from the list examples earlier in the tutorial as the result type +when we `take` a queue from the heap. -```c title="exercises/queue/cn_types_1.h" +```c title="exercises/queue/cn_types_1.test.h" --8<-- -exercises/queue/cn_types_1.h +exercises/queue/cn_types_1.test.h --8<-- ``` Given a pointer to a `queue` struct, this predicate grabs ownership -of the struct, asserts that the `front` and `back` pointers must -either both be NULL or both be non-NULL, and then hands off to an +of the structthen hands off to an auxiliary predicate `QueueFB`. Note that `QueuePtr_At` returns a `List` -- that is, the abstract view of a queue heap structure is simply the sequence of elements that it contains. The difference between a queue and a singly or doubly linked list is simply one of concrete representation. -`QueueFB` is where the interesting part starts. (Conceptually, +{{ todo("BCP: Explain why the asserts are needed. (Testing fails if +we remove them.)") }} + +`QueueFB` is where the interesting part starts. Conceptually, it is part of `QueuePTR`, but CN currently allows conditional expressions only at the beginning of predicate definitions, not after a `take`, so we need to make a separate -auxiliary predicate.) +auxiliary predicate. ```c title="exercises/queue/cn_types_2.test.h" --8<-- @@ -67,9 +70,9 @@ walking down the cells from the front and gathering all the rest of them into a sequence. We take the result from `QueueAux` and `snoc` on the very last element. -{{ todo("BCP: Explain the asserts. (Why) are they useful -for testing? If they are not useful, make a testing-only version -that omits them! Ditto the QueueAux predicate below.") }} +{{ todo("BCP: The asserts here are not needed, but the ones above and +below are. Do we keep them and explain them? What is the +explanation??") }} Finally, the `QueueAux` predicate recurses down the list of cells and returns a list of their contents. @@ -95,9 +98,12 @@ returning it. Again, we need to help the CN verifier by explicitly informing it of the invariant that we know, that `C.next` cannot be null if `f` and `b` are different. -Now we need a bit of boilerplate: just as with linked lists, we need -to be able to allocate and deallocate queues and queue cells. There -are no interesting novelties here. +{{ todo("BCP: The asserts here seem to be sort-of-needed: removing +them leads to a ton of discards. Why? How do we explain this?") }} + +To make all this work, we also need a bit of boilerplate: just as with +linked lists, we need to be able to allocate and deallocate queues and +queue cells. There are no interesting novelties here. ```c title="exercises/queue/allocation.test.h" --8<-- @@ -107,6 +113,8 @@ exercises/queue/allocation.test.h +## Exercises + _Exercise_: The function for creating an empty queue just needs to set both of its fields to NULL. See if you can fill in its specification. @@ -118,10 +126,8 @@ exercises/queue/empty.test.c -The push and pop operations are more involved. Let's look at `push` -first. - -Here's the unannotated C code -- make sure you understand it. +_Exercise_: The push and pop operations are more involved. Let's look +at `push` first. Here's the unannotated C code. ```c title="exercises/queue/push.test.c" --8<-- @@ -129,31 +135,13 @@ exercises/queue/push.test.c --8<-- ``` -_Exercise_: Before reading on, see if you can write down a reasonable -top-level specification for this operation. - -One thing you might find odd about this code is that there's a -`return` statement at the end of each branch of the conditional, -rather than a single `return` at the bottom. The reason for this is -that, when CN analyzes a function body containing a conditional, it -effectively _copies_ all the code after the conditional into each of -the branches. Then, if verification encounters an error related to -this code -- e.g., "you didn't establish the `ensures` conditions at -the point of returning -- the error message will be confusing because -it will not be clear which branch of the conditional it is associated -with. - -Now, here is the annotated version of the `push` operation. - -```c title="solutions/queue/push.test.c" ---8<-- -solutions/queue/push.test.c ---8<-- -``` +Write down a reasonable top-level specification for this function and +test that the code satisfies it. +{{ later("What about mutation testing?") }} -Now let's look at the `pop` operation. Here is the un-annotated +_Exercise_: Now let's look at the `pop` operation. Here is the un-annotated version: ```c title="exercises/queue/pop_orig.broken.c" @@ -162,15 +150,6 @@ exercises/queue/pop_orig.broken.c --8<-- ``` -_Exercise_: Again, before reading on, see if you can write down a -plausible top-level specification and test its correctness. - -Here is the annotated `pop` code: - -```c title="exercises/queue/pop.test.c" ---8<-- -exercises/queue/pop.test.c ---8<-- -``` +Write down a top-level specification and test that the code satisfies it. -{{ todo("BCP: Needs some more exercises?") }} +{{ later("BCP: Needs some more exercises?") }} diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 99d020e1..92a606bb 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -7,6 +7,9 @@ try to whip it into better shape... (Later: It seems people do like it, because it is more like SUT code than the other examples. So we should make it better.) ") }} +{{ todo("BCP: It also still needs some fixing up after the +testing/verification split.") }} + Suppose we have been tasked with writing a program that simulates a runway at an airport. This airport is very small, so it only has one runway, which is used for both takeoffs and landings. We want to diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md index f086e3d3..a0771a3d 100644 --- a/docs/getting-started/case-studies/verif-doubly-linked-lists.md +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -1,107 +1,37 @@ # Doubly-linked Lists, Verified -{{ todo("Need updating after testing/verif split.") }} +{{ todo("BCP: This chapter still needs some fixing up.") }} -{{ todo("BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. ") }} +Verifying the doubly-linked list operations requires a few extra +annotations. -A doubly linked list is a linked list where each node has a pointer -to both the next node and the previous node. This allows for O(1) -operations for adding or removing nodes anywhere in the list. +The basic definitions are unchanged from the associated testing +chapter, except that we need some boilerplate for allocation and deallocation. -Because of all the sharing in this data structure, the separation -reasoning is a bit tricky. We'll give you the core definitions and -then invite you to help fill in the annotations for some of the -functions that manipulate doubly linked lists. - -First, here is the C type definition: - -```c title="exercises/dll/c_types.h" ---8<-- -exercises/dll/c_types.h ---8<-- -``` - -The idea behind the representation of this list is that we don't keep -track of the front or back, but rather we take any node in the list -and have a sequence to the left and to the right of that node. The `left` -and `right` are from the point of view of the node itself, so `left` -is kept in reverse order. Additionally, similarly to in the -`Imperative Queues` example, we can reuse the `List` type. - -```c title="exercises/dll/cn_types.h" +```c title="exercises/dll/allocation.verif.h" --8<-- -exercises/dll/cn_types.h ---8<-- -``` - -The predicate for this datatype is a bit complicated. The idea is that -we first own the node that is passed in. Then we follow all of the -`prev` pointers to own everything backwards from the node, and finally -all the `next` pointers to own everything forwards from the node, to -construct the `left` and `right` fields. - -{{ todo("BCP: Maybe rethink the Own_Forwards / Backwards naming -- would something like Queue_At_Left and Queue_At_Right be clearer?? ") }} - -```c title="exercises/dll/predicates.h" ---8<-- -exercises/dll/predicates.h ---8<-- -``` - -Note that `Dll_at` takes ownership of the node passed in, and then -calls `Own_Backwards` and `Own_Forwards`, which recursively take -ownership of the rest of the list. - -Also, notice that `Own_Forwards` and `Own_Backwards` include `ptr_eq` -assertions for the `prev` and `next` pointers. This is to ensure that -the nodes in the list are correctly doubly linked. For example, the -line `assert (ptr_eq(n.prev, prev_pointer));` in `Own_Forwards` -ensures that the current node correctly points backward to the -previous node in the list. The line `assert(ptr_eq(prev_node.next, -p));` ensures that the previous node correctly points forward to the -current node. - -Before we move on to the functions that manipulate doubly linked -lists, we need to define a few "getter" functions that will allow us -to access the fields of our `Dll` datatype. This will make the -specifications easier to write. - -```c title="exercises/dll/getters.h" ---8<-- -exercises/dll/getters.h ---8<-- -``` - -We also need some boilerplate for allocation and deallocation. - -```c title="exercises/dll/malloc_free.h" ---8<-- -exercises/dll/malloc_free.h ---8<-- -``` - -For convenience, we gather all of these files into a single header file. - -```c title="exercises/dll/headers.verif.h" ---8<-- -exercises/dll/headers.verif.h +exercises/dll/allocation.verif.h --8<-- ``` +## Singleton + Now we can move on to an initialization function. Since an empty list is represented as a null pointer, we will look at initializing a singleton list (or in other words, a list with only one item). -```c title="exercises/dll/singleton.c" +```c title="exercises/dll/singleton.verif.c" --8<-- -exercises/dll/singleton.c +exercises/dll/singleton.verif.c --8<-- ``` +## Add + The `add` and `remove` functions are where it gets a little tricker. Let's start with `add`. Here is the unannotated version: @@ -144,11 +74,11 @@ right part of the list is the same as before. Now, let's look at the annotations in the function body. CN can figure out the empty list case for itself, but it needs some help with the non-empty list case. The `split_case` on `is_null(n->prev)` -tells CN to unpack the `Own_Backwards` predicate. Without this +tells CN to unpack the `Take_Left` predicate. Without this annotation, CN cannot reason that we didn't lose the left half of the list before we return, and will claim we are missing a resource for returning. The `split_case` on `is_null(n->next->next)` is similar, -but for unpacking the `Own_Forwards` predicate. Note that we have to +but for unpacking the `Take_Right` predicate. Note that we have to go one more node forward to make sure that everything past `n->next` is still RW at the end of the function. @@ -215,7 +145,7 @@ Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` The annotations in the function body are similar to in the `add` function. Both of these `split_case` annotations are needed to unpack -the `Own_Forwards` and `Own_Backwards` predicates. Without them, CN +the `Take_Right` and `Take_Left` predicates. Without them, CN will not be able to reason that we didn't lose the left or right half of the list before we return and will claim we are missing a resource for returning. diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md index 19d316cb..8eab13c5 100644 --- a/docs/getting-started/case-studies/verif-imperative-queues.md +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -1,10 +1,10 @@ # Imperative Queues, Verified -{{ todo("Need updating after testing/verif split.") }} +To verify the queue operations, we'll need to add some annotations, +as usual. -A queue is a linked list with O(1) operations for adding things to one -end (the "back") and removing them from the other (the "front"). Here -are the C type definitions: +The basic definitions don't change. They are explained in the +testing version of this chapter. ```c title="exercises/queue/c_types.h" --8<-- @@ -12,127 +12,40 @@ exercises/queue/c_types.h --8<-- ``` -A queue consists of a pair of pointers, one pointing to the front -element, which is the first in a linked list of `queue_cell`s, -the other pointing directly to the last cell in this list. If the -queue is empty, both pointers are NULL. - -Abstractly, a queue just represents a list, so we can reuse the `List` -type from the list examples earlier in the tutorial. - ```c title="exercises/queue/cn_types_1.h" --8<-- exercises/queue/cn_types_1.h --8<-- ``` -Given a pointer to a `queue` struct, this predicate grabs ownership -of the struct, asserts that the `front` and `back` pointers must -either both be NULL or both be non-NULL, and then hands off to an -auxiliary predicate `QueueFB`. Note that `QueuePtr_At` returns a -`List` -- that is, the abstract view of a queue heap structure is -simply the sequence of elements that it contains. The difference -between a queue and a singly or doubly linked list is simply one of -concrete representation. - -`QueueFB` is where the interesting part starts. (Conceptually, -`QueueFB` is part of `QueuePTR`, but CN currently allows -conditional expressions only at the beginning of predicate -definitions, not after a `take`, so we need to make a separate -auxiliary predicate.) - -```c title="exercises/queue/cn_types_2.h" +```c title="exercises/queue/cn_types_2.verif.h" --8<-- -exercises/queue/cn_types_2.h +exercises/queue/cn_types_2.verif.h --8<-- ``` -First, we case on whether the `front` of the queue is NULL. If so, -then the queue is empty and we return the empty sequence. - -If the queue is not empty, we need to walk down the linked list of -elements and gather up all their values into a sequence. But we must -treat the last element of the queue specially, for two reasons. -First, since the `push` operation is going to follow the `back` -pointer directly to the last list cell without traversing all the -others, we need to `take` that element now rather than waiting to -get to it at the end of the recursion starting from the `front`. -Second, and relatedly, there will be two pointers to this final list -cell -- one from the `back` field and one from the `next` field of -the second to last cell (or the `front` pointer, if there is only -one cell in the list), so we need to be careful not to `take` this -cell twice. - -Accordingly, we begin by `take`-ing the tail cell and passing it -separately to the `QueueAux` predicate, which has the job of -walking down the cells from the front and gathering all the rest of -them into a sequence. We take the result from `QueueAux` and -`snoc` on the very last element. - -The `assert (is_null(B.next))` here gives the CN verifier a crucial -piece of information about an invariant of the representation: The -`back` pointer always points to the very last cell in the list, so -its `next` field will always be NULL. - -{{ todo("BCP: First point where testing and -verification split. Remove most of the material above here.") }} - -{{ todo("BCP: What about the second assert? ") }} - -{{ todo("BCP: How to help people guess that these are -needed?? ") }} - -Finally, the `QueueAux` predicate recurses down the list of -cells and returns a list of their contents. - ```c title="exercises/queue/cn_types_3.verif.h" --8<-- exercises/queue/cn_types_3.verif.h --8<-- ``` -Its first argument (`f`) starts out at `front` and progresses -through the queue on recursive calls; its `b` argument is always a -pointer to the very last cell. - -When `f` and `b` are equal, we have reached the last cell and -there is nothing to do. We don't even have to build a singleton -list: that's going to happen one level up, in `QueueFB`. - -Otherwise, we `take` the fields of the `f`, make a recurive -call to `QueueAux` to process the rest of the cells, and cons the -`first` field of this cell onto the resulting sequence before -returning it. Again, we need to help the CN verifier by explicitly -informing it of the invariant that we know, that `C.next` cannot be -null if `f` and `b` are different. - -Now we need a bit of boilerplate: just as with linked lists, we need -to be able to allocate and deallocate queues and queue cells. There -are no interesting novelties here. - ```c title="exercises/queue/allocation.verif.h" --8<-- exercises/queue/allocation.verif.h --8<-- ``` - - -_Exercise_: The function for creating an empty queue just needs to set -both of its fields to NULL. See if you can fill in its specification. - -```c title="exercises/queue/empty.c" +```c title="exercises/queue/empty.verif.c" --8<-- -exercises/queue/empty.c +exercises/queue/empty.verif.c --8<-- ``` - - -The push and pop operations are more involved. Let's look at `push` -first. +## Push -Here's the unannotated C code -- make sure you understand it. +The push and pop operations are more interesting. Let's look at `push` +first. Here's the unannotated C code. ```c title="exercises/queue/push_orig.broken.c" --8<-- @@ -140,19 +53,17 @@ exercises/queue/push_orig.broken.c --8<-- ``` -_Exercise_: Before reading on, see if you can write down a reasonable -top-level specification for this operation. - -One thing you might find odd about this code is that there's a -`return` statement at the end of each branch of the conditional, -rather than a single `return` at the bottom. The reason for this is -that, when CN analyzes a function body containing a conditional, it -effectively _copies_ all the code after the conditional into each of -the branches. Then, if verification encounters an error related to -this code -- e.g., "you didn't establish the `ensures` conditions at -the point of returning -- the error message will be confusing because -it will not be clear which branch of the conditional it is associated -with. +One thing you might find odd about this code (and that's a bit +different from the testing version) is that there's a `return` +statement at the end of each branch of the conditional, rather than a +single `return` at the bottom. The reason for this is that, when CN +analyzes a function body containing a conditional, it effectively +_copies_ all the code after the conditional into each of the +branches. After that happens, if verification encounters an error +related to this code -- e.g., "you didn't establish the `ensures` +conditions at the point of returning -- the error message will be +confusing because it will not be clear which branch of the conditional +it is associated with. Now, here is the annotated version of the `push` operation. @@ -206,7 +117,7 @@ oldback)`, but we don't care about this, since we want to prove `QueueFB(q->front, q->back)`. However, crucially, `QueueAux(q->front, oldback)` is still true. - +## Pop Now let's look at the `pop` operation. Here is the un-annotated version: @@ -237,7 +148,7 @@ CN which of the branches of the `if` at the beginning of the unpacked immediately because it is unconditional, but `QueueFB` cannot.) -{{ todo("BCP: the word 'unpack' is mysterious here. ") }} +{{ later("BCP: the word 'unpack' is mysterious here. ") }} The guard/condition for `QueueFB` is `is_null(front)`, which is why we need to do a `split_case` on this value. On one branch of the @@ -282,14 +193,11 @@ clauses. (Taking them just in the `requires` clause would imply that they are consumed and deallocated when the lemma is applied -- not what we want!) -{{ todo("BCP: The thing about ghost values is mysterious. ") }} -{{ todo("How to say it better?") }} +{{ todo("BCP: The thing about ghost values is mysterious. How to say it better?") }} (The only reason we can't currently prove this lemma in CN is that we -don't have `take`s in CN statements, because this is just a simple -unfolding.) - -{{ todo("BCP: Ugh. ") }} +don't have `take`s in CN statements. This is just a simple +unfolding.) {{ todo("BCP: Ugh. ") }} ## Exercises @@ -324,6 +232,5 @@ q->back`). Can you generalize the `snoc_facts` lemma to handle both cases? You can get past the dereference with a `split_case` but formulating the lemma before the `return` will be a bit more complicated. - -{{ todo("BCP: Again, this has not been shown to be +{{ later("BCP: Again, this has not been shown to be possible, but Dhruv believes it should be! ") }} diff --git a/docs/getting-started/case-studies/verif-the-runway.md b/docs/getting-started/case-studies/verif-the-runway.md index e5a1cb41..43585f7c 100644 --- a/docs/getting-started/case-studies/verif-the-runway.md +++ b/docs/getting-started/case-studies/verif-the-runway.md @@ -1,209 +1,8 @@ # Airport Simulation, Verified -{{ todo("BCP: I'm nervous about this case study -- it is not nearly as well debugged as the others, and it seems potentially quite confusing. I propose deleting it, but if other like it we can try to whip it into better shape... ") }} +_Exercise_: See if CN can verify the functions you wrote for the +exercise in the testing version of this chapter. Fix them if not. +Our solution requires no annotations besides the pre- and +poset-conditions. -Suppose we have been tasked with writing a program that simulates a -runway at an airport. This airport is very small, so it only has one -runway, which is used for both takeoffs and landings. We want to -verify that the runway is always used safely, by checking the -following informal specification: -1. The runway has two modes: departure mode and arrival mode. The two -modes can never be active at the same time. Neither mode is active -at the beginning of the day. -{{ todo("BCP: Would it be simpler to say it is in arrival mode at the beginning of the day? What difference would that make? (Saying there are two modes and then immediately introducing a third one is a bit confusing.) ") }} - -2. At any given moment, there is a waiting list of planes that need to - land at the airport and planes that need to leave the - airport. These are modeled with counters `W_A` for the number of - planes waiting to arrive, and `W_D` for the number of planes - waiting to depart. - -3. At any moment, a plane is either waiting to arrive, waiting to - depart, or on the runway. Once a plane has started arriving or - departing, the corresponding counter (`W_A` or `W_D`) is - decremented. There is no need to keep track of planes once they - have arrived or departed. Additionally, once a plane is waiting to - arrive or depart, it continues waiting until it has arrived or - departed. - -4. It takes 5 minutes for a plane to arrive or depart. During these 5 - minutes, no other plane may use the runway. We can keep track of - how long a plane has been on the runway with the - `Runway_Counter`. If the `Runway_Counter` is at 0, then there is - currently no plane using the runway, and it is clear for another - plane to begin arriving or departing. Once the `Runway_Counter` - reaches 5, we can reset it at the next clock tick. One clock tick - represents 1 minute. - -5. If there is at least one plane waiting to depart and no cars - waiting to arrive, then the runway is set to departure mode (and - vice versa for arrivals). - -6. If both modes of the runway are inactive and planes become ready to - depart and arrive simultaneously, the runway will activate arrival - mode first. If the runway is in arrival mode and there are planes - waiting to depart, no more than 3 planes may arrive from that time - point. When either no more planes are waiting to arrive or 3 planes - have arrived, the runway switches to departure mode. If the runway - is on arrival mode and no planes are waiting to depart, then the - runway may stay in arrival mode until a plane is ready to depart, - from which time the 3-plane limit is imposed (and vice versa for - departures). Put simply, if any planes are waiting for a mode that - is inactive, that mode will become active no more than 15 minutes - later (5 minutes for each of 3 planes). - -To encode all this in CN, we first need a way to describe the state of -the runway at a given time. We can use a _struct_ that includes the -following fields: - -- `ModeA` and `ModeD` to represent the arrival and departure modes, - respectively. We can define constants for `ACTIVE` and `INACTIVE`, - as described in the `Constants` section above. - -- `W_A` and `W_D` to represent the number of planes waiting to arrive - and depart, respectively. - -- `Runway_Time` to represent the time (in minutes) that a plane has - spent on the runway while arriving or departing. - -- `Plane_Counter` to represent the number of planes that have arrived - or departed while planes are waiting for the other mode. This will - help us keep track of the 3-plane limit as described in _(6)_. - -```c title="exercises/runway/state.h" ---8<-- -exercises/runway/state.h ---8<-- -``` - -Next, we need to specify what makes a state valid. We must define a -rigorous specification in order to ensure that the runway is always -safe and working as intended. Try thinking about what this might look -like before looking at the code below. - -```c title="exercises/runway/valid_state.h" ---8<-- -exercises/runway/valid_state.h ---8<-- -``` - -Let's walk through the specifications in `valid_state`: - -- The first two lines ensure that both modes in our model behave as intended: they can only be active or inactive. Any other value for these fields would be invalid. - -- The third line says that either arrival mode or departure mode must be inactive. This specification ensures that the runway is never in both modes at the same time. - -- The fourth line says that the number of planes waiting to arrive or depart must be non-negative. This makes sense: we can't have a negative number of planes! - -- The fifth line ensures that the runway time is between 0 and 5. This addresses how a plane takes 5 minutes on the runway as described in _(4)_. - -- The sixth line ensures that the plane counter is between 0 and 3. This is important for the 3-plane limit as described in _(6)_. - -- The seventh line refers to the state at the beginning of the day. If both modes are inactive, then the day has just begun, and thus no planes have departed yet. This is why the plane counter must be 0. - -- The eighth line says that if there is a plane on the runway, then one of the modes must be active. This is because a plane can only be on the runway if it is either arriving or departing. - -- The final two lines ensure that we are incrementing `Plane_Counter` only if there are planes waiting for the other mode, as described in _(6)_. - -Now that we have the tools to reason about the state of the runway formally, let's start writing some functions. - -First, let's look at an initialization function and functions to update `Plane_Counter`. Step through these yourself and make sure you understand the reasoning behind each specification. - -```c title="exercises/runway/funcs1.h" ---8<-- -exercises/runway/funcs1.h ---8<-- -``` - -_Exercise_: Now try adding your own specifications to the following -functions. Make sure that you specify a valid state as a pre- and -post-condition for every function. If you get stuck, the solution is -in the solutions folder. - -```c title="exercises/runway/funcs2.c" ---8<-- -exercises/runway/funcs2.c ---8<-- -``` - - - -## Acknowledgment of Support and Disclaimer - -This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies (DARPA) under Contract No. FA8750-24-C-B044, a European Research Council (ERC) Advanced Grant “ELVER” under the European Union’s Horizon 2020 research and innovation programme (grant agreement no. 789108), and additional funding from Google. The opinions, findings, and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the Air Force Research Laboratory (AFRL). - - - -{{ todo(" -Further topics: - -- doubly linked lists -- Trees: - deep copy - sum - maybe the accumulating sum -- cn_function -- pack -- bitwise functions (operators are not present in the logical language) -- 'ownership' in Rust vs. CN -- tips amnd tricks -- - cf. [](https://dafny.org/dafny/DafnyRef/DafnyRef.html#sec-verification) -- more data structures to try out - [](https://www.geeksforgeeks.org/data-structures/#most-popular-data-structures) -- Maybe add some explanation of -- or at least a pointer to -- - Dhruv's Iris-in-C examples: - pop_queue_lemma_stages.c - push_queue_induction.c - pop_queue_unified.c - -Further exercises: - -- Some exercises that get THEM to write predicates, datatype - declarations, etc. - -Misc things to do: - -- replace 0 with NULL in specs - -- naming issues - rename == to ptr_eq everywhere in specs - rename list to List in filenames. or go more radical and rename List to cnlist - consider renaming SLList_At to just List (and sllist to just list, - etc.) everywhere (since we are only dealing with one kind of list - in the tutorial, the extra pedantry is not getting us much; and - this simplification would avoid trying to fix conventions that all - CN code should use everywhere...) - - - related: the name Cons is awkward for several reasons: - - long / verbose (nothing to do about that, I guess) - - Seq is capitalized, but it means List - - most important part is buried in the middle - - What are the established C conventions here?? - -- some of the examples use int while the exercises that follow use - unsigned int. This is a needless source of potential confusion. - -- everyplace we do storage allocation, we should really allow the - malloc call to return NULL if it wants to; the caller should - explicitly check that it didn't get back NULL. This requires - defining an 'exit' function with trivial pre- and postconditions - (true / false). - -- In queue.c, when I tried /_@ unfold QueueAux (F.front, F.back, - B.first); @_/ I was confused by 'the specification function - `QueueAux' is not declared'. I guess this is, again, the - distinction between functions and predicates...? - -- In debugging the queue example, The fact that some of the - constraints in the error report are forced while others are random - values filled in by the SMT solver is pretty problematic... - ---- - -For later: - -Alternative formatting tools to consider at some point (not now!): -probably the best fit: -[](https://myst-parser.readthedocs.io/en/latest/) -another very standard one to consider: -alternative: [](https://www.sphinx-doc.org/en/master/index.html) - -Misc notes: - -- Nb: take V = RW(p) === p |-t-> V -") }} diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index 5b815913..5eea78bb 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -149,8 +149,10 @@ exercises/list/free.c --8<-- ``` -_Exercise_. Add annotations to the following "`length` with an -accumulator" function, as appropriate: +_Exercise_. Add a specification to the following "`length` with an +accumulator" function: + +{{ todo("BCP: move the file!") }} ```c title="exercises/slf_length_acc.c" --8<-- diff --git a/docs/getting-started/tutorials/verif-external.md b/docs/getting-started/tutorials/verif-external.md index 633d168d..5d6a8df2 100644 --- a/docs/getting-started/tutorials/verif-external.md +++ b/docs/getting-started/tutorials/verif-external.md @@ -1,12 +1,10 @@ # Working with External Lemmas -{{ todo("BCP: This section should also show what the proof of the lemmas +{{ later("BCP: This section should also show what the proof of the lemmas looks like on the Coq side! ") }} +{{ later(" Dhruyv: There are some examples in the Cerberus repo tests? rems-project/cerberus@20d9d5c ") }} -{{ todo("BCP: This needs to be filled in urgently!! ") }} -{{ todo(" Dhruyv: There are some examples in the Cerberus repo tests? rems-project/cerberus@20d9d5c ") }} - -{{ todo("BCP: +{{ later("BCP: think about capitalization, etc., for lemma names push_lemma should be Push_lemma, I guess? Or lemma_push? snoc_facts should be lemma_Snoc or something @@ -44,7 +42,7 @@ Having stated these lemmas, we can now complete the specification and proof of `IntList_rev`. Note the two places where `apply` is used to tell the SMT solver where to pay attention to the lemmas. -{{ todo("BCP: Why can't it always pay attention to them? (I guess +{{ hidden("BCP: Why can't it always pay attention to them? (I guess 'performance', but at least it would be nice to be able to declare a general scope where a given set of lemmas might be needed, rather than specifying exactly where to use them.)") }} @@ -58,7 +56,7 @@ exercises/list/rev.c For comparison, here is another way to write the program, using a while loop instead of recursion, with its specification and proof. -{{ todo("BCP: Why 0 instead of NULL?? (Is 0 better?) ") }} +{{ hidden("BCP: Why 0 instead of NULL?? (Is 0 better?) ") }} ```c title="exercises/list/rev_alt.c" --8<-- @@ -77,14 +75,3 @@ exercises/list/rev_alt.c exercises/slf_sized_stack.c --8<-- ``` - -{{ todo(" ====================================================================== ") }} - - - -## More on CN Annotations - -{{ todo("Introduce all the different sorts of CN annotations (e.g., - `split_case`) individually with small examples and exercises.") }} - - diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index 992cd7c3..835ed681 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -1,75 +1,16 @@ # Lists, verified -{{ todo("BCP: intro needed") }} +Now let's see what's needed to fully verify linked-list operations. -As before, we need slightly different functions for allocating and -deallocating linked list cells: - -```c title="exercises/list/c_types.verif.h" ---8<-- -exercises/list/c_types.verif.h ---8<-- -``` - -{{ todo("BCP: Per discussion with Christopher, Cassia, and Daniel, the word 'predicate' is quite confusing for newcomers (in logic, predicates do not return things!). A more neutral word might make for significantly easier onboarding.") }} -{{ todo("Dhruv: Or no keyword? rems-project/cerberus#304 How about traversal?") }} -{{ todo(" BCP: No keyword sounds even better. But 'traversal' in the interim is not bad. Or maybe 'extractor' or something like that?") }} - -To write specifications for C functions that manipulate lists, we need -to define a CN "predicate" that describes specification-level list -structures, as one would do in ML, Haskell, or Coq. We use the -datatype `List` for CN-level lists. - -Intuitively, the `SLList_At` predicate walks over a singly-linked -pointer structure in the C heap and extracts an `RW` version of -the CN-level list that it represents. - -```c title="exercises/list/cn_types.h" ---8<-- -exercises/list/cn_types.h ---8<-- -``` - -We can also write _functions_ on CN-level lists by ordinary functional -programming (in a slightly strange, unholy-union-of-C-and-Rust -syntax): - -```c title="exercises/list/hdtl.h" ---8<-- -exercises/list/hdtl.h ---8<-- -``` - -We use the `SLList_At` predicate to specify functions returning the -empty list and the cons of a number and a list. - -```c title="exercises/list/constructors.h" ---8<-- -exercises/list/constructors.h ---8<-- -``` - -Finally, we can collect all this stuff into a single header file. (We -add the usual C `#ifndef` gorp to avoid complaints from the compiler -if it happens to get included twice from the same source file later.) - -```c title="exercises/list/headers.verif.h" ---8<-- -exercises/list/headers.verif.h ---8<-- -``` - -{{ todo("BCP: The 'return != NULL' should not be needed, but to remove it -we need to change the callers of all the allocation functions to check -for NULL and exit (which requires adding a spec for exit).") }} +The basic definitions collected in the file `lists/headers.verif.h` +are pretty much the same as for the testing version of lists. The +only difference is that, as before, we need to define slightly +different functions for allocating and deallocating linked list cells. ### Append -With this basic infrastructure in place, we can start specifying and -verifying list-manipulating functions. First, `append`. - -Here is its specification (in a separate file, because we'll want to -use it multiple times below.) +The specification of `append` is identical to the testing +version: ```c title="exercises/list/append.h" --8<-- @@ -77,13 +18,13 @@ exercises/list/append.h --8<-- ``` -{{ todo("BCP: Here's the first place where the verification version differs. -Tidy the file above and below!") }} - -Here is a simple destructive `append` function. Note the two uses -of the `unfold` annotation in the body, which are needed to help the -CN typechecker. The `unfold` annotation is an instruction to CN to replace a call to a recursive (CN) function (in this case `append`) -with its definition, and is necessary because CN is unable to automatically determine when and where to expand recursive definitions on its own. +And here is the verified code for a simple destructive implementation +of `append`. Note the two uses of the `unfold` annotation in the +body, which are needed to help the CN typechecker. This annotation is +an instruction to CN to replace a call to a recursive (CN) function +(in this case `append`) with its definition, and is necessary because +CN is unable to automatically determine when and where to expand +recursive definitions on its own. {{ todo("BCP: Can someone add a more technical explanation of why they are needed and exactly what they do?") }} @@ -95,38 +36,25 @@ exercises/list/append.verif.c ### List copy -Here is an allocating list copy function with a pleasantly light -annotation burden. - -```c title="exercises/list/copy.c" ---8<-- -exercises/list/copy.c ---8<-- -``` +The verified version of the list copy function is identical to the +testing version. No additional annotations are needed. ### Merge sort -{{ todo("BCP: This could use a gentler explanation (probably in pieces). But -much of it will be in lists.md, not here.") }} +Finally, here is in-place mergesort, with all necessary `unfold` +annotations so that it is accepted by the CN verifier. -Finally, here is a slightly tricky in-place version of merge sort that -avoids allocating any new list cells in the splitting step by taking -alternate cells from the original list and linking them together into -two new lists of roughly equal lengths. - -{{ todo("BCP: Nit: Merge multiple requires and ensures clauses into one") }} - -```c title="exercises/list/mergesort.c" +```c title="solutions/list/mergesort.verif.c" --8<-- -exercises/list/mergesort.c +solutions/list/mergesort.verif.c --8<-- ``` ### Exercises -_Allocating append_. Fill in the CN annotations on -`IntList_append2`. (You will need some in the body as well as at -the top.) +_Exercise_. Fill in the CN annotations on the `IntList_append2` +function below. (You will need some in the body as well as at the +top.) ```c title="exercises/list/append2.c" --8<-- @@ -134,10 +62,7 @@ exercises/list/append2.c --8<-- ``` -Note that it would not make sense to do the usual -functional-programming trick of copying xs but sharing ys. (Why?) - -_Length_. Add annotations as appropriate: +_Exercise_. Add annotations to `length` as appropriate: ```c title="exercises/list/length.c" --8<-- @@ -145,8 +70,8 @@ exercises/list/length.c --8<-- ``` -_List deallocation_. Fill in the body of the following procedure and -add annotations as appropriate: +_Exercise_. Fill in the body of the following list deallocation +function and add annotations as appropriate: ```c title="exercises/list/free.c" --8<-- @@ -154,14 +79,11 @@ exercises/list/free.c --8<-- ``` -_Length with an accumulator_. Add annotations as appropriate: - -{{ todo("BCP: Removing / forgetting the unfold in this one gives a truly") }} -{{ todo(" bizarre error message saying that the constraint `n == (n + length(L1))`") }} -{{ todo(" is unsatisfiable...") }} +_Exercise_. Add annotations as appropriate: -{{ todo("Sainati: when I went through the tutorial, the file provided for this exercise was already 'complete' in that") }} -{{ todo(" it already had all the necessary annotations present for CN to verify it") }} +{{ later("BCP: Removing / forgetting the unfold in this one gives a +truly bizarre error message saying that the constraint `n == (n + +length(L1))` is unsatisfiable...") }} ```c title="exercises/slf_length_acc.c" --8<-- diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 91bd2342..49184e7e 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -1,5 +1,7 @@ # More on Numeric Types (Verification) +{{ todo("Section under construction...") }} + TODO - We need to talk in another (non-optional) section about signed types in the context of specification and testing. @@ -50,13 +52,11 @@ solutions/add_0.c In detail: -- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`.{{ todo("BCP: I understand this reasoning, but I wonder whether it introduces more confusion than it avoids -- it means there are two ways of writing everything, and people have to remember whether the particular thing they are writing right now is C or CN... ") }}{{ todo(" BCP: Hopefully we are moving toward unifying these notations anyway? ") }} +- Instead of C syntax, CN uses Rust-like syntax for integer types, such as `u32` for 32-bit unsigned integers and `i64` for signed 64-bit integers, to make their sizes unambiguous. Here, `x` and `y`, of C-type `int`, have CN type `i32`.{{ hidden("BCP: I understand this reasoning, but I wonder whether it introduces more confusion than it avoids -- it means there are two ways of writing everything, and people have to remember whether the particular thing they are writing right now is C or CN... Hopefully we are moving toward unifying these notations anyway? ") }} - To define `Sum` we cast `x` and `y` to the larger `i64` type, using syntax `(i64)`, which is large enough to hold the sum of any two `i32` values. - Finally, we require this sum to be between the minimal and maximal `int` values. Integer constants, such as `-2147483648i64`, must specifiy their CN type (`i64`). - {{ todo("BCP: We should use the new ' syntax (or whatever it turned out to be) for numeric constants ") }} - {{ todo("Dhruv: Yet to be implemented: rems-project/cerberus#337 ") }} Running CN on the annotated program passes without errors. This means that, with our specified precondition, `add` is safe to execute. @@ -89,9 +89,7 @@ coercion `(i64)`. ## Error reports -{{ todo("*Most of this material needs to be moved to -the first section where we talk about verification, but it will need a -different example (not involving i32 or UB)...*") }} +{{ todo("Update") }} In the original example, CN reported a type error due to C undefined behavior. While that example was perhaps simple enough to guess the @@ -220,8 +218,6 @@ Let’s apply what we know so far to another simple arithmetic example. The function `doubled`, shown below, takes an int `n`, defines `a` as `n` incremented, `b` as `n` decremented, and returns the sum of the two. -{{ todo("BCP: Is it important to number the slf examples? If so, we should do it consistently, but IMO it is not. Better to rename them without numbers. ") }} - ```c title="exercises/slf1_basic_example_let.signed.c" --8<-- exercises/slf1_basic_example_let.signed.c diff --git a/docs/getting-started/tutorials/verif-splitcase.md b/docs/getting-started/tutorials/verif-splitcase.md index 9473efd8..907d86c4 100644 --- a/docs/getting-started/tutorials/verif-splitcase.md +++ b/docs/getting-started/tutorials/verif-splitcase.md @@ -1,9 +1,9 @@ # (Verification) Case Analysis -{{ todo("This section needs writing...") }} +{{ todo("This section is under construction...") }} To verify the `slf_incr2` example, we need one more CN annotation in -the body of the +the body of the function. ```c title="exercises/slf_incr2.verif.c" --8<-- diff --git a/main.py b/main.py index 2484615b..9959ac73 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,9 @@ def common(mesg, color): "Format a TODO (common)" return "[[" + mesg + "]]" + ################################################################# + # These should be suppressed for readers that are not tutorial developers: + @env.macro def todo(mesg): "Format a TODO" @@ -17,4 +20,11 @@ def later(mesg): "Format a TODO for later" return common(mesg, "lightgray") + ################################################################# + # These should always be displayed / hidden + + @env.macro + def hidden(mesg): + "Format a TODO that should not actually appear right now" + return "" diff --git a/src/exercises/dll/predicates.h b/src/exercises/dll/predicates.h index d8f00e11..5b51db7f 100644 --- a/src/exercises/dll/predicates.h +++ b/src/exercises/dll/predicates.h @@ -4,13 +4,13 @@ predicate (datatype Dll) Dll_at (pointer p) { return Empty_Dll{}; } else { take n = RW(p); - take L = Own_Backwards(n.prev, p, n); - take R = Own_Forwards(n.next, p, n); + take L = Take_Left(n.prev, p, n); + take R = Take_Right(n.next, p, n); return Nonempty_Dll{left: L, curr: n, right: R}; } } -predicate (datatype List) Own_Forwards (pointer p, +predicate (datatype List) Take_Right (pointer p, pointer prev_pointer, struct dllist prev_dllist) { if (is_null(p)) { @@ -18,13 +18,13 @@ predicate (datatype List) Own_Forwards (pointer p, } else { take P = RW(p); assert (ptr_eq(P.prev, prev_pointer)); - assert(ptr_eq(prev_dllist.next, p)); - take T = Own_Forwards(P.next, p, P); + assert (ptr_eq(prev_dllist.next, p)); + take T = Take_Right(P.next, p, P); return Cons{Head: P.data, Tail: T}; } } -predicate (datatype List) Own_Backwards (pointer p, +predicate (datatype List) Take_Left (pointer p, pointer next_pointer, struct dllist next_dllist) { if (is_null(p)) { @@ -32,8 +32,8 @@ predicate (datatype List) Own_Backwards (pointer p, } else { take P = RW(p); assert (ptr_eq(P.next, next_pointer)); - assert(ptr_eq(next_dllist.prev, p)); - take T = Own_Backwards(P.prev, p, P); + assert (ptr_eq(next_dllist.prev, p)); + take T = Take_Left(P.prev, p, P); return Cons{Head: P.data, Tail: T}; } } diff --git a/src/exercises/queue/cn_types_1.h b/src/exercises/queue/cn_types_1.test.h similarity index 100% rename from src/exercises/queue/cn_types_1.h rename to src/exercises/queue/cn_types_1.test.h diff --git a/src/exercises/queue/cn_types_1.verif.h b/src/exercises/queue/cn_types_1.verif.h new file mode 100644 index 00000000..2c975e96 --- /dev/null +++ b/src/exercises/queue/cn_types_1.verif.h @@ -0,0 +1,9 @@ +/*@ +predicate (datatype List) QueuePtr_At (pointer q) { + take Q = RW(q); + assert ( (is_null(Q.front) && is_null(Q.back)) + || (!is_null(Q.front) && !is_null(Q.back))); + take L = QueueFB(Q.front, Q.back); + return L; +} +@*/ diff --git a/src/exercises/queue/headers.test.h b/src/exercises/queue/headers.test.h index 5b65c5c7..3b1a4a7f 100644 --- a/src/exercises/queue/headers.test.h +++ b/src/exercises/queue/headers.test.h @@ -5,7 +5,7 @@ #include "../list/snoc.h" #include "./c_types.h" -#include "./cn_types_1.h" +#include "./cn_types_1.test.h" #include "./cn_types_2.test.h" #include "./cn_types_3.test.h" diff --git a/src/exercises/queue/headers.verif.h b/src/exercises/queue/headers.verif.h index b6bc8034..333fc077 100644 --- a/src/exercises/queue/headers.verif.h +++ b/src/exercises/queue/headers.verif.h @@ -5,7 +5,7 @@ #include "../list/snoc.h" #include "./c_types.h" -#include "./cn_types_1.h" +#include "./cn_types_1.verif.h" #include "./cn_types_2.verif.h" #include "./cn_types_3.verif.h" diff --git a/src/exercises/queue/push.test.c b/src/exercises/queue/push.test.c index 1c86b076..5d5fddde 100644 --- a/src/exercises/queue/push.test.c +++ b/src/exercises/queue/push.test.c @@ -14,11 +14,10 @@ void push_queue (int x, struct queue *q) if (q->back == 0) { q->front = c; q->back = c; - return; } else { struct queue_cell *oldback = q->back; q->back->next = c; q->back = c; - return; } + return; } diff --git a/src/exercises/slf_incr2.c b/src/exercises/slf_incr2.verif.c similarity index 100% rename from src/exercises/slf_incr2.c rename to src/exercises/slf_incr2.verif.c diff --git a/src/exercises/slf_length_acc.c b/src/exercises/slf_length_acc.c index e019a773..19d92139 100644 --- a/src/exercises/slf_length_acc.c +++ b/src/exercises/slf_length_acc.c @@ -16,6 +16,7 @@ function [rec] (u32) length(datatype List xs) { @*/ void IntList_length_acc_aux (struct sllist *xs, unsigned int *p) +/* --BEGIN-- */ /*@ requires take L1 = SLList_At(xs); take P = RW(p); ensures take L1_post = SLList_At(xs); @@ -23,8 +24,11 @@ void IntList_length_acc_aux (struct sllist *xs, unsigned int *p) L1 == L1_post; P_post == P + length(L1); @*/ +/* --END-- */ { +/* --BEGIN-- */ /*@ unfold length(L1); @*/ +/* --END-- */ if (xs == 0) { } else { *p = *p + 1; @@ -33,11 +37,13 @@ void IntList_length_acc_aux (struct sllist *xs, unsigned int *p) } unsigned int IntList_length_acc (struct sllist *xs) +/* --BEGIN-- */ /*@ requires take Xs = SLList_At(xs); ensures take Xs_post = SLList_At(xs); Xs == Xs_post; return == length(Xs); @*/ +/* --END-- */ { unsigned int *p = refUnsignedInt(0); IntList_length_acc_aux(xs, p); From e55c37aa09d6dac780170105e8b2fb78aa996453 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 3 Apr 2025 10:56:03 -0400 Subject: [PATCH 099/158] polishing dllist --- Makefile | 11 ++- .../case-studies/doubly-linked-lists.md | 81 ++++++++++--------- .../case-studies/verif-doubly-linked-lists.md | 79 +++++++----------- src/exercises/dll/add_orig.broken.c | 27 ------- src/exercises/dll/getters.h | 22 ----- src/exercises/{dll => dllist}/add.c | 12 ++- src/exercises/{dll => dllist}/add.test.c | 8 +- .../{dll => dllist}/allocation.test.h | 0 .../{dll => dllist}/allocation.verif.h | 0 src/exercises/{dll => dllist}/c_types.h | 0 src/exercises/{dll => dllist}/cn_types.h | 6 +- .../{dll => dllist}/dllist_and_int.test.h | 0 .../{dll => dllist}/dllist_and_int.verif.h | 0 src/exercises/dllist/getters.h | 22 +++++ src/exercises/{dll => dllist}/headers.test.h | 0 src/exercises/{dll => dllist}/headers.verif.h | 0 src/exercises/{dll => dllist}/predicates.h | 6 +- src/exercises/{dll => dllist}/remove.test.c | 10 +-- src/exercises/{dll => dllist}/remove.verify.c | 10 +-- .../{dll => dllist}/remove_orig.broken.c | 0 .../{dll => dllist}/singleton.test.c | 4 +- .../{dll => dllist}/singleton.verif.c | 4 +- 22 files changed, 132 insertions(+), 170 deletions(-) delete mode 100644 src/exercises/dll/add_orig.broken.c delete mode 100644 src/exercises/dll/getters.h rename src/exercises/{dll => dllist}/add.c (82%) rename src/exercises/{dll => dllist}/add.test.c (85%) rename src/exercises/{dll => dllist}/allocation.test.h (100%) rename src/exercises/{dll => dllist}/allocation.verif.h (100%) rename src/exercises/{dll => dllist}/c_types.h (100%) rename src/exercises/{dll => dllist}/cn_types.h (51%) rename src/exercises/{dll => dllist}/dllist_and_int.test.h (100%) rename src/exercises/{dll => dllist}/dllist_and_int.verif.h (100%) create mode 100644 src/exercises/dllist/getters.h rename src/exercises/{dll => dllist}/headers.test.h (100%) rename src/exercises/{dll => dllist}/headers.verif.h (100%) rename src/exercises/{dll => dllist}/predicates.h (88%) rename src/exercises/{dll => dllist}/remove.test.c (80%) rename src/exercises/{dll => dllist}/remove.verify.c (81%) rename src/exercises/{dll => dllist}/remove_orig.broken.c (100%) rename src/exercises/{dll => dllist}/singleton.test.c (84%) rename src/exercises/{dll => dllist}/singleton.verif.c (84%) diff --git a/Makefile b/Makefile index c05028b7..f0201d9c 100644 --- a/Makefile +++ b/Makefile @@ -80,10 +80,13 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/slf15_basic_succ_using_incr_attempt_.c # Extra dependencies -_temp/tested/list/*.c : src/exercises/list/*.h -_temp/verified/list/*.c : src/exercises/list/*.h -_temp/tested/queue/*.c : src/exercises/queue/*.h -_temp/verified/queue/*.c : src/exercises/queue/*.h +define extradeps +_temp/tested/$1/*.c : src/exercises/$1/*.h +_temp/verified/$1/*.c : src/exercises/$1/*.h +endef +$(eval $(call extradeps,list)) +$(eval $(call extradeps,queue)) +$(eval $(call extradeps,dllist)) # NOT WORKING? # _temp/tested/slf18_two_dice.c \ diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 759883a5..7d2e1f7e 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -15,9 +15,9 @@ functions that manipulate doubly linked lists. First, here is the C type definition: -```c title="exercises/dll/c_types.h" +```c title="exercises/dllist/c_types.h" --8<-- -exercises/dll/c_types.h +exercises/dllist/c_types.h --8<-- ``` @@ -28,9 +28,9 @@ and `right` are from the point of view of the node itself, so `left` is kept in reverse order. Additionally, similarly to in the `Imperative Queues` example, we can reuse the `List` type. -```c title="exercises/dll/cn_types.h" +```c title="exercises/dllist/cn_types.h" --8<-- -exercises/dll/cn_types.h +exercises/dllist/cn_types.h --8<-- ``` @@ -40,13 +40,13 @@ we first own the node that is passed in. Then we follow all of the all the `next` pointers to own everything forwards from the node, to construct the `left` and `right` fields. -```c title="exercises/dll/predicates.h" +```c title="exercises/dllist/predicates.h" --8<-- -exercises/dll/predicates.h +exercises/dllist/predicates.h --8<-- ``` -Note that `Dll_at` takes ownership of the node passed in, and then +Note that `DlList_at` takes ownership of the node passed in, and then calls `Take_Left` and `Take_Right`, which recursively take ownership of the rest of the list. @@ -66,28 +66,28 @@ current node. Before we move on to the functions that manipulate doubly linked lists, we need to define a few "getter" functions that will allow us -to access the fields of our `Dll` datatype. This will make the +to access the fields of our `DlList` datatype. This will make the specifications easier to write. -```c title="exercises/dll/getters.h" +```c title="exercises/dllist/getters.h" --8<-- -exercises/dll/getters.h +exercises/dllist/getters.h --8<-- ``` We also need the usual boilerplate for allocation and deallocation. -```c title="exercises/dll/allocation.test.h" +```c title="exercises/dllist/allocation.test.h" --8<-- -exercises/dll/allocation.test.h +exercises/dllist/allocation.test.h --8<-- ``` For convenience, we gather all of these files into a single header file. -```c title="exercises/dll/headers.test.h" +```c title="exercises/dllist/headers.test.h" --8<-- -exercises/dll/headers.test.h +exercises/dllist/headers.test.h --8<-- ``` @@ -99,9 +99,9 @@ Now we can move on to an initialization function. Since an empty list is represented as a null pointer, we will look at initializing a singleton list (or in other words, a list with only one item). -```c title="exercises/dll/singleton.test.c" +```c title="exercises/dllist/singleton.test.c" --8<-- -exercises/dll/singleton.test.c +exercises/dllist/singleton.test.c --8<-- ``` @@ -112,40 +112,38 @@ exercises/dll/singleton.test.c The `add` and `remove` functions are where it gets a little tricker. Let's start with `add`. Here is the unannotated version: -```c title="exercises/dll/add.test.c" +```c title="exercises/dllist/add.test.c" --8<-- -exercises/dll/add.test.c +exercises/dllist/add.test.c --8<-- ``` _Exercise_: Before reading on, see if you can figure out what specification is appropriate. -{{ todo("BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. ") }} +{{ todo("BCP: I seriously doubt they are going to be able to come up +with this specification on their own! We need to set it up earlier +with a simpler example (maybe in a whole earlier section) showing how +to use conditionals in specs. ") }} Now, here is the annotated version of the `add` operation: -{{ todo("BCP: If we're not going to _discuss_ the -solution, there's no need to include it here in-line, since people -already know where to find the file. (But, of course, we should -discuss it!) ") }} - -```c title="solutions/dll/add.test.c" +```c title="solutions/dllist/add.test.c" --8<-- -solutions/dll/add.test.c +solutions/dllist/add.test.c --8<-- ``` The `requires` clause is straightforward. We need to own the list centered around -the node that `n` points to. `Before` is a `Dll` +the node that `n` points to. `Before` is a `DlList` that is either empty, or it has a List to the left, the current node that `n` points to, and a List to the right. This corresponds to the state of the list when it is passed in. In the ensures clause, we again establish ownership of the list, but this time it is centered around the added node. This means that -`After` is a `Dll` structure similar to `Before`, except that the node +`After` is a `DlList` structure similar to `Before`, except that the node `curr` is now the created node. The old `curr` is pushed into the left part of the new list. The conditional operator in the `ensures` clause is saying that if the list was empty coming in, it now is a singleton @@ -153,6 +151,9 @@ list. Otherwise, the left left part of the list now has the data from the old `curr` node, the new `curr` node is the added node, and the right part of the list is the same as before. +{{ later("BCP: More discussion might be good!") }} + + ## Remove Finally, let's look at the `remove` operation. Traditionally, a `remove` @@ -161,17 +162,17 @@ also want all of our functions to return a pointer to the list. Because of this, we define a `struct` that includes an `int` and a `node`. -```c title="exercises/dll/dllist_and_int.test.h" +```c title="exercises/dllist/dllist_and_int.test.h" --8<-- -exercises/dll/dllist_and_int.test.h +exercises/dllist/dllist_and_int.test.h --8<-- ``` Now we can look at the code for the `remove` operation. Here is the un-annotated version: -```c title="exercises/dll/remove.test.c" +```c title="exercises/dllist/remove.test.c" --8<-- -exercises/dll/remove.test.c +exercises/dllist/remove.test.c --8<-- ``` @@ -182,19 +183,19 @@ specification is appropriate. Now, here is the annotated version of `remove`: -```c title="solutions/dll/remove.test.c" +```c title="solutions/dllist/remove.test.c" --8<-- -solutions/dll/remove.test.c +solutions/dllist/remove.test.c --8<-- ``` First, let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we assign the node of that list to the identifier `del` -to make our spec more readable. So `Before` refers to the `Dll` when the function is called, and `del` refers to the node that will be deleted. +to make our spec more readable. So `Before` refers to the `DlList` when the function is called, and `del` refers to the node that will be deleted. Then in the `ensures` clause, we must take ownership -of the `node_and_int` struct as well as the `Dll` that -the node is part of. Here, `After` refers to the `Dll` +of the `node_and_int` struct as well as the `DlList` that +the node is part of. Here, `After` refers to the `DlList` when the function returns. We ensure that the int that is returned is the value of the deleted node, as intended. Then we have a complicated nested ternary conditional that ensures that `After` is the same as `Before` except for the deleted node. Let's break down this conditional: - The first guard asks if both `del.prev` and `del.next` are null. In this case, we are removing the only node in the list, so the resulting list will be empty. The `else` branch of this conditional contains its own conditional. @@ -205,7 +206,7 @@ when the function returns. We ensure that the int that is returned is the value case, `After` is now centered around `del.next`, and the left part of the list is the same as before. Since `del.next` was previously the head of the right side, the right side loses its head in - `After`. This is where we get `After == Dll{left: + `After`. This is where we get `After == DlList{left: Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. - The final `else` branch is the case where `del.next` is null, but @@ -213,7 +214,7 @@ Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. `del.prev`. This branch follows the same logic as the one before it, except now we are taking the head of the left side rather than the right side. Now the right side is unchanged, and the left side is just - the tail, as seen shown in `After == Dll{left: + the tail, as seen shown in `After == DlList{left: Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` ## Exercises @@ -225,6 +226,6 @@ that reverses a list. Try implementing a few of these functions and writing their specifications. _Exercise_: For extra practice, try coming up with one or two -variations on the Dll data structure itself (there are many!). +variations on the DlList data structure itself (there are many!). diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md index a0771a3d..1478de7b 100644 --- a/docs/getting-started/case-studies/verif-doubly-linked-lists.md +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -1,16 +1,14 @@ # Doubly-linked Lists, Verified -{{ todo("BCP: This chapter still needs some fixing up.") }} - Verifying the doubly-linked list operations requires a few extra annotations. The basic definitions are unchanged from the associated testing -chapter, except that we need some boilerplate for allocation and deallocation. +chapter, except that as usual we need some boilerplate for allocation and deallocation. -```c title="exercises/dll/allocation.verif.h" +```c title="exercises/dllist/allocation.verif.h" --8<-- -exercises/dll/allocation.verif.h +exercises/dllist/allocation.verif.h --8<-- ``` @@ -18,13 +16,11 @@ exercises/dll/allocation.verif.h ## Singleton -Now we can move on to an initialization function. Since an empty list -is represented as a null pointer, we will look at initializing a -singleton list (or in other words, a list with only one item). +The `singleton` function can be verified by CN with no additional annotations. -```c title="exercises/dll/singleton.verif.c" +```c title="exercises/dllist/singleton.verif.c" --8<-- -exercises/dll/singleton.verif.c +exercises/dllist/singleton.verif.c --8<-- ``` @@ -33,45 +29,30 @@ exercises/dll/singleton.verif.c ## Add The `add` and `remove` functions are where it gets a little tricker. -Let's start with `add`. Here is the unannotated version: +Let's start with `add`. Here is a version with just the pre- and +post-condition as in the testing version of this chapter: -```c title="exercises/dll/add_orig.broken.c" +```c title="exercises/dllist/add_orig.broken.c" --8<-- -exercises/dll/add_orig.broken.c +exercises/dllist/add.c --8<-- ``` _Exercise_: Before reading on, see if you can figure out what -specification is appropriate and what other are needed. - -{{ todo("BCP: I rather doubt they are going to be able to come up with this specification on their own! We need to set it up earlier with a simpler example (maybe in a whoile earlier section) showing how to use conditionals in specs. ") }} +annotations need to be added to the body of the function to make CN +accept it. -Now, here is the annotated version of the `add` operation: +Here is the fully annotated version: -```c title="exercises/dll/add.c" +```c title="solutions/dllist/add.c" --8<-- -exercises/dll/add.c +solutions/dllist/add.c --8<-- ``` -First, let's look at the pre- and post-conditions. The `requires` -clause is straightforward. We need to own the list centered around -the node that `n` points to. `Before` is a `Dll` -that is either empty, or it has a List to the left, -the current node that `n` points to, and a List to the right. -This corresponds to the state of the list when it is passed in. - -In the ensures clause, we again establish ownership of the list, but -this time it is centered around the added node. This means that -`After` is a `Dll` structure similar to `Before`, except that the node -`curr` is now the created node. The old `curr` is pushed into the left -part of the new list. The conditional operator in the `ensures` clause -is saying that if the list was empty coming in, it now is a singleton -list. Otherwise, the left left part of the list now has the data from -the old `curr` node, the new `curr` node is the added node, and the -right part of the list is the same as before. - -Now, let's look at the annotations in the function body. CN can +## Remove + +Let's look at the required annotations in the function body. CN can figure out the empty list case for itself, but it needs some help with the non-empty list case. The `split_case` on `is_null(n->prev)` tells CN to unpack the `Take_Left` predicate. Without this @@ -88,17 +69,17 @@ also want all of our functions to return a pointer to the list. Because of this, we define a `struct` that includes an `int` and a `node`. -```c title="exercises/dll/dllist_and_int.h" +```c title="exercises/dllist/dllist_and_int.h" --8<-- -exercises/dll/dllist_and_int.h +exercises/dllist/dllist_and_int.h --8<-- ``` Now we can look at the code for the `remove` operation. Here is the un-annotated version: -```c title="exercises/dll/remove_orig.broken.c" +```c title="exercises/dllist/remove_orig.broken.c" --8<-- -exercises/dll/remove_orig.broken.c +exercises/dllist/remove_orig.broken.c --8<-- ``` @@ -109,19 +90,19 @@ specification is appropriate and what annotations are needed. Now, here is the fully annotated version of the `remove` operation: -```c title="exercises/dll/remove.c" +```c title="exercises/dllist/remove.c" --8<-- -exercises/dll/remove.c +exercises/dllist/remove.c --8<-- ``` First, let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we assign the node of that list to the identifier `del` -to make our spec more readable. So `Before` refers to the `Dll` when the function is called, and `del` refers to the node that will be deleted. +to make our spec more readable. So `Before` refers to the `DlList` when the function is called, and `del` refers to the node that will be deleted. Then in the `ensures` clause, we must take ownership -of the `node_and_int` struct as well as the `Dll` that -the node is part of. Here, `After` refers to the `Dll` +of the `node_and_int` struct as well as the `DlList` that +the node is part of. Here, `After` refers to the `DlList` when the function returns. We ensure that the int that is returned is the value of the deleted node, as intended. Then we have a complicated nested ternary conditional that ensures that `After` is the same as `Before` except for the deleted node. Let's break down this conditional: - The first guard asks if both `del.prev` and `del.next` are null. In this case, we are removing the only node in the list, so the resulting list will be empty. The `else` branch of this conditional contains its own conditional. @@ -132,7 +113,7 @@ when the function returns. We ensure that the int that is returned is the value case, `After` is now centered around `del.next`, and the left part of the list is the same as before. Since `del.next` was previously the head of the right side, the right side loses its head in - `After`. This is where we get `After == Dll{left: + `After`. This is where we get `After == DlList{left: Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. - The final `else` branch is the case where `del.next` is null, but @@ -140,7 +121,7 @@ Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. `del.prev`. This branch follows the same logic as the one before it, except now we are taking the head of the left side rather than the right side. Now the right side is unchanged, and the left side is just - the tail, as seen shown in `After == Dll{left: + the tail, as seen shown in `After == DlList{left: Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` The annotations in the function body are similar to in the `add` @@ -159,6 +140,6 @@ that reverses a list. Try implementing a few of these functions and writing their specifications. _Exercise_: For extra practice, try coming up with one or two -variations on the Dll data structure itself (there are many!). +variations on the DlList data structure itself (there are many!). diff --git a/src/exercises/dll/add_orig.broken.c b/src/exercises/dll/add_orig.broken.c deleted file mode 100644 index d454709d..00000000 --- a/src/exercises/dll/add_orig.broken.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "./headers.verif.h" - -// Adds after the given node and returns a pointer to the new node -struct dllist *add(int element, struct dllist *n) -{ - struct dllist *new_dllist = malloc__dllist(); - new_dllist->data = element; - new_dllist->prev = 0; - new_dllist->next = 0; - - if (n == 0) //empty list case - { - new_dllist->prev = 0; - new_dllist->next = 0; - return new_dllist; - } else { - new_dllist->next = n->next; - new_dllist->prev = n; - - if (n->next != 0) { - n->next->prev = new_dllist; - } - - n->next = new_dllist; - return new_dllist; - } -} diff --git a/src/exercises/dll/getters.h b/src/exercises/dll/getters.h deleted file mode 100644 index 4f75bf23..00000000 --- a/src/exercises/dll/getters.h +++ /dev/null @@ -1,22 +0,0 @@ -/*@ -function (datatype List) Right_Sublist (datatype Dll L) { - match L { - Empty_Dll {} => { Nil{} } - Nonempty_Dll {left: _, curr: _, right: r} => { r } - } -} - -function (datatype List) Left_Sublist (datatype Dll L) { - match L { - Empty_Dll {} => { Nil {} } - Nonempty_Dll {left: l, curr: _, right: _} => { l } - } -} - -function (struct dllist) Node (datatype Dll L) { - match L { - Empty_Dll {} => { default } - Nonempty_Dll {left: _, curr: n, right: _} => { n } - } -} -@*/ diff --git a/src/exercises/dll/add.c b/src/exercises/dllist/add.c similarity index 82% rename from src/exercises/dll/add.c rename to src/exercises/dllist/add.c index d76122b9..5efcea8f 100644 --- a/src/exercises/dll/add.c +++ b/src/exercises/dllist/add.c @@ -2,14 +2,14 @@ // Adds after the given node and returns a pointer to the new node struct dllist *add(int element, struct dllist *n) -/*@ requires take Before = Dll_at(n); - ensures take After = Dll_at(return); +/*@ requires take Before = DlList_at(n); + ensures take After = DlList_at(return); is_null(n) ? - After == Nonempty_Dll { + After == Nonempty_DlList { left: Nil{}, curr: Node(After), right: Nil{}} - : After == Nonempty_Dll { + : After == Nonempty_DlList { left: Cons {Head: Node(Before).data, Tail: Left_Sublist(Before)}, curr: Node(After), @@ -27,12 +27,16 @@ struct dllist *add(int element, struct dllist *n) new_dllist->next = 0; return new_dllist; } else { +/* --BEGIN-- */ /*@ split_case(is_null(n->prev)); @*/ +/* --END-- */ new_dllist->next = n->next; new_dllist->prev = n; if (n->next != 0) { +/* --BEGIN-- */ /*@ split_case(is_null(n->next->next)); @*/ +/* --END-- */ n->next->prev = new_dllist; } diff --git a/src/exercises/dll/add.test.c b/src/exercises/dllist/add.test.c similarity index 85% rename from src/exercises/dll/add.test.c rename to src/exercises/dllist/add.test.c index 7fa8d997..d7b13439 100644 --- a/src/exercises/dll/add.test.c +++ b/src/exercises/dllist/add.test.c @@ -3,14 +3,14 @@ // Adds after the given node and returns a pointer to the new node struct dllist *add(int element, struct dllist *n) /* --BEGIN-- */ -/*@ requires take Before = Dll_at(n); - ensures take After = Dll_at(return); +/*@ requires take Before = DlList_at(n); + ensures take After = DlList_at(return); is_null(n) ? - After == Nonempty_Dll { + After == Nonempty_DlList { left: Nil{}, curr: Node(After), right: Nil{}} - : After == Nonempty_Dll { + : After == Nonempty_DlList { left: Cons {Head: Node(Before).data, Tail: Left_Sublist(Before)}, curr: Node(After), diff --git a/src/exercises/dll/allocation.test.h b/src/exercises/dllist/allocation.test.h similarity index 100% rename from src/exercises/dll/allocation.test.h rename to src/exercises/dllist/allocation.test.h diff --git a/src/exercises/dll/allocation.verif.h b/src/exercises/dllist/allocation.verif.h similarity index 100% rename from src/exercises/dll/allocation.verif.h rename to src/exercises/dllist/allocation.verif.h diff --git a/src/exercises/dll/c_types.h b/src/exercises/dllist/c_types.h similarity index 100% rename from src/exercises/dll/c_types.h rename to src/exercises/dllist/c_types.h diff --git a/src/exercises/dll/cn_types.h b/src/exercises/dllist/cn_types.h similarity index 51% rename from src/exercises/dll/cn_types.h rename to src/exercises/dllist/cn_types.h index 479d3626..49989653 100644 --- a/src/exercises/dll/cn_types.h +++ b/src/exercises/dllist/cn_types.h @@ -1,7 +1,7 @@ /*@ -datatype Dll { - Empty_Dll {}, - Nonempty_Dll {datatype List left, +datatype DlList { + Empty_DlList {}, + Nonempty_DlList {datatype List left, struct dllist curr, datatype List right} } diff --git a/src/exercises/dll/dllist_and_int.test.h b/src/exercises/dllist/dllist_and_int.test.h similarity index 100% rename from src/exercises/dll/dllist_and_int.test.h rename to src/exercises/dllist/dllist_and_int.test.h diff --git a/src/exercises/dll/dllist_and_int.verif.h b/src/exercises/dllist/dllist_and_int.verif.h similarity index 100% rename from src/exercises/dll/dllist_and_int.verif.h rename to src/exercises/dllist/dllist_and_int.verif.h diff --git a/src/exercises/dllist/getters.h b/src/exercises/dllist/getters.h new file mode 100644 index 00000000..06c00004 --- /dev/null +++ b/src/exercises/dllist/getters.h @@ -0,0 +1,22 @@ +/*@ +function (datatype List) Right_Sublist (datatype DlList L) { + match L { + Empty_DlList {} => { Nil{} } + Nonempty_DlList {left: _, curr: _, right: r} => { r } + } +} + +function (datatype List) Left_Sublist (datatype DlList L) { + match L { + Empty_DlList {} => { Nil {} } + Nonempty_DlList {left: l, curr: _, right: _} => { l } + } +} + +function (struct dllist) Node (datatype DlList L) { + match L { + Empty_DlList {} => { default } + Nonempty_DlList {left: _, curr: n, right: _} => { n } + } +} +@*/ diff --git a/src/exercises/dll/headers.test.h b/src/exercises/dllist/headers.test.h similarity index 100% rename from src/exercises/dll/headers.test.h rename to src/exercises/dllist/headers.test.h diff --git a/src/exercises/dll/headers.verif.h b/src/exercises/dllist/headers.verif.h similarity index 100% rename from src/exercises/dll/headers.verif.h rename to src/exercises/dllist/headers.verif.h diff --git a/src/exercises/dll/predicates.h b/src/exercises/dllist/predicates.h similarity index 88% rename from src/exercises/dll/predicates.h rename to src/exercises/dllist/predicates.h index 5b51db7f..e8aaaff2 100644 --- a/src/exercises/dll/predicates.h +++ b/src/exercises/dllist/predicates.h @@ -1,12 +1,12 @@ /*@ -predicate (datatype Dll) Dll_at (pointer p) { +predicate (datatype DlList) DlList_at (pointer p) { if (is_null(p)) { - return Empty_Dll{}; + return Empty_DlList{}; } else { take n = RW(p); take L = Take_Left(n.prev, p, n); take R = Take_Right(n.next, p, n); - return Nonempty_Dll{left: L, curr: n, right: R}; + return Nonempty_DlList{left: L, curr: n, right: R}; } } diff --git a/src/exercises/dll/remove.test.c b/src/exercises/dllist/remove.test.c similarity index 80% rename from src/exercises/dll/remove.test.c rename to src/exercises/dllist/remove.test.c index 0f0154ab..e45c551e 100644 --- a/src/exercises/dll/remove.test.c +++ b/src/exercises/dllist/remove.test.c @@ -6,18 +6,18 @@ struct dllist_and_int *remove_current(struct dllist *n) /* --BEGIN-- */ /*@ requires !is_null(n); - take Before = Dll_at(n); + take Before = DlList_at(n); let Del = Node(Before); ensures take Ret = RW(return); - take After = Dll_at(Ret.dllist); + take After = DlList_at(Ret.dllist); Ret.data == Del.data; (is_null(Del.prev) && is_null(Del.next)) - ? After == Empty_Dll{} + ? After == Empty_DlList{} : (!is_null(Del.next) ? - After == Nonempty_Dll {left: Left_Sublist(Before), + After == Nonempty_DlList {left: Left_Sublist(Before), curr: Node(After), right: Tl(Right_Sublist(Before))} - : After == Nonempty_Dll {left: Tl(Left_Sublist(Before)), + : After == Nonempty_DlList {left: Tl(Left_Sublist(Before)), curr: Node(After), right: Right_Sublist(Before)}); @*/ diff --git a/src/exercises/dll/remove.verify.c b/src/exercises/dllist/remove.verify.c similarity index 81% rename from src/exercises/dll/remove.verify.c rename to src/exercises/dllist/remove.verify.c index bf148ba2..4b11b3c8 100644 --- a/src/exercises/dll/remove.verify.c +++ b/src/exercises/dllist/remove.verify.c @@ -5,18 +5,18 @@ // to somewhere in the list, or a null pointer if the list is empty struct dllist_and_int *remove(struct dllist *n) /*@ requires !is_null(n); - take Before = Dll_at(n); + take Before = DlList_at(n); let Del = Node(Before); ensures take Ret = RW(return); - take After = Dll_at(Ret.dllist); + take After = DlList_at(Ret.dllist); Ret.data == Del.data; (is_null(Del.prev) && is_null(Del.next)) - ? After == Empty_Dll{} + ? After == Empty_DlList{} : (!is_null(Del.next) ? - After == Nonempty_Dll {left: Left_Sublist(Before), + After == Nonempty_DlList {left: Left_Sublist(Before), curr: Node(After), right: Tl(Right_Sublist(Before))} - : After == Nonempty_Dll {left: Tl(Left_Sublist(Before)), + : After == Nonempty_DlList {left: Tl(Left_Sublist(Before)), curr: Node(After), right: Right_Sublist(Before)}); @*/ diff --git a/src/exercises/dll/remove_orig.broken.c b/src/exercises/dllist/remove_orig.broken.c similarity index 100% rename from src/exercises/dll/remove_orig.broken.c rename to src/exercises/dllist/remove_orig.broken.c diff --git a/src/exercises/dll/singleton.test.c b/src/exercises/dllist/singleton.test.c similarity index 84% rename from src/exercises/dll/singleton.test.c rename to src/exercises/dllist/singleton.test.c index bc31fa53..dcfe1dbc 100644 --- a/src/exercises/dll/singleton.test.c +++ b/src/exercises/dllist/singleton.test.c @@ -1,8 +1,8 @@ #include "./headers.test.h" struct dllist *singleton(int element) -/*@ ensures take Ret = Dll_at(return); - Ret == Nonempty_Dll { +/*@ ensures take Ret = DlList_at(return); + Ret == Nonempty_DlList { left: Nil{}, curr: struct dllist {prev: NULL, data: element, diff --git a/src/exercises/dll/singleton.verif.c b/src/exercises/dllist/singleton.verif.c similarity index 84% rename from src/exercises/dll/singleton.verif.c rename to src/exercises/dllist/singleton.verif.c index 16ee28dc..0a241248 100644 --- a/src/exercises/dll/singleton.verif.c +++ b/src/exercises/dllist/singleton.verif.c @@ -1,8 +1,8 @@ #include "./headers.verif.h" struct dllist *singleton(int element) -/*@ ensures take Ret = Dll_at(return); - Ret == Nonempty_Dll { +/*@ ensures take Ret = DlList_at(return); + Ret == Nonempty_DlList { left: Nil{}, curr: struct dllist {prev: NULL, data: element, From a30940829df33e1ae7a42691e21b88004e866283 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 3 Apr 2025 15:40:38 -0400 Subject: [PATCH 100/158] Polishing runway case study --- Makefile | 6 +- .../case-studies/doubly-linked-lists.md | 2 +- .../case-studies/the-runway.md | 20 ++--- .../case-studies/verif-doubly-linked-lists.md | 82 +++++------------- .../case-studies/verif-the-runway.md | 4 +- .../tutorials/verif-numeric.md | 3 - mkdocs.yml | 85 ++++++++++--------- .../{remove.verify.c => remove.verif.c} | 4 + src/exercises/dllist/remove_orig.broken.c | 24 ------ src/exercises/runway/state.h | 16 ++-- 10 files changed, 91 insertions(+), 155 deletions(-) rename src/exercises/dllist/{remove.verify.c => remove.verif.c} (96%) delete mode 100644 src/exercises/dllist/remove_orig.broken.c diff --git a/Makefile b/Makefile index f0201d9c..c985a170 100644 --- a/Makefile +++ b/Makefile @@ -207,11 +207,13 @@ _temp/consistent/% : % ############################################################################## # Tutorial document +# BCP: Added the --quiet flag to suppress a bunch of INFO messages +# that the macros plugin was generating on every compile tutorial: rebuild - mkdocs build --strict + mkdocs build --strict --quiet serve: rebuild - mkdocs serve + mkdocs serve --quiet rebuild: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 7d2e1f7e..1ef2a767 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -189,7 +189,7 @@ solutions/dllist/remove.test.c --8<-- ``` -First, let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we +Let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we assign the node of that list to the identifier `del` to make our spec more readable. So `Before` refers to the `DlList` when the function is called, and `del` refers to the node that will be deleted. diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 92a606bb..882377fe 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -1,14 +1,8 @@ # Airport Simulation -{{ todo("BCP: I'm nervous about this case study -- it -is not nearly as well debugged as the others, and it seems potentially -quite confusing. I propose deleting it, but if others like it we can -try to whip it into better shape... (Later: It seems people do like -it, because it is more like SUT code than the other examples. So we -should make it better.) ") }} - -{{ todo("BCP: It also still needs some fixing up after the -testing/verification split.") }} +{{ later("BCP: This case study is not as well polished as the +others. It's useful because it's more like real-world C code than the +others, but we should make it better...") }} Suppose we have been tasked with writing a program that simulates a runway at an airport. This airport is very small, so it only has one @@ -79,8 +73,7 @@ following fields: or departed while planes are waiting for the other mode. This will help us keep track of the 3-plane limit as described in _(6)_. -{{ todo("BCP: Do we need these functions for the -testing version? Has function been explained earlier? ") }} +{{ todo("Has function been explained earlier? ") }} ```c title="exercises/runway/state.h" --8<-- @@ -119,7 +112,7 @@ Let's walk through the specifications in `valid_state`: Now that we have the tools to reason about the state of the runway formally, let's start writing some functions. -First, let's look at an initialization function and functions to update `Plane_Counter`. Step through these yourself and make sure you understand the reasoning behind each specification. +First, let's look at an initialization function and functions to update `Plane_Counter`. Read through these yourself and make sure you understand the reasoning behind each specification. ```c title="exercises/runway/funcs1.h" --8<-- @@ -129,8 +122,7 @@ exercises/runway/funcs1.h _Exercise_: Now try adding your own specifications to the following functions. Make sure that you specify a valid state as a pre- and -post-condition for every function. If you get stuck, the solution is -in the solutions folder. +post-condition for every function. ```c title="exercises/runway/funcs2.c" --8<-- diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md index 1478de7b..e59092b1 100644 --- a/docs/getting-started/case-studies/verif-doubly-linked-lists.md +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -32,7 +32,7 @@ The `add` and `remove` functions are where it gets a little tricker. Let's start with `add`. Here is a version with just the pre- and post-condition as in the testing version of this chapter: -```c title="exercises/dllist/add_orig.broken.c" +```c title="exercises/dllist/add.c" --8<-- exercises/dllist/add.c --8<-- @@ -50,80 +50,38 @@ solutions/dllist/add.c --8<-- ``` -## Remove +CN can figure out the empty list case for itself, but it needs some +help with the non-empty list case. The `split_case` on +`is_null(n->prev)` tells CN to unpack the `Take_Left` +predicate. Without this annotation, CN cannot reason that we didn't +lose the left half of the list before we return, and will claim we are +missing a resource for returning. The `split_case` on +`is_null(n->next->next)` is similar, but for unpacking the +`Take_Right` predicate. Note that we have to go one more node forward +to make sure that everything past `n->next` is still RW at the end of +the function. -Let's look at the required annotations in the function body. CN can -figure out the empty list case for itself, but it needs some help with -the non-empty list case. The `split_case` on `is_null(n->prev)` -tells CN to unpack the `Take_Left` predicate. Without this -annotation, CN cannot reason that we didn't lose the left half of the -list before we return, and will claim we are missing a resource for -returning. The `split_case` on `is_null(n->next->next)` is similar, -but for unpacking the `Take_Right` predicate. Note that we have to -go one more node forward to make sure that everything past `n->next` -is still RW at the end of the function. - -Now let's look at the `remove` operation. Traditionally, a `remove` -operation for a list returns the integer that was removed. However we -also want all of our functions to return a pointer to the -list. Because of this, we define a `struct` that includes an `int` -and a `node`. - -```c title="exercises/dllist/dllist_and_int.h" ---8<-- -exercises/dllist/dllist_and_int.h ---8<-- -``` +## Remove -Now we can look at the code for the `remove` operation. Here is the un-annotated version: +Here is the `remove` operation with just its specification: -```c title="exercises/dllist/remove_orig.broken.c" +```c title="exercises/dllist/remove.verif.c" --8<-- -exercises/dllist/remove_orig.broken.c +exercises/dllist/remove.verif.c --8<-- ``` _Exercise_: Before reading on, see if you can figure out what -specification is appropriate and what annotations are needed. - -{{ todo("BCP: Again, unlikely the reader is going to be able to figure this out without help. We need some hints. ") }} +annotations are needed to make CN happy. -Now, here is the fully annotated version of the `remove` operation: +Here is the fully annotated version of `remove`: -```c title="exercises/dllist/remove.c" +```c title="solutions/dllist/remove.verif.c" --8<-- -exercises/dllist/remove.c +solutions/dllist/remove.verif.c --8<-- ``` -First, let's look at the pre- and post-conditions. The `requires` clause says that we cannot remove a node from an empty list, so the pointer passed in must not be null. Then we take ownership of the list, and we -assign the node of that list to the identifier `del` -to make our spec more readable. So `Before` refers to the `DlList` when the function is called, and `del` refers to the node that will be deleted. - -Then in the `ensures` clause, we must take ownership -of the `node_and_int` struct as well as the `DlList` that -the node is part of. Here, `After` refers to the `DlList` -when the function returns. We ensure that the int that is returned is the value of the deleted node, as intended. Then we have a complicated nested ternary conditional that ensures that `After` is the same as `Before` except for the deleted node. Let's break down this conditional: - -- The first guard asks if both `del.prev` and `del.next` are null. In this case, we are removing the only node in the list, so the resulting list will be empty. The `else` branch of this conditional contains its own conditional. - -- For the following conditional, the guard checks if 'del.prev' is - _not_ null. This means that the returned node is `del.next`, - regardless of whether or not `del.prev` is null. If this is the - case, `After` is now centered around `del.next`, and the left part - of the list is the same as before. Since `del.next` was previously - the head of the right side, the right side loses its head in - `After`. This is where we get `After == DlList{left: -Left_Sublist(Before), curr: Node(After), right: Tl(Right(Before))}`. - -- The final `else` branch is the case where `del.next` is null, but - `del.prev` is not null. In this case, the returned node is - `del.prev`. This branch follows the same logic as the one before it, - except now we are taking the head of the left side rather than the - right side. Now the right side is unchanged, and the left side is just - the tail, as seen shown in `After == DlList{left: -Tl(Left_Sublist(Before)), curr: Node(After), right: Right(Before)};` - The annotations in the function body are similar to in the `add` function. Both of these `split_case` annotations are needed to unpack the `Take_Right` and `Take_Left` predicates. Without them, CN @@ -137,7 +95,7 @@ _Exercise_: There are many other functions that one might want to implement for a doubly linked list. For example, one might want to implement a function that appends one list to another, or a function that reverses a list. Try implementing a few of these functions and -writing their specifications. +writing _and verifying_ their specifications. _Exercise_: For extra practice, try coming up with one or two variations on the DlList data structure itself (there are many!). diff --git a/docs/getting-started/case-studies/verif-the-runway.md b/docs/getting-started/case-studies/verif-the-runway.md index 43585f7c..ece995d2 100644 --- a/docs/getting-started/case-studies/verif-the-runway.md +++ b/docs/getting-started/case-studies/verif-the-runway.md @@ -2,7 +2,7 @@ _Exercise_: See if CN can verify the functions you wrote for the exercise in the testing version of this chapter. Fix them if not. -Our solution requires no annotations besides the pre- and -poset-conditions. +(Our solution requires no annotations besides the pre- and +post-conditions.) diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 49184e7e..09f1ca71 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -234,9 +234,6 @@ solutions/slf1_basic_example_let.signed.c --8<-- ``` -{{ todo("BCP: WHy n*+n\\_ in some places and n\*2i32 in others? ") }} -{{ todo("Dhruv: Unlikely to be meaningful, either is fine. ") }} - We encode these expectations using a similar style of precondition as in the first example. We first define `N` as `n` cast to type `i64` — i.e. a type large enough to hold `n+1`, `n-1`, and `a+b` for any possible `i32` value for `n`. Then we specify that decrementing `N` does not go below the minimal `int` value, that incrementing `N` does not go above the maximal value, and that `n` doubled is also in range. These preconditions together guarantee safe execution. {{ todo("BCP: How about renaming N to n64? ") }} diff --git a/mkdocs.yml b/mkdocs.yml index 7225d6f5..01814fe4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -96,46 +96,47 @@ markdown_extensions: custom_checkbox: true - pymdownx.tilde -# Page tree -nav: - - Getting started: - - README.md - - Installation: getting-started/installation.md - - Tutorial: getting-started/tutorials/README.md -# - Testing: -# - "A first taste of CN": getting-started/tutorials/first-taste.md -# - "CN basics": getting-started/tutorials/cn-basics.md -# - Verification: -# - "Basic usage": getting-started/tutorials/verification/basic-usage.md -# - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md -# - "Ownership of compound objects": getting-started/tutorials/verification/ownership-of-compound-objects.md -# - "Arrays and loops": getting-started/tutorials/verification/arrays-and-loops.md -# - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md -# - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md -# - "Lists": getting-started/tutorials/verification/lists.md -# - "Working with external lemmas": getting-started/tutorials/verification/external-lemmas.md - - "Case studies": - - "Imperative queues": getting-started/case-studies/imperative-queues.md - - "Doubly-linked lists": getting-started/case-studies/doubly-linked-lists.md - - "Airport Simulation": getting-started/case-studies/the-runway.md - - "Style guide": - - getting-started/style-guide/README.md - - Specifications: - - specifications/README.md - - Function specifications: specifications/function-specifications.md - - Loop invariants: specifications/loop-invariants.md - - Conditions: specifications/conditions.md - - Expressions: specifications/expressions.md - - Resource predicates: specifications/resource-predicates.md - - Auxiliary definitions: - - specifications/auxiliary-definitions/README.md - - Data structures: specifications/auxiliary-definitions/data-structures.md - - Logical functions: specifications/auxiliary-definitions/logical-functions.md - - Custom resource predicates: specifications/auxiliary-definitions/custom-resource-predicates.md - - Types: specifications/types.md - - Scoping: specifications/scoping.md - - "Tactics (proof hints)": specifications/tactics.md - - Interactive theorem proving: specifications/interactive-theorem-proving.md - - Reference: - - reference/README.md +# # Page tree +# nav: +# - Getting started: +# - README.md +# - Installation: getting-started/installation.md +# - Tutorial: getting-started/tutorials/README.md +# # - Testing: +# # - "A first taste of CN": getting-started/tutorials/first-taste.md +# # - "CN basics": getting-started/tutorials/cn-basics.md +# # - Verification: +# # - "Basic usage": getting-started/tutorials/verification/basic-usage.md +# # - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md +# # - "Ownership of compound objects": getting-started/tutorials/verification/ownership-of-compound-objects.md +# # - "Arrays and loops": getting-started/tutorials/verification/arrays-and-loops.md +# # - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md +# # - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md +# # - "Lists": getting-started/tutorials/verification/lists.md +# # - "Working with external lemmas": getting-started/tutorials/verification/external-lemmas.md +# - "Case studies": +# - "Imperative queues": getting-started/case-studies/imperative-queues.md +# - "Doubly-linked lists": getting-started/case-studies/doubly-linked-lists.md +# - "Airport Simulation": getting-started/case-studies/the-runway.md +# - "Style guide": +# - getting-started/style-guide/README.md +# - Specifications: +# - specifications/README.md +# - Function specifications: specifications/function-specifications.md +# - Loop invariants: specifications/loop-invariants.md +# - Conditions: specifications/conditions.md +# - Expressions: specifications/expressions.md +# - Resource predicates: specifications/resource-predicates.md +# - Auxiliary definitions: +# - specifications/auxiliary-definitions/README.md +# - Data structures: specifications/auxiliary-definitions/data-structures.md +# - Logical functions: specifications/auxiliary-definitions/logical-functions.md +# - Custom resource predicates: specifications/auxiliary-definitions/custom-resource-predicates.md +# - Types: specifications/types.md +# - Scoping: specifications/scoping.md +# - "Tactics (proof hints)": specifications/tactics.md +# - Interactive theorem proving: specifications/interactive-theorem-proving.md +# - Reference: +# - reference/README.md + diff --git a/src/exercises/dllist/remove.verify.c b/src/exercises/dllist/remove.verif.c similarity index 96% rename from src/exercises/dllist/remove.verify.c rename to src/exercises/dllist/remove.verif.c index 4b11b3c8..a7286ac5 100644 --- a/src/exercises/dllist/remove.verify.c +++ b/src/exercises/dllist/remove.verif.c @@ -23,12 +23,16 @@ struct dllist_and_int *remove(struct dllist *n) { struct dllist *temp = 0; if (n->prev != 0) { +/* --BEGIN-- */ /*@ split_case(is_null(n->prev->prev)); @*/ +/* --END-- */ n->prev->next = n->next; temp = n->prev; } if (n->next != 0) { +/* --BEGIN-- */ /*@ split_case(is_null(n->next->next)); @*/ +/* --END-- */ n->next->prev = n->prev; temp = n->next; } diff --git a/src/exercises/dllist/remove_orig.broken.c b/src/exercises/dllist/remove_orig.broken.c deleted file mode 100644 index 0879a7fe..00000000 --- a/src/exercises/dllist/remove_orig.broken.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "./headers.verif.h" -#include "./dllist_and_int.h" - -// removes the given node from the list and returns another pointer -// to somewhere in the list, or a null pointer if the list is empty. -struct dllist_and_int *remove(struct dllist *n) -{ - struct dllist *temp = 0; - if (n->prev != 0) { - n->prev->next = n->next; - temp = n->prev; - } - if (n->next != 0) { - n->next->prev = n->prev; - temp = n->next; - } - - struct dllist_and_int *pair = malloc__dllist_and_int(); - pair->dllist = temp; - pair->data = n->data; - - free__dllist(n); - return pair; -} \ No newline at end of file diff --git a/src/exercises/runway/state.h b/src/exercises/runway/state.h index ecfe5b18..4ec54041 100644 --- a/src/exercises/runway/state.h +++ b/src/exercises/runway/state.h @@ -1,10 +1,16 @@ #define INACTIVE 0 - /*@ function (i32) INACTIVE () @*/ - static int c_INACTIVE() /*@ cn_function INACTIVE; @*/ { return INACTIVE; } +/*@ function (i32) INACTIVE() { 0i32 } @*/ +static int c_INACTIVE() +/*@ requires true; + ensures return == INACTIVE(); @*/ +{ return INACTIVE; } #define ACTIVE 1 - /*@ function (i32) ACTIVE () @*/ - static int c_ACTIVE() /*@ cn_function ACTIVE; @*/ { return ACTIVE; } +/*@ function (i32) ACTIVE() { 1i32 } @*/ +static int c_ACTIVE() +/*@ requires true; + ensures return == ACTIVE(); @*/ +{ return ACTIVE; } struct State { int ModeA; @@ -15,4 +21,4 @@ struct State { int Runway_Time; int Plane_Counter; -}; \ No newline at end of file +}; From 49dd57581ece5d7b3847fe4714cb16d36275b090 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 3 Apr 2025 15:46:33 -0400 Subject: [PATCH 101/158] Last fixes to get everything compiling --- Makefile | 3 +-- src/exercises/slf17_get_and_free.test.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index c985a170..46424350 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,6 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/min3/min3.fixed.c \ _temp/tested/min3/min3.partial.c \ _temp/tested/min3/min3.partial1.c \ - _temp/tested/slf_incr2.c \ _temp/tested/id_by_div/id_by_div.fixed.c \ _temp/tested/slf2_basic_quadruple.c \ _temp/tested/swap.c \ @@ -112,7 +111,7 @@ _temp/tested/% : src/exercises/% $(V)$(CNTEST) _temp/$<.combined.c 2>&1 | tee $@.test.out $(V)-grep "PASSED\\|FAILED" $@.test.out || true @# Next line should not be needed! - $(V)if grep -q "fatal error\\|Failed to compile\\|Failed to link\\|: error:" $@.test.out; then \ + $(V)if grep -q "FAILED\\|fatal error\\|Failed to compile\\|Failed to link\\|: error:" $@.test.out; then \ exit 1; \ fi $(V)touch $@ diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c index 6e7ee59a..1c287e4e 100644 --- a/src/exercises/slf17_get_and_free.test.c +++ b/src/exercises/slf17_get_and_free.test.c @@ -22,7 +22,7 @@ unsigned int get_and_free (unsigned int *p) unsigned int tester() /*@ requires true; - ensures return == 41u32; + ensures return == 42u32; @*/ { unsigned int *p = malloc_and_set (42); From c49b78a66cf9d58b8d0788249506857909252332 Mon Sep 17 00:00:00 2001 From: Dimitrios Economou Date: Fri, 4 Apr 2025 16:58:15 +0100 Subject: [PATCH 102/158] Fix minor typos and other minor fixes and edits --- .../case-studies/doubly-linked-lists.md | 8 ++++---- .../case-studies/imperative-queues.md | 8 ++++---- docs/getting-started/case-studies/the-runway.md | 2 +- .../case-studies/verif-imperative-queues.md | 16 ++++++++-------- docs/getting-started/tutorials/arrays.md | 2 +- docs/getting-started/tutorials/lists.md | 2 +- docs/getting-started/tutorials/pointers.md | 2 +- docs/getting-started/tutorials/predicates.md | 2 +- docs/getting-started/tutorials/verif-arrays.md | 2 +- src/exercises/slf_ref_greater.c | 2 +- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 1ef2a767..2f35691a 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -26,7 +26,7 @@ track of the front or back, but rather we take any node in the list and have a sequence to the left and to the right of that node. The `left` and `right` are from the point of view of the node itself, so `left` is kept in reverse order. Additionally, similarly to in the -`Imperative Queues` example, we can reuse the `List` type. +Imperative Queues example, we can reuse the `List` type. ```c title="exercises/dllist/cn_types.h" --8<-- @@ -147,7 +147,7 @@ this time it is centered around the added node. This means that `curr` is now the created node. The old `curr` is pushed into the left part of the new list. The conditional operator in the `ensures` clause is saying that if the list was empty coming in, it now is a singleton -list. Otherwise, the left left part of the list now has the data from +list. Otherwise, the left part of the list now has the data from the old `curr` node, the new `curr` node is the added node, and the right part of the list is the same as before. @@ -200,7 +200,7 @@ when the function returns. We ensure that the int that is returned is the value - The first guard asks if both `del.prev` and `del.next` are null. In this case, we are removing the only node in the list, so the resulting list will be empty. The `else` branch of this conditional contains its own conditional. -- For the following conditional, the guard checks if 'del.prev' is +- For the following conditional, the guard checks if `del.prev` is _not_ null. This means that the returned node is `del.next`, regardless of whether or not `del.prev` is null. If this is the case, `After` is now centered around `del.next`, and the left part @@ -226,6 +226,6 @@ that reverses a list. Try implementing a few of these functions and writing their specifications. _Exercise_: For extra practice, try coming up with one or two -variations on the DlList data structure itself (there are many!). +variations on the `DlList` data structure itself (there are many!). diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index b2813efb..5b61c6dd 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -37,7 +37,7 @@ concrete representation. we remove them.)") }} `QueueFB` is where the interesting part starts. Conceptually, -it is part of `QueuePTR`, but CN currently allows +it is part of `QueuePtr_At`, but CN currently allows conditional expressions only at the beginning of predicate definitions, not after a `take`, so we need to make a separate auxiliary predicate. @@ -68,7 +68,7 @@ Accordingly, we begin by `take`-ing the tail cell and passing it separately to the `QueueAux` predicate, which has the job of walking down the cells from the front and gathering all the rest of them into a sequence. We take the result from `QueueAux` and -`snoc` on the very last element. +`Snoc` on the very last element. {{ todo("BCP: The asserts here are not needed, but the ones above and below are. Do we keep them and explain them? What is the @@ -91,11 +91,11 @@ When `f` and `b` are equal, we have reached the last cell and there is nothing to do. We don't even have to build a singleton list: that's going to happen one level up, in `QueueFB`. -Otherwise, we `take` the fields of the `f`, make a recurive +Otherwise, we `take` the fields of the `f`, make a recursive call to `QueueAux` to process the rest of the cells, and cons the `first` field of this cell onto the resulting sequence before returning it. Again, we need to help the CN verifier by explicitly -informing it of the invariant that we know, that `C.next` cannot be +informing it of the invariant that we know, that `F.next` cannot be null if `f` and `b` are different. {{ todo("BCP: The asserts here seem to be sort-of-needed: removing diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index 882377fe..eb2b6b0c 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -61,7 +61,7 @@ following fields: - `ModeA` and `ModeD` to represent the arrival and departure modes, respectively. We can define constants for `ACTIVE` and `INACTIVE`, - as described in the `Constants` section above. + as described in the Constants section above. - `W_A` and `W_D` to represent the number of planes waiting to arrive and depart, respectively. diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md index 8eab13c5..8d231c5d 100644 --- a/docs/getting-started/case-studies/verif-imperative-queues.md +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -96,7 +96,7 @@ values in some chain of queue cells of length at least 2, starting with the cell `front` and terminating when we get to the next cell _following_ some given cell `p` -- call it `c`. We can either gather up all the cells from `front` to `c`, or we can gather up -just the cells from `front` to `p` and then `snoc` on the single +just the cells from `front` to `p` and then `Snoc` on the single value from `c`. When we apply this lemma, `p` will be the old `back` cell and @@ -161,14 +161,14 @@ checking proceeds. When `h == q->back`, we are in the case where the queue contains just a single element, so we just need to NULL out its `front` and `back` fields and deallocate the dead cell. The `unfold` -annotation is needed because the `snoc` function is recursive, so CN +annotation is needed because the `Snoc` function is recursive, so CN doesn't do the unfolding automatically. Finally, when the queue contains two or more elements, we need to deallocate the front cell, return its `first` field, and redirect the `front` field of the queue structure to point to the next cell. To push the verification through, we need a simple lemma about the -`snoc` function: +`Snoc` function: ```c title="exercises/queue/pop_lemma.h" --8<-- @@ -177,10 +177,10 @@ exercises/queue/pop_lemma.h ``` The crucial part of this lemma is the last three lines, which express -a simple, general fact about `snoc`: -if we form a sequence by calling `snoc` to add a final element +a simple, general fact about `Snoc`: +if we form a sequence by calling `Snoc` to add a final element `B.first` to a sequence with head element `x` and tail `Q`, then the -head of the resulting sequence is still `x`, and its tail is `snoc +head of the resulting sequence is still `x`, and its tail is `Snoc (Q, B.first)`. The `requires` clause and the first three lines of the `ensures` @@ -206,8 +206,8 @@ Investigate what happens when you make each of the following changes to the queue definitions. What error does CN report? Where are the telltale clues in the error report that suggest what the problem was? -- Remove `assert (is_null(B.next));` from `InqQueueFB`. -- Remove `assert (is_null(B.next));` from `InqQueueAux`. +- Remove `assert (is_null(B.next));` from `QueueFB`. +- Remove `assert (is_null(B.next));` from `QueueAux`. - Remove one or both of occurrences of `free_queue_cell(f)` in `pop_queue`. - Remove, in turn, each of the CN annotations in the bodies of diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index a0f6c51c..e7f33ea7 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -46,7 +46,7 @@ exercises/array_load.test.c The CN precondition requires -- ownership of the array on entry — one `RW` resource for each array index between `0` and `n` — and +- ownership of the array on entry — one `RW` resource for each array index between `0` and `n - 1` — and - that `i` lies within the range of RW indices. On exit the array ownership is returned again. The postcondition also asserts that the return value of the function is indeed equal to the value of the array at index `i`. diff --git a/docs/getting-started/tutorials/lists.md b/docs/getting-started/tutorials/lists.md index 5eea78bb..88f4e79d 100644 --- a/docs/getting-started/tutorials/lists.md +++ b/docs/getting-started/tutorials/lists.md @@ -75,7 +75,7 @@ With this basic infrastructure in place, we can start specifying and verifying list-manipulating functions. First, `append`. Here is its specification (in a separate file, because we'll want to -use it multiple times below.) +use it multiple times below). ```c title="exercises/list/append.h" --8<-- diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 73ad8484..d0f5b1a5 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -123,7 +123,7 @@ exercises/read2.c ``` ∀p. - ∀v1. + ∀P. { p ↦ P } read(p) { \return. ∃P_post. (p ↦ P_post) and return = P and P = P_post } diff --git a/docs/getting-started/tutorials/predicates.md b/docs/getting-started/tutorials/predicates.md index 4191db6d..76ad9ed6 100644 --- a/docs/getting-started/tutorials/predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -24,7 +24,7 @@ exercises/slf_incr2_alias.c --8<-- ``` -This version does correctly state that the final values of `p` and `q` are,m respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. +This version does correctly state that the final values of `p` and `q` are, respectively, `3` and `1` more than their original values. But the way we got there -- by duplicating the whole function `incr2`, is horrible. A better way is to define a _predicate_ that captures both the aliased and the non-aliased cases together and use it in the pre- and diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 56ec4341..21992320 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -88,7 +88,7 @@ the same — and that the value returned is `A[i]`. ### Exercises -_Exercise:_ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. Assuming `i` and `j` are different, it returns the sum of the values at these two indices. +_Exercise:_ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. *Assuming `i` and `j` are different*, it returns the sum of the values at these two indices. ```c title="exercises/array_read_two.c" --8<-- diff --git a/src/exercises/slf_ref_greater.c b/src/exercises/slf_ref_greater.c index 87fd53c6..34222015 100644 --- a/src/exercises/slf_ref_greater.c +++ b/src/exercises/slf_ref_greater.c @@ -7,7 +7,7 @@ unsigned int *ref_greater_abstract (unsigned int *p) ensures take P_post = RW(p); take R = RW(return); P == P_post; - P <= R; + P < R; @*/ /* --END-- */ { From 0ea583d0e26db7ca84c5ab71ec67e02a5357b56b Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 4 Apr 2025 14:24:34 -0400 Subject: [PATCH 103/158] fix nav bar --- __pycache__/main.cpython-313.pyc | Bin 0 -> 1268 bytes docs/getting-started/tutorials/README.md | 36 +++++++++++------------ mkdocs.yml | 29 +++++++++--------- 3 files changed, 33 insertions(+), 32 deletions(-) create mode 100644 __pycache__/main.cpython-313.pyc diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d02a204dcae0904019327c21ac6bf51c3e811cb GIT binary patch literal 1268 zcmbVLO=}ZD7@pa$rh#-Ng{ovm~w9cLErt3unezEHim(qQ*OPP2%Fqvn*@tx=v2~3O8h?t>G zc0E6KSX9bd(gnrbpM_^|0}M~Bj#t2|N!-?v@MUfnk)d?v9#IyUF)_*J#)A#AY|$W~ zq0yPGL`^d!QQY>Odqs=-l-=zp#p?EUXL@I+Qs!v&7#UKc1WwdQR6&V&a6*!$ay(;O5BPmar>D6D6iLO|DIn%aI)C=fV8yqB9L$nfqXWe0ZuC zPclWu$MHWTULBJt2EsR?>&dk5HQczt%(jrsL~K$1p;k5JU7sXYKwRi$wU1Br<&(_v z-)i~g5e4P-IT9DDvo@|Rc43Ypm$rPHgcL@~id&}dw~5(oIwm8G3kKvcK|->DMU^9d zG)e2Lxt?u1;pBlxu>x1ko6$vmC~;m$eQMxD6*t3B6B)*c%>aY(3>lw*w3EE21lIjD zSoTk47(bQkh@OLi?)}J0>J!|bLE7~Dt+!i0B}u(GkddbMx!2EJ*f-AijdT7Pu<~MG kcq5G>Oxi9!4ylYxC7^c8cdBfDB!Yu|8Dl(<7I2#3Z$>>8dH?_b literal 0 HcmV?d00001 diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index da0f64ed..e0489842 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -3,40 +3,40 @@ - [Welcome](welcome.md) ## A Tour of CN -- [A first taste of CN: Specification and testing](first-taste.md) +- [A First Taste of CN: Specification and Testing](first-taste.md) - [(V) - A first taste of verification](verif-basics.md) -- [Working with pointers](pointers.md) + A First Taste of Verification](verif-basics.md) +- [Working with Pointers](pointers.md) - [(V) - Pointers to structured objects, verified](verif-pointers.md) -- [Arrays and loops](arrays.md) + Pointers to Structured Objects, Verified](verif-pointers.md) +- [Arrays and Loops](arrays.md) - [(V) - Arrays and loops, verified](verif-arrays.md) -- [Allocating and deallocating memory](alloc.md) + Arrays and Loops, Verified](verif-arrays.md) +- [Allocating and Deallocating Memory](alloc.md) - (V) - [Allocating and deallocating memory, verified](verif-alloc.md) -- [Defining predicates](predicates.md) + [Allocating and Deallocating Memory, Verified](verif-alloc.md) +- [Defining Predicates](predicates.md) - [Lists](lists.md) - [(V) - Lists, verified](verif-lists.md) + Lists, Verified](verif-lists.md) - [(V) - Case analysis](verif-splitcase.md) + Case Analysis](verif-splitcase.md) - (V) - [More on numeric types](verif-numeric.md) + [More on Numeric Types](verif-numeric.md) - [(V) - Working with external lemmas](verif-external.md) + Working with External Lemmas](verif-external.md) ## Case studies -- [Imperative queues](../case-studies/imperative-queues.md) +- [Imperative Queues](../case-studies/imperative-queues.md) - [(V) - Imperative queues, verified](../case-studies/verif-imperative-queues.md) -- [Doubly-linked lists](../case-studies/doubly-linked-lists.md) + Imperative Queues, Verified](../case-studies/verif-imperative-queues.md) +- [Doubly-Linked Lists](../case-studies/doubly-linked-lists.md) - [(V) - Doubly-linked lists, verified](../case-studies/verif-doubly-linked-lists.md) + Doubly-Linked Lists, Verified](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) - [(V) - Airport simulation, verified](../case-studies/verif-the-runway.md) + Airport Simulation, Verified](../case-studies/verif-the-runway.md) ## TODOs diff --git a/mkdocs.yml b/mkdocs.yml index 01814fe4..a6eb65fb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,7 +51,7 @@ theme: plugins: - search - macros - + # Extensions markdown_extensions: - abbr @@ -97,19 +97,20 @@ markdown_extensions: - pymdownx.tilde # # Page tree -# nav: -# - Getting started: -# - README.md -# - Installation: getting-started/installation.md -# - Tutorial: getting-started/tutorials/README.md -# # - Testing: -# # - "A first taste of CN": getting-started/tutorials/first-taste.md -# # - "CN basics": getting-started/tutorials/cn-basics.md -# # - Verification: -# # - "Basic usage": getting-started/tutorials/verification/basic-usage.md -# # - "Pointers and simple ownership": getting-started/tutorials/verification/pointers-and-simple-ownership.md -# # - "Ownership of compound objects": getting-started/tutorials/verification/ownership-of-compound-objects.md -# # - "Arrays and loops": getting-started/tutorials/verification/arrays-and-loops.md +nav: + - Getting Started: + - README.md + - Installation: getting-started/installation.md + - Tutorial: + - getting-started/tutorials/README.md + - "Welcome": getting-started/tutorials/welcome.md + - "A First Taste of CN: Specification and Testing": getting-started/tutorials/first-taste.md + - "(V) A First Taste of Verification": getting-started/tutorials/verif-basics.md + - "Working with Pointers": getting-started/tutorials/pointers.md + - "(V) Pointers to Structured Objects, Verified": getting-started/tutorials/verif-pointers.md + - "Arrays and Loops": getting-started/tutorials/arrays.md + - "(V) Arrays and Loops, Verified": getting-started/tutorials/verif-arrays.md + # # - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md # # - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md # # - "Lists": getting-started/tutorials/verification/lists.md From 4d76d10041cd775336e7b64c101f7ddf1d7cd3d9 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 4 Apr 2025 14:25:14 -0400 Subject: [PATCH 104/158] remove extraneous file --- __pycache__/main.cpython-313.pyc | Bin 1268 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/main.cpython-313.pyc diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc deleted file mode 100644 index 7d02a204dcae0904019327c21ac6bf51c3e811cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1268 zcmbVLO=}ZD7@pa$rh#-Ng{ovm~w9cLErt3unezEHim(qQ*OPP2%Fqvn*@tx=v2~3O8h?t>G zc0E6KSX9bd(gnrbpM_^|0}M~Bj#t2|N!-?v@MUfnk)d?v9#IyUF)_*J#)A#AY|$W~ zq0yPGL`^d!QQY>Odqs=-l-=zp#p?EUXL@I+Qs!v&7#UKc1WwdQR6&V&a6*!$ay(;O5BPmar>D6D6iLO|DIn%aI)C=fV8yqB9L$nfqXWe0ZuC zPclWu$MHWTULBJt2EsR?>&dk5HQczt%(jrsL~K$1p;k5JU7sXYKwRi$wU1Br<&(_v z-)i~g5e4P-IT9DDvo@|Rc43Ypm$rPHgcL@~id&}dw~5(oIwm8G3kKvcK|->DMU^9d zG)e2Lxt?u1;pBlxu>x1ko6$vmC~;m$eQMxD6*t3B6B)*c%>aY(3>lw*w3EE21lIjD zSoTk47(bQkh@OLi?)}J0>J!|bLE7~Dt+!i0B}u(GkddbMx!2EJ*f-AijdT7Pu<~MG kcq5G>Oxi9!4ylYxC7^c8cdBfDB!Yu|8Dl(<7I2#3Z$>>8dH?_b From 11f74ce62893d85f834af6b474a4bad925723029 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 4 Apr 2025 14:28:32 -0400 Subject: [PATCH 105/158] restore other tabs --- mkdocs.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index a6eb65fb..a2732383 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -121,23 +121,23 @@ nav: # - "Airport Simulation": getting-started/case-studies/the-runway.md # - "Style guide": # - getting-started/style-guide/README.md -# - Specifications: -# - specifications/README.md -# - Function specifications: specifications/function-specifications.md -# - Loop invariants: specifications/loop-invariants.md -# - Conditions: specifications/conditions.md -# - Expressions: specifications/expressions.md -# - Resource predicates: specifications/resource-predicates.md -# - Auxiliary definitions: -# - specifications/auxiliary-definitions/README.md -# - Data structures: specifications/auxiliary-definitions/data-structures.md -# - Logical functions: specifications/auxiliary-definitions/logical-functions.md -# - Custom resource predicates: specifications/auxiliary-definitions/custom-resource-predicates.md -# - Types: specifications/types.md -# - Scoping: specifications/scoping.md -# - "Tactics (proof hints)": specifications/tactics.md -# - Interactive theorem proving: specifications/interactive-theorem-proving.md -# - Reference: -# - reference/README.md + - Specifications: + - specifications/README.md + - Function specifications: specifications/function-specifications.md + - Loop invariants: specifications/loop-invariants.md + - Conditions: specifications/conditions.md + - Expressions: specifications/expressions.md + - Resource predicates: specifications/resource-predicates.md + - Auxiliary definitions: + - specifications/auxiliary-definitions/README.md + - Data structures: specifications/auxiliary-definitions/data-structures.md + - Logical functions: specifications/auxiliary-definitions/logical-functions.md + - Custom resource predicates: specifications/auxiliary-definitions/custom-resource-predicates.md + - Types: specifications/types.md + - Scoping: specifications/scoping.md + - "Tactics (proof hints)": specifications/tactics.md + - Interactive theorem proving: specifications/interactive-theorem-proving.md + - Reference: + - reference/README.md From 129dba16678ffeb80e2764ca79a34d494fbba192 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 4 Apr 2025 14:51:12 -0400 Subject: [PATCH 106/158] tweaks to first two chapters --- docs/getting-started/tutorials/first-taste.md | 29 ++++++++++--------- docs/getting-started/tutorials/welcome.md | 14 ++++----- src/exercises/id_by_div/id_by_div.broken.c | 2 +- src/exercises/min3/min3.partial1.c | 2 +- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index d3d8e6fd..5a4bf67a 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -105,14 +105,14 @@ inputs, and checks that the output satisfies the postcondition. It repeats this process until either some number (by default, 100) of tests succeed or else a failing test, called a _counterexample_, is encountered. In this case, the counterexample is printed out in -the form of a snipped of C code that will recreate the failing -situation. +the form of a snippet of C code that will recreate the failure. (The counterexample you will see if you run the tests yourself will most likely be different, due to randomness, but the debugging logic will be the same.) -Given these three inputs, we expect the function to enter this branch: +Given these inputs `x = 10`, `y = 2`, and `z = 14`, we expect the function to +enter this branch: ```c else if (y <= x && y <= z) { @@ -144,7 +144,9 @@ _Exercise:_ The specification we wrote is a bit loose: It says the result value should be smaller than `x`, `y`, and `z`, but it does not say that it must be equal to one of these. For example, a function that always returns `0` would satisfy this -spec specification. Improve it. +specification. Improve it. + +{{ later("JWS: Should explain at some point how to write multiple ensures clauses without ANDing everything etc.") }} _Exercise:_ Practice the workflow of specifying and testing the function `add`. @@ -153,10 +155,9 @@ _Exercise:_ Practice the workflow of specifying and testing the function `add`. arithmetic and boolean operators such as `+` and `==`. - Write a _correct_ implementation and check that `cn test` succeeds. - Write an _incorrect_ implementation of `add` and check that `cn test` fails. -- Extra credit: Can you find a way to write an incorrect - implementation of `add` for which testing will (incorrectly) succeed - -- i.e., such that `cn test` cannot find a counterexample after 100 - tests? +- Bonus: Can you write an incorrect implementation of `add` for which testing + will (incorrectly) succeed — i.e., such that `cn test` cannot find a + counterexample after 100 tests? ```c title="exercises/add.partial.c" --8<-- @@ -190,7 +191,7 @@ exercises/id_by_div/id_by_div.fixed.c --8<-- ``` -A specification with both preconditions and postconditions says that, if +A specification with both preconditions and postconditions says: if the preconditions hold at the point where the function is called, then the postconditions will hold when the function returns. @@ -211,11 +212,11 @@ exercises/id_by_div/id_by_div_n.broken.c --8<-- ``` -_Exercise_: Write a specification for this -function that says that the result is between the first argument and -the second, but that does not reveal the precise value of the -result. (I.e., the same specification should work for a function that -returns `p` or `(p+q)/2` instead of `q`.) +_Exercise_: Write a specification for this function that says the result is +between the first argument and the second, but that does not reveal the precise +value of the result. (That is, the same specification should work for a +function that returns `p` or `(p+q)/2` instead of `q`.) +{{ later("JWS: 'between the first argument and the second' is a bit confusing because it doesn't imply to me that p <= q") }} ```c title="exercises/between.c" --8<-- exercises/between.c diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 80ba75bb..abd86306 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -9,10 +9,11 @@ This tutorial introduces CN through a series of examples and case studies, starting with basic usage of CN on simple arithmetic functions and slowly moving towards more elaborate separation logic specifications of data structures. -{{ later("BCP: Once the structure of the tutorial stabilizes, we +{{ later("BCP: Once the structure of the tutorial stabilizes, we could outline the material it covers in more detail...") }} CN can be used in two distinct ways: + - The simpler way is as a framework for writing down formal specifications of C code, in the form of logical pre- and post-conditions, and _testing_ that the code agrees with its @@ -23,12 +24,11 @@ CN can be used in two distinct ways: of assurance, in return for a somewhat larger investment in learning to use the verification-oriented aspects of CN. -The main thread of this tutorial is aimed at readers who want to get -up to speed quickly with specifying and testing C programs using -CN. Verification topics are covered in optional sections throughout -the document. Most readers -- even readers whose primary interest is -verification -- should skip these sections on a first reading and, if -desired, come back to them on a second pass. +The main thread of this tutorial is aimed at readers who want to get up to speed +quickly with specifying and testing C programs using CN. Verification topics are +covered in optional sections marked (V). Most readers — even readers whose +primary interest is verification — should skip these sections on a first reading +and, if desired, come back to them on a second pass. ## Setup Instructions diff --git a/src/exercises/id_by_div/id_by_div.broken.c b/src/exercises/id_by_div/id_by_div.broken.c index 1330ebc1..a7e5f759 100644 --- a/src/exercises/id_by_div/id_by_div.broken.c +++ b/src/exercises/id_by_div/id_by_div.broken.c @@ -1,4 +1,4 @@ -unsigned int id_by_div/id_by_div(unsigned int x) +unsigned int id_by_div(unsigned int x) /*@ ensures return == x; @*/ { return (x / 2) * 2; diff --git a/src/exercises/min3/min3.partial1.c b/src/exercises/min3/min3.partial1.c index b800b4c0..3be96345 100644 --- a/src/exercises/min3/min3.partial1.c +++ b/src/exercises/min3/min3.partial1.c @@ -1,5 +1,5 @@ unsigned int min3(unsigned int x, unsigned int y, unsigned int z) -/*@ ensures return <= x +/*@ ensures return <= x && return <= y && return <= z; @*/ From ac4ef56adc9b270afcae1bd0985751d73fa6aed0 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 4 Apr 2025 14:52:07 -0400 Subject: [PATCH 107/158] More fixes --- docs/getting-started/tutorials/README.md | 33 +++++++-------------- docs/getting-started/tutorials/arrays.md | 7 ++--- docs/getting-started/tutorials/pointers.md | 34 ++++------------------ docs/getting-started/tutorials/welcome.md | 7 +++-- main.py | 9 ++++++ 5 files changed, 32 insertions(+), 58 deletions(-) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index da0f64ed..60bbafca 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,39 +4,28 @@ ## A Tour of CN - [A first taste of CN: Specification and testing](first-taste.md) -- [(V) - A first taste of verification](verif-basics.md) +- [{{ verifmarker("A first taste of verification") }}](verif-basics.md) - [Working with pointers](pointers.md) -- [(V) - Pointers to structured objects, verified](verif-pointers.md) +- [{{ verifmarker("Pointers to structured objects, verified") }}](verif-pointers.md) - [Arrays and loops](arrays.md) -- [(V) - Arrays and loops, verified](verif-arrays.md) +- [{{ verifmarker("Arrays and loops, verified") }}](verif-arrays.md) - [Allocating and deallocating memory](alloc.md) -- (V) - [Allocating and deallocating memory, verified](verif-alloc.md) +- [{{ verifmarker("Allocating and deallocating memory, verified") }}](verif-alloc.md) - [Defining predicates](predicates.md) - [Lists](lists.md) -- [(V) - Lists, verified](verif-lists.md) -- [(V) - Case analysis](verif-splitcase.md) -- (V) - [More on numeric types](verif-numeric.md) -- [(V) - Working with external lemmas](verif-external.md) +- [{{ verifmarker("Lists, verified") }}](verif-lists.md) +- [{{ verifmarker("Case analysis") }}](verif-splitcase.md) +- [{{ verifmarker("More on numeric types") }}](verif-numeric.md) +- [{{ verifmarker("Working with external lemmas") }}](verif-external.md) ## Case studies - [Imperative queues](../case-studies/imperative-queues.md) -- [(V) - Imperative queues, verified](../case-studies/verif-imperative-queues.md) +- [{{ verifmarker("Imperative queues, verified") }}](../case-studies/verif-imperative-queues.md) - [Doubly-linked lists](../case-studies/doubly-linked-lists.md) -- [(V) - Doubly-linked lists, verified](../case-studies/verif-doubly-linked-lists.md) +- [{{ verifmarker("Doubly-linked lists, verified") }}](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) -- [(V) - Airport simulation, verified](../case-studies/verif-the-runway.md) +- [{{ verifmarker("Airport simulation, verified") }}](../case-studies/verif-the-runway.md) ## TODOs diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index a0f6c51c..7318f437 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -4,12 +4,9 @@ Another common datatype in C is arrays. Reasoning about memory ownership for arr To support reasoning about code manipulating arrays and computed pointers, CN has _iterated resources_. For instance, to specify ownership of an `unsigned` array with 10 cells starting at pointer `p`, CN uses the following iterated resource: - -JWS: I think these should be `u64`s (per the warning), +{{ todo("JWS: I think these should be `u64`s (per the warning), but then the sizes `n` need to be cast to `u64` from `u32` -in the later example. Not sure what the cleanest route is here. - - +in the later example. Not sure what the cleanest route is here.")}} ```c each (u32 i; i < 10u32) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 73ad8484..c5771ca1 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -43,34 +43,12 @@ Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type `T`. -{{ todo(" If `T` is a single-word type, then `` can be omitted. ") }} -{{ todo(" JWS: ^I propose that we cut this sentence, since -I don't know what a 'single-word type' is and -I think type annotations that are sometimes optional and sometimes not -are less confusingly presented as always required? ") }} - -{{ todo(" BCP: I feel torn about this. On one hand, the CN specs we are - asking people to read and write are pretty long and verbose, - impeding understanding, and removing all these type annotations - would streamline some of them significantly. Moreover, I don't - find it hard to explain to a C programmer that when the type is - represented in 32 bits it can be omitted. On the other hand, I - do agree that there is *some* overhead to telling people that the - annotation can be omitted. I can see a couple stable alternatives: - - Keep the annotations everywhere - - Delete them everywhere they can be deleted (i.e., for - one-word types) and explain, either here or when we get to the - first multi-word pointer target, that we need the annotation - there. - I mildly prefer the second. But I wonder whether the decision - should be informed by some data about whether pointers to single - words are common in real C code... -") }} - -{{ todo("BCP: Do we mean 32-bit word here?? -And BCP: Maybe the description of the T argument can be - postponed for a while, if we remove the - annotations...?") }} +{{ hidden("BCP: The description of the T argument could be postponed + for a while, if we removed `` annotations everywhere. + But I'm not convinced that this suppressing is helpful; it really + depends whether real C code often uses pointers to things whose + size CN can determine automatically, and I don't have a clear + enough picture of what those are...") }} In this example, we can ensure the safe execution of `read` by adding a precondition that requires ownership of `RW(p)`, as diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 80ba75bb..4a450359 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -26,9 +26,10 @@ CN can be used in two distinct ways: The main thread of this tutorial is aimed at readers who want to get up to speed quickly with specifying and testing C programs using CN. Verification topics are covered in optional sections throughout -the document. Most readers -- even readers whose primary interest is -verification -- should skip these sections on a first reading and, if -desired, come back to them on a second pass. +the document, marked "{{ verifmarkername() }}". Most readers -- even +readers whose primary interest is verification -- should skip these +sections on a first reading and, if desired, come back to them on a +second pass. ## Setup Instructions diff --git a/main.py b/main.py index 9959ac73..35c059bb 100644 --- a/main.py +++ b/main.py @@ -28,3 +28,12 @@ def hidden(mesg): "Format a TODO that should not actually appear right now" return "" + @env.macro + def verifmarkername(): + return "(V)" + + @env.macro + def verifmarker(title): + "format a title with a marker that it is a verification chapter" + return verifmarkername() + " " + title + From b04d5dae774ef8cf12053c61067944587fd216bd Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Fri, 4 Apr 2025 14:58:02 -0400 Subject: [PATCH 108/158] Finish merge --- docs/getting-started/tutorials/README.md | 33 ++++++++---------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index e0489842..1e56847e 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -4,39 +4,28 @@ ## A Tour of CN - [A First Taste of CN: Specification and Testing](first-taste.md) -- [(V) - A First Taste of Verification](verif-basics.md) +- [{{ verifmarker("A First Taste of Verification") }}](verif-basics.md) - [Working with Pointers](pointers.md) -- [(V) - Pointers to Structured Objects, Verified](verif-pointers.md) +- [{{ verifmarker("Pointers to Structured Objects, Verified") }}](verif-pointers.md) - [Arrays and Loops](arrays.md) -- [(V) - Arrays and Loops, Verified](verif-arrays.md) +- [{{ verifmarker("Arrays and Loops, Verified") }}](verif-arrays.md) - [Allocating and Deallocating Memory](alloc.md) -- (V) - [Allocating and Deallocating Memory, Verified](verif-alloc.md) +- [{{ verifmarker("Allocating and Deallocating Memory, Verified") }}](verif-alloc.md) - [Defining Predicates](predicates.md) - [Lists](lists.md) -- [(V) - Lists, Verified](verif-lists.md) -- [(V) - Case Analysis](verif-splitcase.md) -- (V) - [More on Numeric Types](verif-numeric.md) -- [(V) - Working with External Lemmas](verif-external.md) +- [{{ verifmarker("Lists, Verified") }}](verif-lists.md) +- [{{ verifmarker("Case Analysis") }}](verif-splitcase.md) +- [{{ verifmarker("More on Numeric Types") }}](verif-numeric.md) +- [{{ verifmarker("Working with External Lemmas") }}](verif-external.md) ## Case studies - [Imperative Queues](../case-studies/imperative-queues.md) -- [(V) - Imperative Queues, Verified](../case-studies/verif-imperative-queues.md) +- [{{ verifmarker("Imperative Queues, Verified") }}](../case-studies/verif-imperative-queues.md) - [Doubly-Linked Lists](../case-studies/doubly-linked-lists.md) -- [(V) - Doubly-Linked Lists, Verified](../case-studies/verif-doubly-linked-lists.md) +- [{{ verifmarker("Doubly-Linked Lists, Verified") }}](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) -- [(V) - Airport Simulation, Verified](../case-studies/verif-the-runway.md) +- [{{ verifmarker("Airport Simulation, Verified") }}](../case-studies/verif-the-runway.md) ## TODOs From 295ced55a075c8b76781039224132e457791a19c Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 4 Apr 2025 16:57:48 -0400 Subject: [PATCH 109/158] tweaks to pointers --- docs/getting-started/tutorials/pointers.md | 31 +++++++++++----------- src/exercises/read.broken.c | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index 967f21cd..fa063810 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -37,7 +37,7 @@ For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. We next explain how to represent this permission. -## RW resources +## RW Resources Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type @@ -72,7 +72,7 @@ This specification can be read as follows: - the caller will receive back a resource `RW(p)` when `read` returns. -## Pointee values +## Pointee Values In addition to reasoning about memory accesed by pointers, we likely also want to reason about the actual values that the pointers point to. The `take P =` in @@ -126,7 +126,7 @@ while running `cn test` on this incorrect implementation *p = 0; return m; ``` -or this incorrect implementation +and this incorrect implementation ```C unsigned int n = *p; unsigned int m = n + n + n; @@ -134,7 +134,7 @@ or this incorrect implementation ``` should fail. -## Writing through pointers +## Writing Through Pointers We next have an example where data is written to a pointer. The function `incr` takes a pointer `p` and increments the value in the memory cell that it @@ -162,7 +162,7 @@ exercises/slf3_basic_inplace_double.c --8<-- ``` -## No memory leaks +## No Memory Leaks In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. @@ -193,23 +193,24 @@ read(p); The error from `cn test` report tells us (1) in which function the error occurred, (2) what happened -("ownership leaked"), and (3) a failing input -- i.e., a snipped of C +("ownership leaked"), and (3) a failing input — i.e., a snippet of C code that will construct a heap state on which the test fails in this -way. +way. What went wrong here is that, given the above specification, `read` leaks memory: it takes ownership, does not return it, but also does not deallocate the RW memory or otherwise dispose of it. CN requires that every resource passed into a function has to be either _returned_ to the caller or else _destroyed_ by deallocating the RW area of -memory (as we shall see later). CN’s motivation for this choice is its focus on -low-level systems software in which memory is managed manually; in this context, -memory leaks are typically very undesirable. -As a consequence, function specifications have to do precise bookkeeping of -their resource footprint and, in particular, return any unused resources back to -the caller. +memory (as we shall see later). -## Disjoint memory regions +CN’s motivation for this choice is its focus on low-level systems software in +which memory is managed manually; in this context, memory leaks are typically +very undesirable. As a consequence, function specifications have to do precise +bookkeeping of their resource footprint and, in particular, return any unused +resources back to the caller. + +## Disjoint Memory Regions When functions manipulate multiple pointers, we can assert ownership of each one, just like before. But there is an additional twist: simultaneously owning @@ -239,7 +240,7 @@ exercises/slf8_basic_transfer.c --8<-- ``` -## Ownership of structured objects +## Ownership of Structured Objects So far, our examples have worked with just integers and pointers, but larger programs typically also manipulate compound values, often diff --git a/src/exercises/read.broken.c b/src/exercises/read.broken.c index 1ccc2699..878b2d97 100644 --- a/src/exercises/read.broken.c +++ b/src/exercises/read.broken.c @@ -1,5 +1,5 @@ unsigned int read (unsigned int *p) -/*@ requires take v1 = RW(p); @*/ +/*@ requires take P = RW(p); @*/ { return *p; } From 9cca03af2a55ba9a5a2de431539b0304c22e57ca Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Sat, 5 Apr 2025 01:07:55 -0400 Subject: [PATCH 110/158] take pass over verif-arrays --- docs/getting-started/tutorials/arrays.md | 10 +-- .../getting-started/tutorials/verif-arrays.md | 84 +++++++------------ src/exercises/array_init_rev.c | 9 +- src/exercises/array_load.broken.c | 10 --- src/exercises/array_load.c | 15 ++-- src/exercises/array_load.test.c | 2 +- 6 files changed, 50 insertions(+), 80 deletions(-) delete mode 100644 src/exercises/array_load.broken.c diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index 2ade6970..c23c8192 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -33,7 +33,7 @@ each ( ; ) { } ### First Array Example -Let’s see how this applies to a simple array-manipulating function. Function `readi` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `readi` then returns the value of the `i`-th array cell. +Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. ```c title="exercises/array_load.test.c" --8<-- @@ -58,9 +58,9 @@ exercises/array_write.test.c --8<-- ``` -The specification closely resembles that of `readi`, except for the last line, which now asserts that `A_post[i]`, the value of the array _after_ the function executes at index `i`, is equal to `val`. +The specification closely resembles that of `read`, except for the last line, which now asserts that `A_post[i]`, the value of the array _after_ the function executes at index `i`, is equal to `val`. -What if we additionally wanted to make assertions about values in the array _not_ being modified? In the prior `readi` example, we could add +What if we additionally wanted to make assertions about values in the array _not_ being modified? In the prior `read` example, we could add ```c A == A_post ``` @@ -167,8 +167,8 @@ exercises/array_add3.test.c _Exercise:_ Write a specification for `array_sort`, which should sort an array into increasing order. Your specification should succeed on -this correct implementation below -(yes, [it's correct](https://arxiv.org/abs/2110.01111)), and fail +this correct implementation below +(yes, [it's correct](https://arxiv.org/abs/2110.01111)), and fail when bugs are inserted: {{ later("JWS: One gnarly aspect of this is that you need to carefully diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 21992320..8bafc39b 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -2,23 +2,22 @@ Recall this specification for a simple function that reads from an array: -```c title="exercises/array_load.broken.c" +```c title="exercises/array_load.test.c" --8<-- -exercises/array_load.broken.c +exercises/array_load.test.c --8<-- ``` -This specification, in principle, should ensure that the access `p[i]` +This specification should ensure that the access `p[i]` is safe. However, running `cn verify` on the example produces an error: CN is unable to find the required ownership for reading `p[i]`. ``` -cn verify solutions/array_load.broken.c -[1/1]: read -build/solutions/array_load.broken.c:5:10: error: Missing resource for reading -return p[i]; -^~~~ -Resource needed: RW(array_shift(p, (u64)i)) +[1/1]: read -- fail +solutions/array_load.test.c:10:10: error: `&p[(u64)i]` out of bounds + return p[i]; + ^~~~ +(UB missing short message): UB_CERB004_unspecified__pointer_add ``` The reason is that, when searching for a required resource, such as @@ -38,13 +37,13 @@ exercises/array_load.c --8<-- ``` -The CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "`ghost statement`" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits the iterated resource into two: +The CN comment `/*@ focus RW, i; @*/` is a proof hint in the form of a "ghost statement" that instructs CN to instantiate any available iterated `RW` resource for index `i`. In our example this operation splits this iterated resource ```c -each(i32 j; 0i32 <= j && j < n) { RW(array_shift(p,j)) } +each(u32 j; j < n) { RW(array_shift(p,j)) } ``` -is split into +into two parts: 1. the instantiation of the iterated resource at `i` @@ -55,48 +54,19 @@ RW(array_shift(p,i)) 2. the remainder of the iterated resource, the ownership for all indices except `i` ```c - each(i32 j; 0i32 <= j && j < n && j != i) + each(u32 j; j < n && j != i) { RW(array_shift(p,j)) } ``` After this extraction step, CN can use the (former) extracted resource to justify the access `p[i]`. Note that an `focus` statement's second argument can be any arithmetic expression, not just a single identifier like in this example. -Following an `focus` statement, CN remembers the extracted index and can automatically "`reverse`" the extraction when needed: after type checking the access `p[i]` CN must ensure the function’s postcondition holds, which needs the full array ownership again (including the extracted index `i`); remembering the index `i`, CN then automatically merges resources (1) and (2) again to obtain the required full array ownership, and completes the verification of the function. - -So far the specification only guarantees safe execution but does not -specify the behaviour of `read`. To address this, let’s return to -the iterated resources in the function specification. When we specify -`take A = each ...` here, what is `A`? In CN, the output of an -iterated resource is a _map_ from indices to resource outputs. In this -example, where index `j` has CN type `i32` and the iterated -resource is `RW`, the output `A` is a map from `i32` -indices to `i32` values — CN type `map`. If the type of -`j` was `i64` and the resource `RW`, `A` would have -type `map`. - -We can use this to refine our specification with information about the functional behaviour of `read`. - -```c title="exercises/array_load2.c" ---8<-- -exercises/array_load2.c ---8<-- -``` - -We specify that `read` does not change the array — the outputs of `RW`, -`A` and `A_post`, taken before and after running the function, are -the same — and that the value returned is `A[i]`. +Following a `focus`, CN remembers the extracted index and can automatically "reverse" the extraction when needed, merging the resources when ownership of the full array is required. + ### Exercises -_Exercise:_ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. *Assuming `i` and `j` are different*, it returns the sum of the values at these two indices. - -```c title="exercises/array_read_two.c" ---8<-- -exercises/array_read_two.c ---8<-- -``` - -_Exercise:_ Specify and verify `swap_array`, which swaps the values of two cells of an `unsigned int` array. Assume again that `i` and `j` are different, and describe the effect of `swap_array` on the array value using the CN map update expression `a[i:v]`, which denotes the same map as `a`, except with index `i` updated to `v`. +_Exercise:_ Add `focus` statements to verify your specification of `array_swap` from last chapter. ```c title="exercises/array_swap.c" --8<-- @@ -129,11 +99,18 @@ the numeric stuff works. } ") }} -### Loops -The array examples covered so far manipulate one or two individual cells of an array. Another typical pattern in code working over arrays is to _loop_, uniformly accessing all cells of an array or a sub-range of it. +_Exercise:_ Specify and verify the following function, `array_read_two`, which takes the base pointer `p` of an `unsigned int` array, the array length `n`, and two indices `i` and `j`. *Assuming `i` and `j` are different*, it returns the sum of the values at these two indices. -In order to verify code with loops, CN requires the user to supply loop invariants -- CN specifications of all RW resources and the constraints required to verify each iteration of the loop. +```c title="exercises/array_read_two.c" +--8<-- +exercises/array_read_two.c +--8<-- +``` + +### Loops + +If we have array code with loops, CN requires the user to supply _loop invariants_ — CN specifications of the `RW` resources and constraints required to verify each iteration of the loop. Let's take a look at a simple first example. The following function, `array_init`, takes the base pointer `p` of a `char` array and the array length `n` and writes `0` to each array cell. @@ -143,7 +120,7 @@ exercises/array_init.c --8<-- ``` -If, for the moment, we focus just on proving safe execution of `array_init`, ignoring its functional behaviour, a specification might look as above: on entry, `array_init` takes ownership of an iterated `RW` resource -- one `RW` resource for each index `i` of type `u32` (so necessarily greater or equal to `0`) up to `n`; on exit `array_init` returns the ownership. +If we focus for now just on proving safe execution of `array_init`, a specification might look as above. This closely resembles specifications we have seen previously, but now with `char`s. To verify this, we have to supply a loop invariant that specifies all resource ownership and the necessary constraints that hold before and after each iteration of the loop. Loop invariants are specified using the keyword `inv`, followed by CN specifications using the same syntax as in function pre- and postconditions. The variables in scope for loop invariants are all in-scope C variables, as well as CN variables introduced in the function precondition. _In loop invariants, the name of a C variable refers to its current value_ (more on this shortly). @@ -168,7 +145,10 @@ The final piece needed in the verification is an `focus` statement, as used in t With the `inv` and `focus` statements in place, CN accepts the function. -### Second loop example + +{{ todo("JWS: removed second loop example because it is out of sync as we moved `W` resources later. could try to replace with something from the previous chapter") }} + + ### Exercises diff --git a/src/exercises/array_init_rev.c b/src/exercises/array_init_rev.c index 5d635325..60b5bf06 100644 --- a/src/exercises/array_init_rev.c +++ b/src/exercises/array_init_rev.c @@ -1,7 +1,6 @@ void array_init_rev (char *p, unsigned int n) /*@ requires take A = each(u32 i; i < n) { - W( array_shift(p, i)) }; - n > 0u32; + RW( array_shift(p, i)) }; ensures take A_post = each(u32 i; i < n) { RW( array_shift(p, i)) }; @*/ @@ -10,16 +9,16 @@ void array_init_rev (char *p, unsigned int n) while (j < n) /* --BEGIN-- */ /*@ inv take Al = each(u32 i; i < n-j) { - W( array_shift(p, i)) }; + RW( array_shift(p, i)) }; take Ar = each(u32 i; n-j <= i && i < n) { RW( array_shift(p, i)) }; {p} unchanged; {n} unchanged; - 0u32 <= j && j <= n; + j <= n; @*/ /* --END-- */ { /* --BEGIN-- */ - /*@ focus W, n-(j+1u32); @*/ + /*@ focus RW, n-(j+1u32); @*/ /*@ focus RW, n-(j+1u32); @*/ /* --END-- */ p[n-(j+1)] = 0; diff --git a/src/exercises/array_load.broken.c b/src/exercises/array_load.broken.c deleted file mode 100644 index 618cc8ac..00000000 --- a/src/exercises/array_load.broken.c +++ /dev/null @@ -1,10 +0,0 @@ -int read (int *p, int n, int i) -/*@ requires take A = each(i32 j; 0i32 <= j && j < n) { - RW(array_shift(p,j)) }; - 0i32 <= i && i < n; - ensures take A_post = each(i32 j; 0i32 <= j && j < n) { - RW(array_shift(p,j)) }; -@*/ -{ - return p[i]; -} diff --git a/src/exercises/array_load.c b/src/exercises/array_load.c index 58e039a2..80805dda 100644 --- a/src/exercises/array_load.c +++ b/src/exercises/array_load.c @@ -1,11 +1,12 @@ -int read (int *p, int n, int i) -/*@ requires take A = each(i32 j; 0i32 <= j && j < n) { - RW(array_shift(p,j)) }; - 0i32 <= i && i < n; - ensures take A_post = each(i32 j; 0i32 <= j && j < n) { - RW(array_shift(p,j)) }; +unsigned int read (unsigned int *p, unsigned int n, unsigned int i) +/*@ requires take A = each(u32 j; j < n) + { RW(array_shift(p,j)) }; + i < n; + ensures take A_post = each(u32 j; j < n) + { RW(array_shift(p,j)) }; + return == A[i]; @*/ { - /*@ focus RW, i; @*/ + /*@ focus RW, i; @*/ return p[i]; } diff --git a/src/exercises/array_load.test.c b/src/exercises/array_load.test.c index b1787097..7c35a742 100644 --- a/src/exercises/array_load.test.c +++ b/src/exercises/array_load.test.c @@ -1,4 +1,4 @@ -unsigned int readi (unsigned int *p, unsigned int n, unsigned int i) +unsigned int read (unsigned int *p, unsigned int n, unsigned int i) /*@ requires take A = each(u32 j; j < n) { RW(array_shift(p,j)) }; i < n; From e3a2b34c3152fd1b2166e14d6b68c84827190689 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Sun, 6 Apr 2025 19:42:01 -0400 Subject: [PATCH 111/158] Last fix --- docs/getting-started/case-studies/imperative-queues.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 5b61c6dd..37627190 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -1,5 +1,9 @@ # Imperative Queues +{{ todo("BCP: Zain points out that the lemma in `push_lemma.h` might +be wrong when `P.next` is `NULL`... To fix it, try taking ownership[ +of `p.next in both the pre- and the postcondition of the push lemma.")}} + A queue is a linked list with constant-time operations for adding things to one end (the "back") and removing them from the other (the "front"). Here are the C type definitions: From 109484a73e26f0cca86f0673c30410e47671fa60 Mon Sep 17 00:00:00 2001 From: Christopher Pulte Date: Mon, 7 Apr 2025 18:30:52 +0100 Subject: [PATCH 112/158] tweaks+fixes to verif-pointers.md --- .../tutorials/verif-pointers.md | 36 ++++++++++--------- src/exercises/transpose2.c | 4 +-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/getting-started/tutorials/verif-pointers.md b/docs/getting-started/tutorials/verif-pointers.md index 642101dc..a7ca5606 100644 --- a/docs/getting-started/tutorials/verif-pointers.md +++ b/docs/getting-started/tutorials/verif-pointers.md @@ -10,7 +10,7 @@ Given a struct pointer, C programmers can construct pointers to _individual stru Instead, `RW` is defined inductively on the structure of the C-type `T`. To handle code that manipulates pointers into parts of a struct object, CN can automatically decompose a struct resource into the resources of its members, and it can recompose the struct later, as needed. The following example illustrates this. -Suppose we have a function `zero` that initializes a pointer to 0. Now consider the function `init_point` which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. +Suppose we have a function `zero` that takes a pointer to an `unsigned int` and initialises its value to 0. Now consider the function `init_point` which takes a pointer `p` to a `struct point` and zero-initialises its members by calling `zero` twice, once with a pointer to struct member `x`, and once with a pointer to `y`. ```c title="exercises/init_point.c" --8<-- @@ -18,17 +18,17 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `RW(p)`. The `zero` function, however, works on `unsigned int` pointers and requires `RW` ownership. +As stated in its precondition, `init_point` receives ownership `RW(p)`. The `zero` function, however, works on `unsigned int` pointers and requires ownership `RW`, so CN cannot simply pass `init_point`'s struct ownership to `zero`. Instead, CN decomposes the `RW(p)` resource into two `RW` resources, one for each member pointer, and proves that the calls to `zero` with `&p->x` and `&p->y` are safe by supplying the respective `RW` resources. -CN can prove the calls to `zero` with `&p->x` and `&p->y` are safe because it decomposes the `RW(p)` into a `RW` for member `x` and likewise for member `y`. Later, the reverse happens. Since the postcondition of `init_point` requires ownership `RW(p)`, CN combines these back into a compound resource. The resulting pointee value `P_post` is a struct composed of the zeroed member values for `x` and `y`. +Later, the reverse happens. Since the postcondition of `init_point` requires ownership `RW(p)`, CN re-assembles the two `RW` resources (now both zero-initialised) back into a compound struct resource. The resulting pointee value `P_post` is a struct composed of the zeroed member values for `x` and `y`. ## Resource inference -To handle the required resource inference, CN "`eagerly`" decomposes all `struct` resources into resources for the struct members, and "`lazily`" re-composes them as needed. +To handle the required resource inference, CN "eagerly" decomposes all `struct` resources into resources for the struct members, and "lazily" re-composes them as needed. -We can see this if we experimentally change the previous `transpose` example to force a type error. Let’s insert an `/*@ assert(false) @*/` CN assertion in the middle of `transpose`, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) +We can see this if we experimentally change the previous `transpose` example to force a verification error. Let’s insert an `/*@ assert(false); @*/` CN assertion into the middle of `transpose`, so we can inspect CN’s proof context shown in the error report. (More on CN assertions later.) -{{ todo("BCP: Recheck that what we say here matches what it actually looks like") }} + ```c title="exercises/transpose.broken.c" --8<-- @@ -46,27 +46,29 @@ exercises/transpose.broken.c --8<-- ``` -The precondition of `transpose` asserts ownership of an `RW(p)` resource. The error report now instead lists under "`Available resources`" two resources: +CN produces an HTML error report with information about a possible trace of the function leading to the error. Click 'last' to jump to the state just before the error. Under "`Available resources`" we find five resources listed. The first three capture ownership of the local variables: +- `RW(&temp_y)(P.y)` (ownership of the stack location holding local variable `temp_y`) +- `RW(&temp_x)(P.x)` (as above, for `temp_x`) +- `RW(&ARG0)(p)` (ownership of the stack location holding the value of function argument `p`). More relevant for us now, the remaining two resources contain the `struct point` ownership. Whereas in the precondition of `transpose` we asserted ownership of an `RW(p)` resource, here we instead see that CN has decomposed this into the two member resources: +- `RW(&p->y)(P.y)` (asserting ownership of location `&p->y`, and that the value is the `y` member of the input struct value `P`) +- `RW(&p->x)(P.x)` (respectively asserting ownership of `&p->x` with value `P.x`). -- `RW(member_shift(p, x))` with output `P.x` and + -- `RW(member_shift(p, y))` with output `P.y` + -{{ todo("BCP: We should verify that it really does say this. (It certainly -does not, after recent syntax changes...)") }} - -Here `member_shift(p,m)` is the CN expression that constructs, from a `struct s` pointer `p`, the "`shifted`" pointer for its member `m`. - -When the function returns, the two member resources are recombined "`on demand`" to satisfy the postcondition `RW(p)`. +The assignments to `p->x` and `p->y` update these member resources with new values, and when the function returns, they are recombined "`on demand`" to satisfy the postcondition `RW(p)`. ### Exercises _Exercise:_ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. _Exercise:_ Recreate the `transpose` function from before, now -using the `swap` function. +using the `swap` function: write a specification for `swap` (as defined below) and verify the result in CN. {{ todo("JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work?") }} {{ todo("BCP: Maybe that's OK? Or maybe we can think of a more interesting variant...") }} +{{ todo("CP: I tweaked the exercise so it includes (at least) giving a specification for `swap`; that's still an easy exercise and we could use more+more interesting ones, but maybe it's better than nothing, for now.") }} ```c title="exercises/transpose2.c" diff --git a/src/exercises/transpose2.c b/src/exercises/transpose2.c index 35eb9d7c..e79d10d8 100644 --- a/src/exercises/transpose2.c +++ b/src/exercises/transpose2.c @@ -1,10 +1,12 @@ void swap (unsigned int *p, unsigned int *q) +/* --BEGIN-- */ /*@ requires take P = RW(p); take Q = RW(q); ensures take P_post = RW(p); take Q_post = RW(q); P_post == Q && Q_post == P; @*/ +/* --END-- */ { unsigned int m = *p; unsigned int n = *q; @@ -15,13 +17,11 @@ void swap (unsigned int *p, unsigned int *q) struct point { unsigned int x; unsigned int y; }; void transpose2 (struct point *p) -/* --BEGIN-- */ /*@ requires take P = RW(p); ensures take P_post = RW(p); P_post.x == P.y; P_post.y == P.x; @*/ -/* --END-- */ { swap(&p->x, &p->y); } From 36855b39d811c07d16c752effcb26f404da0903e Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 7 Apr 2025 17:06:42 -0400 Subject: [PATCH 113/158] Update CI to new CN repository --- .github/workflows/run-cn-examples.yml | 52 +++++++++++---------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/.github/workflows/run-cn-examples.yml b/.github/workflows/run-cn-examples.yml index 469487ef..ea085b8c 100644 --- a/.github/workflows/run-cn-examples.yml +++ b/.github/workflows/run-cn-examples.yml @@ -1,4 +1,4 @@ -# Modified from rems-project/cerberus/blob/master/.github/workflows/ci.yml +# Modified from rems-project/cn/blob/master/.github/workflows/ci-cn.yml name: Test all examples with CN @@ -24,13 +24,13 @@ jobs: steps: - uses: actions/checkout@v4 with: - repository: rems-project/cerberus + repository: rems-project/cn - name: System dependencies (ubuntu) run: | sudo apt install build-essential libgmp-dev z3 opam - - - name: Restore cached opam + + - name: Restore OPAM cache id: cache-opam-restore uses: actions/cache/restore@v4 with: @@ -39,28 +39,31 @@ jobs: - name: Setup opam if: steps.cache-opam-restore.outputs.cache-hit != 'true' - run: opam init --yes --no-setup --shell=sh --compiler=${{ matrix.version }} - - - name: Install dependencies run: | - opam switch ${{ matrix.version }} + opam init --yes --no-setup --shell=sh --compiler=${{ matrix.version }} eval $(opam env --switch=${{ matrix.version }}) - opam install --deps-only --yes ./cerberus.opam ./cerberus-lib.opam ./cn.opam + opam repo add --yes --this-switch coq-released https://coq.inria.fr/opam/released + opam install --deps-only --yes ./cn.opam - - name: Save cached opam - id: cache-opam-save + - name: Save OPAM cache uses: actions/cache/save@v4 + if: steps.cache-opam-restore.outputs.cache-hit != 'true' with: path: ~/.opam - key: ${{ steps.cache-opam-restore.outputs.cache-primary-key }} + key: ${{ matrix.version }} + + - name: Download cvc5 release + uses: robinraju/release-downloader@v1 + with: + repository: cvc5/cvc5 + tag: cvc5-1.2.0 + fileName: cvc5-Linux-x86_64-static.zip - - name: Install Cerberus + - name: Unzip and install cvc5 run: | - opam switch ${{ matrix.version }} - eval $(opam env --switch=${{ matrix.version }}) - opam pin --yes --no-action add cerberus-lib . - opam pin --yes --no-action add cerberus . - opam install --yes cerberus + unzip cvc5-Linux-x86_64-static.zip + chmod +x cvc5-Linux-x86_64-static/bin/cvc5 + sudo cp cvc5-Linux-x86_64-static/bin/cvc5 /usr/local/bin/ - name: Install CN run: | @@ -69,19 +72,6 @@ jobs: opam pin --yes --no-action add cn . opam install --yes cn - - name: Download cvc5 release - uses: robinraju/release-downloader@v1 - with: - repository: cvc5/cvc5 - tag: cvc5-1.1.2 - fileName: cvc5-Linux-static.zip - - - name: Unzip and install cvc5 - run: | - unzip cvc5-Linux-static.zip - chmod +x cvc5-Linux-static/bin/cvc5 - sudo cp cvc5-Linux-static/bin/cvc5 /usr/local/bin/ - - name: Checkout cn-tutorial uses: actions/checkout@v4 with: From aa8e308e004b1111ddb66952d1da47219e27cd97 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 7 Apr 2025 17:18:06 -0400 Subject: [PATCH 114/158] [CI] Install CN before building --- .github/workflows/test-tutorial-build.yml | 64 +++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-tutorial-build.yml b/.github/workflows/test-tutorial-build.yml index 121c36b0..3fd05882 100644 --- a/.github/workflows/test-tutorial-build.yml +++ b/.github/workflows/test-tutorial-build.yml @@ -11,8 +11,60 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + repository: rems-project/cn + + - name: System dependencies (ubuntu) + run: | + sudo apt install build-essential libgmp-dev z3 opam + + - name: Restore OPAM cache + id: cache-opam-restore + uses: actions/cache/restore@v4 + with: + path: ~/.opam + key: ${{ matrix.version }} + + - name: Setup opam + if: steps.cache-opam-restore.outputs.cache-hit != 'true' + run: | + opam init --yes --no-setup --shell=sh --compiler=${{ matrix.version }} + eval $(opam env --switch=${{ matrix.version }}) + opam repo add --yes --this-switch coq-released https://coq.inria.fr/opam/released + opam install --deps-only --yes ./cn.opam + + - name: Save OPAM cache + uses: actions/cache/save@v4 + if: steps.cache-opam-restore.outputs.cache-hit != 'true' + with: + path: ~/.opam + key: ${{ matrix.version }} + + - name: Download cvc5 release + uses: robinraju/release-downloader@v1 + with: + repository: cvc5/cvc5 + tag: cvc5-1.2.0 + fileName: cvc5-Linux-x86_64-static.zip + + - name: Unzip and install cvc5 + run: | + unzip cvc5-Linux-x86_64-static.zip + chmod +x cvc5-Linux-x86_64-static/bin/cvc5 + sudo cp cvc5-Linux-x86_64-static/bin/cvc5 /usr/local/bin/ + + - name: Install CN + run: | + opam switch ${{ matrix.version }} + eval $(opam env --switch=${{ matrix.version }}) + opam pin --yes --no-action add cn . + opam install --yes cn + + - name: Checkout cn-tutorial + uses: actions/checkout@v4 + with: + path: cn-tutorial - name: Set up Python uses: actions/setup-python@v5 @@ -23,7 +75,11 @@ jobs: run: pip install mkdocs-material - name: Clean the build directory - run: make clean + run: | + cd cn-tutorial + make clean - name: Check that the tutorial builds - run: make + run: | + cd cn-tutorial + make From c7d7692ddb810a42a8b040b5bd89b2716c42e192 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 7 Apr 2025 17:28:51 -0400 Subject: [PATCH 115/158] [CI] Fix cache for building --- .github/workflows/test-tutorial-build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-tutorial-build.yml b/.github/workflows/test-tutorial-build.yml index 3fd05882..0766d4ca 100644 --- a/.github/workflows/test-tutorial-build.yml +++ b/.github/workflows/test-tutorial-build.yml @@ -8,7 +8,11 @@ permissions: jobs: build: - runs-on: ubuntu-latest + strategy: + matrix: + version: [4.14.1] + + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 From a78cc5d582bb4d7fe4eba47698d16121bb33098f Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 7 Apr 2025 17:31:12 -0400 Subject: [PATCH 116/158] [CI] Checking is now part of building the tutorial --- Makefile | 6 +----- check.sh | 57 -------------------------------------------------------- 2 files changed, 1 insertion(+), 62 deletions(-) delete mode 100755 check.sh diff --git a/Makefile b/Makefile index 46424350..94b967c0 100644 --- a/Makefile +++ b/Makefile @@ -183,11 +183,7 @@ check-archive: @echo Check archive examples @$(MAKEFILE_DIR)/src/example-archive/check-all.sh "$(CN_PATH)" -check-tutorial: - @echo Check tutorial exercises - @$(MAKEFILE_DIR)/check.sh "$(CN_PATH)" - -check: check-tutorial check-archive +check: exercises check-archive ############################################################################## # Check for inconsistent exercise names / paths diff --git a/check.sh b/check.sh deleted file mode 100755 index 2eb54c26..00000000 --- a/check.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" - -if [ -n "$1" ] -then - echo "using CN=$1 in $PWD" - CN="$1" -else - CN="cn verify" -fi - -good=0 -bad=0 -declare -a bad_tests - -for file in $SCRIPT_DIR/src/examples/*c; -do - echo "Checking $file ..." - $CN $file - retval=$? - if [[ $file == *.broken.c ]] - then - if [[ $retval -ne 0 ]]; - then - good=$(($good+1)) - else - bad_tests[$bad]=$file - bad=$(($bad+1)) - fi - else - if [[ $retval -eq 0 ]]; - then - good=$(($good+1)) - else - bad_tests[$bad]=$file - bad=$(($bad+1)) - fi - fi -done - -echo "----------------------------" -echo "$good good, $bad bad" -echo "----------------------------" - - -if [[ "$bad" = 0 ]] -then - exit 0 -else - echo "Failed tests:" - for file in ${bad_tests[@]}; do - echo $file - done - exit 1 -fi - From ac2c4e3e0009e556ffa695e3ece9a145ecc6b30b Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 7 Apr 2025 17:41:09 -0400 Subject: [PATCH 117/158] Adjust testing flags --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 94b967c0..7220c97c 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) exercises: $(EXERCISES) $(SOLUTIONS) $(TESTED) $(VERIFIED) $(CONSISTENT) CN=cn verify -CNTEST=cn test --output _temp +CNTEST=cn test --output _temp --progress-level=function -I${OPAM_SWITCH_PREFIX}/lib/cerberus-lib/runtime/libc/include/posix # Control verbosity (run make with V= to show everything that's happening) V=@ From 76b19a643887321be4fc24b05951fc480d02b5b6 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 7 Apr 2025 17:43:23 -0400 Subject: [PATCH 118/158] Revert testing with Cerberus standard library Didn't fix CI issue --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7220c97c..6715068d 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) exercises: $(EXERCISES) $(SOLUTIONS) $(TESTED) $(VERIFIED) $(CONSISTENT) CN=cn verify -CNTEST=cn test --output _temp --progress-level=function -I${OPAM_SWITCH_PREFIX}/lib/cerberus-lib/runtime/libc/include/posix +CNTEST=cn test --output _temp --progress-level=function # Control verbosity (run make with V= to show everything that's happening) V=@ From 0e395653521449f5a50cbfcf74935495edf8a7d2 Mon Sep 17 00:00:00 2001 From: Cole Schlesinger Date: Mon, 7 Apr 2025 15:10:24 -0700 Subject: [PATCH 119/158] CI: Reset opam env before making tutorial --- .github/workflows/test-tutorial-build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-tutorial-build.yml b/.github/workflows/test-tutorial-build.yml index 0766d4ca..34b1e90e 100644 --- a/.github/workflows/test-tutorial-build.yml +++ b/.github/workflows/test-tutorial-build.yml @@ -85,5 +85,7 @@ jobs: - name: Check that the tutorial builds run: | + opam switch ${{ matrix.version }} + eval $(opam env --switch=${{ matrix.version }}) cd cn-tutorial make From bea703b1555708f75729038480121444f27ee4e9 Mon Sep 17 00:00:00 2001 From: Brett Decker Date: Tue, 8 Apr 2025 13:40:49 -0500 Subject: [PATCH 120/158] install: Point to new CN repo instead of Cerberus Updates the links to the CN repo and the CN README instead of the old Cerberus pages, the second of which is now a 404 error. --- docs/getting-started/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 330cbdf4..c81848ad 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -1,6 +1,6 @@ # Installation -To fetch and install CN, visit the [Cerberus repository](https://github.com/rems-project/cerberus) and follow the instructions in [backend/cn/README.md](https://github.com/rems-project/cerberus/blob/master/backend/cn/README.md). +To fetch and install CN, visit the [CN repository](https://github.com/rems-project/cn) and follow the installation instructions in the [README.md](https://github.com/rems-project/cn?tab=readme-ov-file#installation). Once the installation is completed, type `cn --help` in your terminal to ensure CN is installed and found by your system. This should print the list of available options CN can be executed with. From 522e19069f99ac5ba9c9625b37bbe6efc84e2270 Mon Sep 17 00:00:00 2001 From: Brett Decker Date: Tue, 8 Apr 2025 13:43:38 -0500 Subject: [PATCH 121/158] gitignore: Add __pycache__ folder to be ignored To remove the possibility of it accidentally being committed. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fe901c51..6fc04164 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ docs/solutions /docs/exercises.zip /_temp/ *.tmp +/__pycache__/ From 1446a79eaa6b099dde1e5aae52086d023922f1dc Mon Sep 17 00:00:00 2001 From: Brett Decker Date: Tue, 8 Apr 2025 14:24:13 -0500 Subject: [PATCH 122/158] install: Fix broken links to VERSE-Toolchain repo --- docs/getting-started/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index c81848ad..e14afaea 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -9,7 +9,7 @@ To use CN to verify a C file, run `cn verify CFILE`. To use CN to test a C file, run `cn test CFILE`. Install the [language -server](https://github.com/GaloisInc/VERSE-Toolchain/tree/main/cn-lsp/server) +server](https://github.com/GaloisInc/VERSE-Toolchain/tree/main/cn-lsp) and [VSCode -plugin](https://github.com/GaloisInc/VERSE-Toolchain/tree/main/cn-lsp/client) +plugin](https://github.com/GaloisInc/VERSE-Toolchain/tree/main/cn-client) for a better IDE experience. From abfa23de00fa0b4bed69646d4fdd73632f016c87 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 8 Apr 2025 21:55:07 -0400 Subject: [PATCH 123/158] Spelling --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index a230c30f..e095a6cc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ # Welcome to CN _These tutorials and docs were developed by Christopher Pulte, Benjamin C. -Pierce, and Cole Schlesinger, with contributions from Elizbeth Austell._ +Pierce, and Cole Schlesinger, with contributions from Elizabeth Austell. CN is an extension of the C programming language for testing and verifying the correctness of C code, especially on low-level systems code. Compared to From 3115dfbffcb8452ba5f42c93ef852f010da4ffb6 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Wed, 9 Apr 2025 07:25:20 -0400 Subject: [PATCH 124/158] Fix `push_lemma`, so it is true --- src/exercises/queue/push_lemma.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/exercises/queue/push_lemma.h b/src/exercises/queue/push_lemma.h index 00ba86d7..8d4e5782 100644 --- a/src/exercises/queue/push_lemma.h +++ b/src/exercises/queue/push_lemma.h @@ -4,6 +4,7 @@ lemma push_lemma (pointer front, pointer p) ptr_eq(front, p) || !addr_eq(front, p); take Q = QueueAux(front, p); take P = RW(p); + !is_null(P.next); ensures ptr_eq(front, P.next) || !addr_eq(front, P.next); take Q_post = QueueAux(front, P.next); From 3d6adc563d3dc823e0b9bf84cc3d4f6ea5a8685b Mon Sep 17 00:00:00 2001 From: Chris Phifer Date: Wed, 9 Apr 2025 12:18:06 -0700 Subject: [PATCH 125/158] mkdocs.yml: Add GitHub widget to tutorial pages. This makes sure there is a link to the GitHub-hosted tutorial repository on every page (either visible next to the search on large screens, or in the navigation drawer on small screens). Someone has already added the setting necessary to display "Edit this page" and "View this page" icons on each page -- this commit adds the requisite edit_uri configuration, which we need as we don't use `master` as our trunk branch name (note also that these links will be broken until the changes are merged into main; there is no obvious way to have edit_uri pick up the current branch for the benefit of local testing). --- mkdocs.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index a2732383..06149ff2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,8 @@ site_name: CN Docs site_dir: build +repo_url: https://github.com/rems-project/cn-tutorial +repo_name: rems-project/cn-tutorial +edit_uri: edit/main/docs theme: name: material features: @@ -47,6 +50,8 @@ theme: font: text: Roboto code: Roboto Mono + icon: + repo: fontawesome/brands/github plugins: - search From 397602b1595eef7dea2e8133bead813ec70e67d4 Mon Sep 17 00:00:00 2001 From: Chris Phifer Date: Wed, 9 Apr 2025 15:23:05 -0700 Subject: [PATCH 126/158] main.py: Apply some Python formatting. Courtesy of my editor's configuration (via the `ruff` formatter/linter). In particular: - Reduce the need for escaped characters in string literals through use of single-quote marks. - Adjust whitespace around functions and at the end of the file. These changes are compliant with the Python style guides (e.g. PEP 8). --- main.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index 35c059bb..01b7d4e8 100644 --- a/main.py +++ b/main.py @@ -5,11 +5,11 @@ def define_env(env): def common(mesg, color): "Format a TODO (common)" - return "[[" + mesg + "]]" + return '[[' + mesg + "]]" ################################################################# # These should be suppressed for readers that are not tutorial developers: - + @env.macro def todo(mesg): "Format a TODO" @@ -27,13 +27,12 @@ def later(mesg): def hidden(mesg): "Format a TODO that should not actually appear right now" return "" - + @env.macro def verifmarkername(): - return "(V)" + return '(V)' @env.macro def verifmarker(title): "format a title with a marker that it is a verification chapter" return verifmarkername() + " " + title - From 082534ff9a3a9ce804140d3d4db91a25d13c03eb Mon Sep 17 00:00:00 2001 From: Chris Phifer Date: Wed, 9 Apr 2025 15:54:43 -0700 Subject: [PATCH 127/158] main.py: Use an environment variable to conditionally include TODOs. main.py now checks whether or not an environment variable, TUTORIAL_TODOS, is present in the environment (for now, the value is unimportant; this could be changed to support e.g. different levels of commentary inclusion.) README.md also includes instructions on using this variable to include developer commentary when building/serving the HTML documentation. This ought to give us the desired behavior in CI "for free", as the default build now excludes the TODO commentary. --- README.md | 13 +++++++++++++ main.py | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0277baf4..45f41fee 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,16 @@ pip install mkdocs-material mkdocs-macros-plugin make ``` +If you are _developing_ tutorial documentation, you may wish to include +developer commentary in the generated output. +To do so, simply set the `TUTORIAL_TODOS` environment variable (the value is +unimportant, so the empty string will suffice): + +```bash +# Build the tutorial, including any developer comments +TUTORIAL_TODOS= make +``` + ### Hosting locally You can start a local server that automatically renders changes to the tutorial @@ -40,6 +50,9 @@ files. This is useful while editing the tutorial. make serve ``` +(You can set `TUTORIAL_TODOS` as above to include developer commentary in served +documentation, i.e. `TUTORIAL_TODOS= make serve`.) + View at: http://localhost:8000/ Install dependencies: [asciidoctor](https://asciidoctor.org/). diff --git a/main.py b/main.py index 01b7d4e8..d6079fe9 100644 --- a/main.py +++ b/main.py @@ -2,6 +2,9 @@ def define_env(env): """ This is the hook for the variables, macros and filters. """ + import os + + show_todos = "TUTORIAL_TODOS" in os.environ def common(mesg, color): "Format a TODO (common)" @@ -13,12 +16,12 @@ def common(mesg, color): @env.macro def todo(mesg): "Format a TODO" - return common(mesg, "red") + return common(mesg, "red") if show_todos else "" @env.macro def later(mesg): "Format a TODO for later" - return common(mesg, "lightgray") + return common(mesg, "lightgray") if show_todos else "" ################################################################# # These should always be displayed / hidden From 7d320a62346e6ff704f54cf5c3d982ab4d7a2635 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 9 Apr 2025 20:25:43 -0400 Subject: [PATCH 128/158] Fix up the new conditional display of comments-to-ourselves introduce `make servecomments` target tidy the Python code a bit --- Makefile | 3 +++ main.py | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6715068d..30980a62 100644 --- a/Makefile +++ b/Makefile @@ -212,6 +212,9 @@ serve: rebuild rebuild: exercises docs/exercises.zip mkdocs.yml $(shell find docs -type f) +servecomments: + TUTORIAL_TODOS= $(MAKE) serve + ############################################################################## # Misc diff --git a/main.py b/main.py index d6079fe9..8ce0e011 100644 --- a/main.py +++ b/main.py @@ -8,7 +8,10 @@ def define_env(env): def common(mesg, color): "Format a TODO (common)" - return '[[' + mesg + "]]" + if show_todos: + return '[[' + mesg + "]]" + else: + return "" ################################################################# # These should be suppressed for readers that are not tutorial developers: @@ -16,12 +19,12 @@ def common(mesg, color): @env.macro def todo(mesg): "Format a TODO" - return common(mesg, "red") if show_todos else "" + return common(mesg, "red") @env.macro def later(mesg): "Format a TODO for later" - return common(mesg, "lightgray") if show_todos else "" + return common(mesg, "lightgray") ################################################################# # These should always be displayed / hidden From 60082b70cb795bb24ef58aa13108741c0dc8fe5b Mon Sep 17 00:00:00 2001 From: Aditya Zutshi Date: Mon, 14 Apr 2025 18:57:19 -0700 Subject: [PATCH 129/158] Edited the first chapter to add context, ease transitions, improve layout and add todos. --- docs/getting-started/tutorials/first-taste.md | 184 +++++++++++++----- 1 file changed, 133 insertions(+), 51 deletions(-) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 5a4bf67a..62a9d8b1 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,12 +1,14 @@ # A First Taste of CN: Specification and Testing -This section introduces the most basic features of CN: a notation for -writing _specifications_ of C functions and a tool for _testing_ the -behavior of the code against those specifications. +This section introduces two most basic features of CN: + +1. A notation for writing _specifications_ of C functions, and +2. A tool for _testing_ the behavior of the code against those specifications. ## A First Specification -Suppose we are writing a function `min3`, which takes three `unsigned int` arguments. +Suppose we want to write a function `min3`, which takes three `unsigned int` arguments +and returns the smallest of the three. ```c title="exercises/min3/min3.partial.c" --8<-- @@ -14,9 +16,10 @@ exercises/min3/min3.partial.c --8<-- ``` -The desired behavior of `min3` is to return the smallest of the three -inputs. We expect, then, that the return value should be less -than or equal to `x` and to `y` and to `z`. More formally: +The desired behavior of `min3` is to return the smallest of the three inputs. +We expect, then, that the return value should be less than or equal to `x` and to `y` +and to `z`. Using CN specifications, we can state this formally and attach it directly +to the function using a special comment block `/*@ ... @*/`: ```c title="exercises/min3/min3.partial1.c" --8<-- @@ -24,11 +27,10 @@ exercises/min3/min3.partial1.c --8<-- ``` -In more detail... +Let’s break this down... -- Function specifications are written inside special `/*@ ... @*/` - comments, placed between the function argument list and the function - body. +- Function specifications are written inside a special comment block `/*@ ... @*/` + and placed between the function argument list and the function body. - The keyword `ensures` introduces the function's _postcondition_ -- that is, a logical statement that we expect should be true when the @@ -43,7 +45,14 @@ In more detail... - Each clause of the specification concludes with a semicolon. -Next, suppose we have implemented `min3` (a little incorrectly) as +{{ todo("AZ: Since these terms might be unfamiliar to a practicing software engineer, +it can be useful to explain more about pre- and post-conditions in an aside, or by +linking references to it. For example wiki references might be enough: +https://en.wikipedia.org/wiki/Precondition and +https://en.wikipedia.org/wiki/Postcondition") }} + +This gives us a clear, machine-checkable description of what the function is supposed to +do — not how it does it. Next, suppose we have implemented `min3` incorrectly as shown below. ```c title="exercises/min3/min3.broken.c" @@ -51,15 +60,40 @@ shown below. exercises/min3/min3.broken.c --8<-- ``` +This function contains a subtle bug: in the second case, where y is the smallest, +it accidentally returns x instead. From a quick glance, the code looks reasonable — it +has the right structure, and the mistake is subtle and can go uncaught. That’s where +specification-based testing becomes useful. ## Testing How can we find out whether our implementation satisfies our -specification? We can test it! +specification? We can test it! + +This is one of the big ideas behind CN: once you’ve written a specification, CN can +generate test inputs and check whether the implementation behaves correctly for those +inputs. + +For example, if the `min3` function ever returns a value that violates the specification +(like returning x when y is the smallest), the tool will find it and report it — giving +concrete test inputs that fail the test (by violating the specifications). +{{ todo("AZ: Might be useful to have names for the testing and verification tools.") }} + +Specification-based testing shifts the focus from writing tests manually, to letting the +specification drive the testing process. This not only catches bugs more effectively, +but also makes specifications an active part of the development workflow. -Running the command `cn test ` in a terminal will produce an output along -the following lines. To open a terminal inside VSCode (which will -ensure your paths are set up correctly, etc.), use `View > Terminal`. +### Running `cn test` + +To test the implementation, CN’s command-line tool can be invoked as `cn test `. +!!! tip + To open a terminal inside VSCode (which will ensure your paths are set up correctly, + etc.), use `View > Terminal`. + +{{ todo("AZ: The bit about VS Code appears abruptly. Is the user expected to use VS Code, +or this is more like a 'tip' in case the user is using VS Code. If its the former, then +this might be a place to talk about or link to details about VS Code integrations if there +are any. If it is the latter, then consider writing it as a 'tip'.") }} ``` $ cn test min3.broken.c @@ -89,27 +123,54 @@ CN reports that there seems to be an issue with our implementation. We'll return to that in a second, but first, let's explain what happened when we ran `cn test`. -The `cn test` command does _property-based random testing_. You may -instead be accustomed to input-output testing, where the developer -writes _unit tests_ that assert what the output of a function should -be on a given input. With property-based random testing, things are -much more automatic. First, instead of requiring the developer to -manually construct a suite of interesting test _inputs_, CN -automatically generates large number of random test inputs. Second, -instead of requiring the developer to manually calculate the expected -_output_ for each test input, CN uses the provided specification to -check whether the program's behavior is satisfactory. - -Here, `cn test` generates three integer inputs, runs `min3` on these -inputs, and checks that the output satisfies the postcondition. It -repeats this process until either some number (by default, 100) of -tests succeed or else a failing test, called a _counterexample_, is -encountered. In this case, the counterexample is printed out in -the form of a snippet of C code that will recreate the failure. - -(The counterexample you will see if you run the tests yourself will +#### Property-Based Testing vs Input-Output Testing + +You may be accustomed to input-output testing, where the developer writes _unit tests_ +that assert what the output of a function should be on a given input. +CN uses a different approach called _property-based random testing_. With +property-based random testing, things are much more automatic. CN works in two important +ways: + +1. First, instead of requiring the developer to manually construct a suite of interesting + test _inputs_, CN automatically generates a large number of random test inputs. +2. Second, instead of requiring the developer to manually calculate the expected _output_ + for each test input, CN uses the provided specification to check whether the program's + behavior is satisfactory. + +In other words, you tell CN what properties the function should satisfy (e.g., "the +result should be less than equal to x, y, and z"), and CN checks whether your +implementation always satisfies them. + +#### What Went Wrong? + +For our example, `cn test` generates three integer inputs, runs `min3` on these +inputs, and checks that the output satisfies the postcondition: +` + return <= x + && return <= y + && return <= z +`. +It repeats this process until either some number of +tests (by default, 100) succeed or else a failing test, called a _counterexample_, is +encountered. In the latter case, the counterexample is printed out as a snippet of +C code that will recreate the failure. + +Our run of `cn test min3.broken.c` found the counterexamples as +`x = 10`, `y = 2`, and `z = 14`. This is highlighted under failing input: +``` +********************** Failing input *********************** + +unsigned int x = (unsigned int)(10); +unsigned int y = (unsigned int)(2); +unsigned int z = (unsigned int)(14); +min3(x, y, z); + +************************************************************ +``` + +The counterexample you will see if you run the tests yourself will most likely be different, due to randomness, but the debugging logic -will be the same.) +will be the same. Given these inputs `x = 10`, `y = 2`, and `z = 14`, we expect the function to enter this branch: @@ -129,9 +190,12 @@ exercises/min3/min3.fixed.c --8<-- ``` -Now, if we run `cn test` again, the output should end with this message that the tests passed: +Now, if we run `cn test` again, the output should end with this message that the +tests passed: ``` +$ cn test min3.fixed.c + Testing min3::min3: 100 runs PASSED ``` @@ -140,7 +204,11 @@ Hooray! ### Exercises -_Exercise:_ The specification we wrote is +{{ todo("AZ: It might be useful number the exercises.")}} + +_Exercise:_ Improve the specification. + +The specification we wrote is a bit loose: It says the result value should be smaller than `x`, `y`, and `z`, but it does not say that it must be equal to one of these. For example, a function that always returns `0` would satisfy this @@ -150,6 +218,14 @@ specification. Improve it. _Exercise:_ Practice the workflow of specifying and testing the function `add`. +Try the CN workflow on a simple function that adds two numbers. + +```c title="exercises/add.partial.c" +--8<-- +exercises/add.partial.c +--8<-- +``` + - Write a specification with the postcondition that `add` should return the sum of its inputs. Remember that CN supports standard arithmetic and boolean operators such as `+` and `==`. @@ -159,15 +235,12 @@ _Exercise:_ Practice the workflow of specifying and testing the function `add`. will (incorrectly) succeed — i.e., such that `cn test` cannot find a counterexample after 100 tests? -```c title="exercises/add.partial.c" ---8<-- -exercises/add.partial.c ---8<-- -``` ## Specifications with Preconditions -Here's a silly way of writing a function that +Sometimes, a function is only meant to work under certain conditions. We can express +these assumptions using a precondition. +As an example, here's a silly way of writing a function that returns whatever number it is given as input: ```c title="exercises/id_by_div/id_by_div.broken.c" @@ -191,18 +264,23 @@ exercises/id_by_div/id_by_div.fixed.c --8<-- ``` +This updated specification says: _as long as x is even, the function must return x_. + A specification with both preconditions and postconditions says: if the preconditions hold at the point where the function is called, then the postconditions will hold when the function returns. -The other new piece of syntax here is the `u32` type annotations. In -CN specifications, numeric types need to be annotated explicitly, and -we use `u32` for `unsigned int`. Try removing the annotations to see -the error message that results. +!!! note + The other new piece of syntax here is the `u32` type annotations. In + CN specifications, numeric types need to be annotated explicitly, and + we use `u32` for `unsigned int`. Try removing the annotations to see + the error message that results. ### Exercises -_Exercise:_ Without changing the postcondition or implementation, fix +_Exercise:_ Fix a specification by adding a precondition. + +Without changing the postcondition or implementation, fix the specification in the following example by adding a precondition on the inputs `x` and `n`. Check that `cn test` succeeds. @@ -214,9 +292,13 @@ exercises/id_by_div/id_by_div_n.broken.c _Exercise_: Write a specification for this function that says the result is between the first argument and the second, but that does not reveal the precise -value of the result. (That is, the same specification should work for a -function that returns `p` or `(p+q)/2` instead of `q`.) +value of the result. That is, the same specification should work for a +function that returns `p` or `(p+q)/2` instead of `q`. + {{ later("JWS: 'between the first argument and the second' is a bit confusing because it doesn't imply to me that p <= q") }} + +{{ todo("AZ: Perhaps a hint can be added pointing the user to add p<=q in the assumptions as required?") }} + ```c title="exercises/between.c" --8<-- exercises/between.c From 5e7be079ecb6cb6ada755081dc956333ae340616 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Mon, 14 Apr 2025 23:04:30 -0400 Subject: [PATCH 130/158] make small changes to alloc --- docs/getting-started/tutorials/alloc.md | 11 +++++------ src/exercises/slf17_get_and_free.test.c | 6 +++--- src/exercises/slf_greater.test.c | 7 +++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index cef90806..8b7cbb3f 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -2,7 +2,7 @@ Our next topic is programs that use dynamically allocated heap memory. -## Malloc and free +## Malloc and Free Heap-using programs in CN can be written in almost exactly the same way as in vanilla C. The only difference is that, instead of calling @@ -19,7 +19,7 @@ exercises/cn_malloc.h --8<-- ``` -Using `cn_malloc` and `cn_free`, we can write higher-level programs +Using `cn_malloc` and `cn_free_sized`, we can write higher-level programs that manipulate the heap, as usual. ```c title="exercises/slf17_get_and_free.test.c" @@ -31,9 +31,8 @@ exercises/slf17_get_and_free.test.c ### Exercises -Write a specification for the following program that reveals _only_ -that it returns a pointer to a number that is greater than the number -pointed to by its argument. +_Exercise:_ Write a specification for the following program that returns a +pointer to a number that is the number pointed to by its argument `+ 1`. ```c title="exercises/slf_greater.test.c" --8<-- @@ -41,7 +40,7 @@ exercises/slf_greater.test.c --8<-- ``` -## W resources +## W Resources In low-level C code, it is sometimes useful to pass around memory that has been allocated but not yet initialized. CN provides an alternate diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c index 1c287e4e..63e61ffe 100644 --- a/src/exercises/slf17_get_and_free.test.c +++ b/src/exercises/slf17_get_and_free.test.c @@ -20,12 +20,12 @@ unsigned int get_and_free (unsigned int *p) return v; } -unsigned int tester() +unsigned int tester() /*@ requires true; ensures return == 42u32; @*/ { - unsigned int *p = malloc_and_set (42); - unsigned int v = get_and_free (p); + unsigned int *p = malloc_and_set(42); + unsigned int v = get_and_free(p); return v; } diff --git a/src/exercises/slf_greater.test.c b/src/exercises/slf_greater.test.c index fa34d72f..f8a60d00 100644 --- a/src/exercises/slf_greater.test.c +++ b/src/exercises/slf_greater.test.c @@ -1,13 +1,12 @@ #include "cn_malloc.h" -unsigned int *greater_abstract (unsigned int *p) +unsigned int *incr (unsigned int *p) /* --BEGIN-- */ /*@ requires take P = RW(p); - P < 4294967295u32; ensures take P_post = RW(p); - take R = RW(return); + take Q = RW(return); P == P_post; - P <= R; + Q == P + 1u32; @*/ /* --END-- */ { From 9554beee875c7135406a65cc2a4b9eaac371af78 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Tue, 15 Apr 2025 14:13:37 -0400 Subject: [PATCH 131/158] Polishing and comments on first-taste --- docs/getting-started/tutorials/first-taste.md | 79 ++++++++++++------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 62a9d8b1..205b81be 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,6 +1,6 @@ # A First Taste of CN: Specification and Testing -This section introduces two most basic features of CN: +This section introduces two of the most basic features of CN: 1. A notation for writing _specifications_ of C functions, and 2. A tool for _testing_ the behavior of the code against those specifications. @@ -17,8 +17,9 @@ exercises/min3/min3.partial.c ``` The desired behavior of `min3` is to return the smallest of the three inputs. -We expect, then, that the return value should be less than or equal to `x` and to `y` -and to `z`. Using CN specifications, we can state this formally and attach it directly +We expect, then, that the return value should be less than or equal to +each of`x`, `y`, and `z`. Using CN specifications, we can state this +formally and attach it directly to the function using a special comment block `/*@ ... @*/`: ```c title="exercises/min3/min3.partial1.c" @@ -29,8 +30,9 @@ exercises/min3/min3.partial1.c Let’s break this down... -- Function specifications are written inside a special comment block `/*@ ... @*/` - and placed between the function argument list and the function body. +- Function specifications are written inside a special comment block + `/*@ ... @*/` and placed between the function argument list and the + function body. - The keyword `ensures` introduces the function's _postcondition_ -- that is, a logical statement that we expect should be true when the @@ -50,9 +52,12 @@ it can be useful to explain more about pre- and post-conditions in an aside, or linking references to it. For example wiki references might be enough: https://en.wikipedia.org/wiki/Precondition and https://en.wikipedia.org/wiki/Postcondition") }} +{{ todo("BCP: Sure. We could also add a little more material here -- +e.g., another example or two focused just on thinking about pre- and +postconditions. But let's leave that for a later pass.") }} This gives us a clear, machine-checkable description of what the function is supposed to -do — not how it does it. Next, suppose we have implemented `min3` incorrectly as +do — not how it does it. Next, suppose we have implemented `min3` _incorrectly_ as shown below. ```c title="exercises/min3/min3.broken.c" @@ -60,9 +65,10 @@ shown below. exercises/min3/min3.broken.c --8<-- ``` -This function contains a subtle bug: in the second case, where y is the smallest, -it accidentally returns x instead. From a quick glance, the code looks reasonable — it -has the right structure, and the mistake is subtle and can go uncaught. That’s where +This function contains a subtle bug: in the second case, where `y` is the smallest, +it accidentally returns `x` instead. From a quick glance, the code looks reasonable — it +has the right structure — and the mistake is subtle and can go +uncaught. That’s where specification-based testing becomes useful. ## Testing @@ -75,13 +81,21 @@ generate test inputs and check whether the implementation behaves correctly for inputs. For example, if the `min3` function ever returns a value that violates the specification -(like returning x when y is the smallest), the tool will find it and report it — giving +(like returning `x` when `y` is the smallest), CN will notice and report it — giving concrete test inputs that fail the test (by violating the specifications). {{ todo("AZ: Might be useful to have names for the testing and verification tools.") }} +{{ todo("BCP: Maybe better not to emphasize the difference between +testing and verification modes -- i.e., just call it CN throughout...") }} Specification-based testing shifts the focus from writing tests manually, to letting the specification drive the testing process. This not only catches bugs more effectively, but also makes specifications an active part of the development workflow. +{{ todo("BCP: I slightly disagree with the framing here: +Specification-based testing can be used in different modes -- 'point +testing' in the style of standard unit testing (but using the +specification to judge whether the output for a given test is OK, +rather than the using predicting what the output should be) and +'specification-based random testing'. i.e., setandard PBT.") }} ### Running `cn test` @@ -94,6 +108,9 @@ To test the implementation, CN’s command-line tool can be invoked as `cn test or this is more like a 'tip' in case the user is using VS Code. If its the former, then this might be a place to talk about or link to details about VS Code integrations if there are any. If it is the latter, then consider writing it as a 'tip'.") }} +{{ todo("BCP: FOr VERSE, everyone will be using VSCode. +It's possible that people outside VERSE will have other ways, but this +should be presented as the default.") }} ``` $ cn test min3.broken.c @@ -130,6 +147,13 @@ that assert what the output of a function should be on a given input. CN uses a different approach called _property-based random testing_. With property-based random testing, things are much more automatic. CN works in two important ways: +{{ todo("BCP: Again, CN also supports 'specification-based unit +testing' (or whatever it should be called -- I'm sure we don't +actually want to call it that!). However, I don't think we want to +spend time here showing people how to do unit testing with CN -- that +should come later, IMO. Namely, it should be introduced as a tool to +use to increase test coverage and/or deal with situations where the +random testing is not doing a good enough job of finding bugs.") }} 1. First, instead of requiring the developer to manually construct a suite of interesting test _inputs_, CN automatically generates a large number of random test inputs. @@ -145,11 +169,11 @@ implementation always satisfies them. For our example, `cn test` generates three integer inputs, runs `min3` on these inputs, and checks that the output satisfies the postcondition: -` - return <= x +``` + return <= x && return <= y && return <= z -`. +``` It repeats this process until either some number of tests (by default, 100) succeed or else a failing test, called a _counterexample_, is encountered. In the latter case, the counterexample is printed out as a snippet of @@ -204,7 +228,9 @@ Hooray! ### Exercises -{{ todo("AZ: It might be useful number the exercises.")}} +{{ todo("AZ: It might be useful to number the exercises.")}} +{{ todo("BCP: Keeping the numbers consistent as we edit will be a big +pain in the neck!")}} _Exercise:_ Improve the specification. @@ -264,7 +290,7 @@ exercises/id_by_div/id_by_div.fixed.c --8<-- ``` -This updated specification says: _as long as x is even, the function must return x_. +This updated specification says: _as long as `x` is even, the function must return `x`_. A specification with both preconditions and postconditions says: if the preconditions hold at the point where the function is called, then the @@ -275,14 +301,14 @@ postconditions will hold when the function returns. CN specifications, numeric types need to be annotated explicitly, and we use `u32` for `unsigned int`. Try removing the annotations to see the error message that results. +{{ todo("BCP: Shouldn't every reader see this information?")}} ### Exercises -_Exercise:_ Fix a specification by adding a precondition. - -Without changing the postcondition or implementation, fix -the specification in the following example by adding a precondition on -the inputs `x` and `n`. Check that `cn test` succeeds. +_Exercise:_ Fix the specification in the following example by adding a +precondition on +the inputs `x` and `n` (don't change the postcondition or implementation). +Check that `cn test` succeeds. ```c title="exercises/id_by_div/id_by_div_n.broken.c" --8<-- @@ -290,14 +316,11 @@ exercises/id_by_div/id_by_div_n.broken.c --8<-- ``` -_Exercise_: Write a specification for this function that says the result is -between the first argument and the second, but that does not reveal the precise -value of the result. That is, the same specification should work for a -function that returns `p` or `(p+q)/2` instead of `q`. - -{{ later("JWS: 'between the first argument and the second' is a bit confusing because it doesn't imply to me that p <= q") }} - -{{ todo("AZ: Perhaps a hint can be added pointing the user to add p<=q in the assumptions as required?") }} +_Exercise_: Write a specification for the following function that says +the result is between arguments `p` and `q` (where `p` is less than or +equal to `q`), but that does not reveal the precise value of the +result. That is, the same specification should work for a +function that returns `p` or `(p+q)/2` instead of `q`. ```c title="exercises/between.c" --8<-- From 12d7cbfc35f22092f45537ebf72a187d7b554aa7 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Tue, 15 Apr 2025 15:09:22 -0400 Subject: [PATCH 132/158] `AUTHORS` and `CONTRIBUTORS` --- AUTHORS | 5 +++++ CONTRIBUTORS | 6 ++++++ docs/README.md | 6 ++---- main.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 AUTHORS create mode 100644 CONTRIBUTORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..630a8c34 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +# List of main authors of the CN tutorial +Christopher Pulte +Benjamin C. Pierce +Cole Schlesinger +Jessica Shi diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 00000000..70edbb5c --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,6 @@ +# List of contributors to the CN tutorial +Christopher Pulte +Benjamin C. Pierce +Cole Schlesinger +Jessica Shi +Elizabeth Austell diff --git a/docs/README.md b/docs/README.md index e095a6cc..288f5471 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,6 @@ # Welcome to CN -_These tutorials and docs were developed by Christopher Pulte, Benjamin C. -Pierce, and Cole Schlesinger, with contributions from Elizabeth Austell. +_These tutorials and docs were developed by {{ text_authors() }}._ CN is an extension of the C programming language for testing and verifying the correctness of C code, especially on low-level systems code. Compared to @@ -57,8 +56,7 @@ extended exercise due to Bryan Parno. ??? info "BibTeX citation" ``` @misc{cn-tutorial, - author = "Christopher Pulte and Benjamin C. Pierce and Cole - Schlesinger and Jessica Shi and Elizabeth Austell", + author = "{{ latex_authors() }}", title = "{CN Tutorial}", howpublished = "\url{https://rems-project.github.io/cn-tutorial/}", year = {2025}, diff --git a/main.py b/main.py index 8ce0e011..2fce88fc 100644 --- a/main.py +++ b/main.py @@ -42,3 +42,37 @@ def verifmarkername(): def verifmarker(title): "format a title with a marker that it is a verification chapter" return verifmarkername() + " " + title + + ################################################################# + # Authors and contributors + + authors_fn = os.path.join(env.project_dir, 'AUTHORS') + with open(authors_fn, 'r') as f: + lines = [l.strip() for l in f.readlines()] + authors = [l for l in lines if not l.startswith('#')] + + contributors_fn = os.path.join(env.project_dir, 'CONTRIBUTORS') + with open(contributors_fn, 'r') as f: + lines = [l.strip() for l in f.readlines()] + contributors = [l for l in lines if not l.startswith('#')] + + # Contributors, not authors + cna = [a for a in contributors if a not in authors] + + @env.macro + def latex_authors(): + # NOTE: Software Foundations does not include non-author contributors + # in its LaTeX citations. We might want to do the same, in which case + # one just has to delete `+ cna`. + return ' and '.join(authors + cna) + + @env.macro + def text_authors(): + if len(authors) == 1: + authors_list = authors[0] + else: + authors_list = ', '.join(authors[:-1]) + ', and ' + authors[-1] + + if len(cna) == 1: + cna_list = cna[0] + else: From 14aa941ff13bbf6a75f7dbe387f9104d4083b298 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Tue, 15 Apr 2025 16:43:28 -0400 Subject: [PATCH 133/158] Somehow missed the last lines --- main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.py b/main.py index 2fce88fc..4ae9c5eb 100644 --- a/main.py +++ b/main.py @@ -76,3 +76,6 @@ def text_authors(): if len(cna) == 1: cna_list = cna[0] else: + cna_list = ', '.join(cna[:-1]) + ', and ' + cna[-1] + + return f'{authors_list}, with contributions from {cna_list}' From f119d201443969999c3dc602aef8465186ce67cc Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Wed, 16 Apr 2025 02:46:32 -0400 Subject: [PATCH 134/158] fix typos in examples and move w resource section --- docs/getting-started/tutorials/alloc.md | 39 +---------------- docs/getting-started/tutorials/verif-alloc.md | 43 ++++++++++++++++++- src/exercises/slf17_get_and_free.test.c | 4 +- src/exercises/slf17_get_and_free.verif.c | 4 +- 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/docs/getting-started/tutorials/alloc.md b/docs/getting-started/tutorials/alloc.md index 8b7cbb3f..9da9b0a6 100644 --- a/docs/getting-started/tutorials/alloc.md +++ b/docs/getting-started/tutorials/alloc.md @@ -38,41 +38,4 @@ pointer to a number that is the number pointed to by its argument `+ 1`. --8<-- exercises/slf_greater.test.c --8<-- -``` - -## W Resources - -In low-level C code, it is sometimes useful to pass around memory that -has been allocated but not yet initialized. CN provides an alternate -form of resource, written `W`, to address this situation. Given a -C-type `T` and pointer `p`, `W(p)` asserts the same ownership as -`RW(p)`: ownership of a memory cell at `p` the size of type `T`. -However, but, in contrast to `RW`, `W` memory is not assumed to be -initialised. - -CN uses this distinction to prevent reads from uninitialised memory: - -- A read at C-type `T` and pointer `p` requires a resource - `RW(p)`, i.e., ownership of _initialised_ memory at the - right C-type. The load returns the `RW` resource unchanged. - -- A write at C-type `T` and pointer `p` needs only a - `W(p)` (so, unlike reads, writes to uninitialised memory - are fine). The write consumes ownership of the `W` resource - (it destroys it) and returns a new resource `RW(p)` with the - value written as the output. This means the resource returned from a - write records the fact that this memory cell is now initialised and - can be read from. - -Since `RW` carries the same ownership as `W`, just with the -additional information that the `RW` memory is initalised, a -resource `RW(p)` is "at least as good" as `W(p)` — -an `RW(p)` resource can be used whenever `W(p)` is -needed. For instance CN’s type checking of a write to `p` requires a -`W(p)`, but if an `RW(p)` resource is what is -available, this can be used just the same. This allows an -already-initialised memory cell to be over-written again. - -Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. - -{{ todo("BCP: An example and/or an exercise about the W resource would be nice!") }} +``` \ No newline at end of file diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md index 404a8bb3..3a4f047a 100644 --- a/docs/getting-started/tutorials/verif-alloc.md +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -1,5 +1,43 @@ # Allocating and Deallocating Memory, Verified + +## W Resources + +In low-level C code, it is sometimes useful to pass around memory that +has been allocated but not yet initialized. CN provides an alternate +form of resource, written `W`, to address this situation. Given a +C-type `T` and pointer `p`, `W(p)` asserts the same ownership as +`RW(p)`: ownership of a memory cell at `p` the size of type `T`. +However, but, in contrast to `RW`, `W` memory is not assumed to be +initialised. + +CN uses this distinction to prevent reads from uninitialised memory: + +- A read at C-type `T` and pointer `p` requires a resource + `RW(p)`, i.e., ownership of _initialised_ memory at the + right C-type. The load returns the `RW` resource unchanged. + +- A write at C-type `T` and pointer `p` needs only a + `W(p)` (so, unlike reads, writes to uninitialised memory + are fine). The write consumes ownership of the `W` resource + (it destroys it) and returns a new resource `RW(p)` with the + value written as the output. This means the resource returned from a + write records the fact that this memory cell is now initialised and + can be read from. + +Since `RW` carries the same ownership as `W`, just with the +additional information that the `RW` memory is initalised, a +resource `RW(p)` is "at least as good" as `W(p)` — +an `RW(p)` resource can be used whenever `W(p)` is +needed. For instance CN’s type checking of a write to `p` requires a +`W(p)`, but if an `RW(p)` resource is what is +available, this can be used just the same. This allows an +already-initialised memory cell to be over-written again. + +Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. + +{{ todo("BCP: An example and/or an exercise about the W resource would be nice!") }} + ## Verifying programs with malloc and free Verifying programs that allocate and deallocate heap memory is a bit @@ -12,8 +50,8 @@ standard `malloc` and `free`. However, at the moment, CN's verification machinery does not understand the types of the `malloc` and `free` functions, which are a bit tricky because they rely on a bit of polymorphism and a typecast -between `char*` -- the result type of `malloc` and argument type of -`free` -- and the actual type of the object being allocated or +between `char*` — the result type of `malloc` and argument type of +`free` — and the actual type of the object being allocated or deallocated. To work around this shortcoming, verifying programs with heap @@ -58,3 +96,4 @@ of their CN specifications. exercises/malloc_trusted.verif.c --8<-- ``` +{{ todo("JWS: Where is this file?") }} diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c index 63e61ffe..a5b4254e 100644 --- a/src/exercises/slf17_get_and_free.test.c +++ b/src/exercises/slf17_get_and_free.test.c @@ -1,7 +1,7 @@ #include "cn_malloc.h" unsigned int *malloc_and_set (unsigned int x) -/*@ ensures take P = RW(return); +/*@ ensures take P = RW(return); P == x; @*/ { @@ -11,7 +11,7 @@ unsigned int *malloc_and_set (unsigned int x) } unsigned int get_and_free (unsigned int *p) -/*@ requires take P = RW(p); +/*@ requires take P = RWunsigned int>(p); ensures return == P; @*/ { diff --git a/src/exercises/slf17_get_and_free.verif.c b/src/exercises/slf17_get_and_free.verif.c index 64589474..d7c190c8 100644 --- a/src/exercises/slf17_get_and_free.verif.c +++ b/src/exercises/slf17_get_and_free.verif.c @@ -1,8 +1,8 @@ #include "free.h" unsigned int get_and_free (unsigned int *p) -/*@ requires take P = RW(p); - ensures return == P; +/*@ requires take P = RW(p); + ensures return == P; @*/ { unsigned int v = *p; From 905a2e6e60c992361852ae878108ee8295ffb176 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Wed, 16 Apr 2025 12:03:52 -0400 Subject: [PATCH 135/158] Fix typo --- src/exercises/slf17_get_and_free.test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exercises/slf17_get_and_free.test.c b/src/exercises/slf17_get_and_free.test.c index a5b4254e..f82af0dc 100644 --- a/src/exercises/slf17_get_and_free.test.c +++ b/src/exercises/slf17_get_and_free.test.c @@ -11,7 +11,7 @@ unsigned int *malloc_and_set (unsigned int x) } unsigned int get_and_free (unsigned int *p) -/*@ requires take P = RWunsigned int>(p); +/*@ requires take P = RW(p); ensures return == P; @*/ { From 9f925880c18b5e1017d5ae0b66bc0678474ce139 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Wed, 16 Apr 2025 12:37:22 -0400 Subject: [PATCH 136/158] Update READMEs --- .../tutorials/overview-fulminate.md | 16 ++++++++-------- docs/getting-started/tutorials/overview-pbt.md | 7 ++++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/getting-started/tutorials/overview-fulminate.md b/docs/getting-started/tutorials/overview-fulminate.md index 30de92a7..26589f9c 100644 --- a/docs/getting-started/tutorials/overview-fulminate.md +++ b/docs/getting-started/tutorials/overview-fulminate.md @@ -18,9 +18,9 @@ cn instrument .c This will produce three files: -* `-exec.c`, the instrumented source -* `cn.h`, a header file containing various definitions and prototypes, including C struct definitions representing CN datatypes, structs and records, as well as function prototypes for the various translated top-level CN functions and predicates. -* `cn.c`, a file that includes `cn.h` and provides definitions for the aforementioned prototypes +* `.exec.c`, the instrumented source +* `.cn.h`, a header file containing various definitions and prototypes, including C struct definitions representing CN datatypes, structs and records, as well as function prototypes for the various translated top-level CN functions and predicates. +* `.cn.c`, a file that includes `.cn.h` and provides definitions for the aforementioned prototypes These are all produced in the directory the command was run from. Alternatively, one can provide an output directory for these three files (after creating the directory) using the `--output-dir` argument: @@ -34,13 +34,13 @@ The translation tool injects the executable precondition right before the source ### Compiling, linking and running executable CN specifications -To compile and link the output files described in the above section, and also to run these examples on some manually-produced concrete inputs (i.e. via a handwritten `main` function), one can run the following commands: +To compile and link the output files described in the above section, and also to run these examples on some manually-produced concrete inputs (i.e. via a handwritten `main` function), one can run the following command: ```bash -export CHECK_SCRIPT="$OPAM_SWITCH_PREFIX/lib/cn/runtime/libexec/cn-runtime-single-file.sh" -$CHECK_SCRIPT .c +cn instrument --run .c ``` -This runs the `cn-runtime-single-file.sh` script from the CN runtime library on `.c`, which generates the executable specification files, compiles and links these, and then runs the produced binary. This script is configurable with the `-n` option for disabling dynamic ownership checking and/or the `-q` option for running the script in quiet mode. This script can be found in `runtime/libcn/libexec` if you are interested in seeing the compile and link commands. +This generates the executable specification files, compiles and links these, and then runs the produced binary. -The compile command includes the `-g` flag for collecting debug information, which means gdb or lldb can be run on the produced binary for setting breakpoints, stepping in and out of functions in a given run, printing concrete variable values at specific points in the program run, etc. gdb can cause problems on Mac due to some certification-related issues, so for Mac users we recommend you use lldb. +The compile command includes the `-g` flag for collecting debug information, which means gdb or lldb can be run on the produced binary for setting breakpoints, stepping in and out of functions in a given run, printing concrete variable values at specific points in the program run, etc. +Problems can be caused by gdb on Mac due to some certification-related issues, so we recommend that Mac users use lldb. diff --git a/docs/getting-started/tutorials/overview-pbt.md b/docs/getting-started/tutorials/overview-pbt.md index 799bccad..ea7766d8 100644 --- a/docs/getting-started/tutorials/overview-pbt.md +++ b/docs/getting-started/tutorials/overview-pbt.md @@ -32,9 +32,10 @@ It calls the function with this input and uses [Fulminate](overview-fulminate.md #### Understanding errors -{{ todo("BCP: This is out of date:") }} -Currently, the tool does not print out counterexamples, but this is [planned](https://github.com/rems-project/cerberus/issues/841). -Until then, `tests.out` can be run with the `--trap` flag in a debugger. +By default, the tool will attempt to synthesize a C program which reproduces the failure. +However, due to non-determinism of `malloc`, if your code include complex relationships between pointer, we cannot guarantee it will consistently reproduce the failure. + +If the C program provided does not reproduce the failure, `tests.out` can be run with the `--trap` flag in a debugger. Since seeds are printed each time the tool runs, `--seed ` can be used to reproduce the test case. The debugger should automatically pause right before rerunning the failing test case. From 3758d1091b44e611d1723a416326989970bd1208 Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 18 Apr 2025 15:52:48 -0400 Subject: [PATCH 137/158] add w resource exercise --- docs/getting-started/tutorials/verif-alloc.md | 13 ++++++++++-- src/exercises/w_resources_ex.broken.c | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/exercises/w_resources_ex.broken.c diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md index 3a4f047a..583e6ed5 100644 --- a/docs/getting-started/tutorials/verif-alloc.md +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -36,7 +36,16 @@ already-initialised memory cell to be over-written again. Unlike `RW`, whose output is the pointee value, `W` has no meaningful output. -{{ todo("BCP: An example and/or an exercise about the W resource would be nice!") }} +### Exercises + +_Exercise:_ This specification is broken. (Run `cn verify` to see the error +message.) Fix the specification by fixing which kinds of resources are used. + +```c title="exercises/w_resources_ex.broken.c" +--8<-- +exercises/w_resources_ex.broken.c +--8<-- +``` ## Verifying programs with malloc and free @@ -44,7 +53,7 @@ Verifying programs that allocate and deallocate heap memory is a bit different from testing such programs, in two respects: On one hand, there is no need to link against the nonstandard -`cn_malloc` and `cn_free` functions: programs can just use the +`cn_malloc` and `cn_free_sized` functions: programs can just use the standard `malloc` and `free`. However, at the moment, CN's verification machinery does not diff --git a/src/exercises/w_resources_ex.broken.c b/src/exercises/w_resources_ex.broken.c new file mode 100644 index 00000000..3869aebe --- /dev/null +++ b/src/exercises/w_resources_ex.broken.c @@ -0,0 +1,21 @@ +#include "malloc.h" + +void do_nothing (unsigned int* p) +/*@ +requires take P = RW(p); +ensures take P_post = RW(p); +@*/ +{ +} + +unsigned int* create (unsigned int x) +/*@ +ensures take P = RW(return); + P == x; +@*/ +{ + unsigned int* p = malloc__unsigned_int(); + do_nothing(p); + *p = x; + return p; +} \ No newline at end of file From 5e54b34505f98e0bbfc35e59152b13cdec9419bc Mon Sep 17 00:00:00 2001 From: Jessica Shi Date: Fri, 18 Apr 2025 16:00:16 -0400 Subject: [PATCH 138/158] sentence case everywhere --- .../case-studies/doubly-linked-lists.md | 2 +- .../case-studies/imperative-queues.md | 2 +- .../case-studies/the-runway.md | 2 +- .../case-studies/verif-doubly-linked-lists.md | 2 +- .../case-studies/verif-imperative-queues.md | 2 +- .../case-studies/verif-the-runway.md | 2 +- docs/getting-started/tutorials/README.md | 34 +++++++++---------- docs/getting-started/tutorials/arrays.md | 8 ++--- docs/getting-started/tutorials/first-taste.md | 6 ++-- docs/getting-started/tutorials/pointers.md | 14 ++++---- docs/getting-started/tutorials/predicates.md | 2 +- docs/getting-started/tutorials/verif-alloc.md | 4 +-- .../getting-started/tutorials/verif-arrays.md | 2 +- .../tutorials/verif-external.md | 2 +- .../tutorials/verif-numeric.md | 4 +-- .../tutorials/verif-pointers.md | 6 ++-- docs/getting-started/tutorials/welcome.md | 6 ++-- mkdocs.yml | 12 +++---- 18 files changed, 56 insertions(+), 56 deletions(-) diff --git a/docs/getting-started/case-studies/doubly-linked-lists.md b/docs/getting-started/case-studies/doubly-linked-lists.md index 2f35691a..ed30c0fb 100644 --- a/docs/getting-started/case-studies/doubly-linked-lists.md +++ b/docs/getting-started/case-studies/doubly-linked-lists.md @@ -1,4 +1,4 @@ -# Doubly-linked Lists +# Doubly-linked lists {{ later("BCP: The rest of the tutorial (from here to the end) needs to be checked for consistency of naming and capitalization conventions. ") }} diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 37627190..640babd7 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -1,4 +1,4 @@ -# Imperative Queues +# Imperative queues {{ todo("BCP: Zain points out that the lemma in `push_lemma.h` might be wrong when `P.next` is `NULL`... To fix it, try taking ownership[ diff --git a/docs/getting-started/case-studies/the-runway.md b/docs/getting-started/case-studies/the-runway.md index eb2b6b0c..05996fc2 100644 --- a/docs/getting-started/case-studies/the-runway.md +++ b/docs/getting-started/case-studies/the-runway.md @@ -1,4 +1,4 @@ -# Airport Simulation +# Airport simulation {{ later("BCP: This case study is not as well polished as the others. It's useful because it's more like real-world C code than the diff --git a/docs/getting-started/case-studies/verif-doubly-linked-lists.md b/docs/getting-started/case-studies/verif-doubly-linked-lists.md index e59092b1..0c52d31f 100644 --- a/docs/getting-started/case-studies/verif-doubly-linked-lists.md +++ b/docs/getting-started/case-studies/verif-doubly-linked-lists.md @@ -1,4 +1,4 @@ -# Doubly-linked Lists, Verified +# Doubly-linked lists, verified Verifying the doubly-linked list operations requires a few extra annotations. diff --git a/docs/getting-started/case-studies/verif-imperative-queues.md b/docs/getting-started/case-studies/verif-imperative-queues.md index 8d231c5d..b944dee0 100644 --- a/docs/getting-started/case-studies/verif-imperative-queues.md +++ b/docs/getting-started/case-studies/verif-imperative-queues.md @@ -1,4 +1,4 @@ -# Imperative Queues, Verified +# Imperative queues, verified To verify the queue operations, we'll need to add some annotations, as usual. diff --git a/docs/getting-started/case-studies/verif-the-runway.md b/docs/getting-started/case-studies/verif-the-runway.md index ece995d2..35a1975a 100644 --- a/docs/getting-started/case-studies/verif-the-runway.md +++ b/docs/getting-started/case-studies/verif-the-runway.md @@ -1,4 +1,4 @@ -# Airport Simulation, Verified +# Airport simulation, verified _Exercise_: See if CN can verify the functions you wrote for the exercise in the testing version of this chapter. Fix them if not. diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 1e56847e..21d6a4ff 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -3,29 +3,29 @@ - [Welcome](welcome.md) ## A Tour of CN -- [A First Taste of CN: Specification and Testing](first-taste.md) -- [{{ verifmarker("A First Taste of Verification") }}](verif-basics.md) -- [Working with Pointers](pointers.md) -- [{{ verifmarker("Pointers to Structured Objects, Verified") }}](verif-pointers.md) -- [Arrays and Loops](arrays.md) -- [{{ verifmarker("Arrays and Loops, Verified") }}](verif-arrays.md) -- [Allocating and Deallocating Memory](alloc.md) -- [{{ verifmarker("Allocating and Deallocating Memory, Verified") }}](verif-alloc.md) -- [Defining Predicates](predicates.md) +- [A first taste of CN: specification and testing](first-taste.md) +- [{{ verifmarker("A first taste of verification") }}](verif-basics.md) +- [Working with pointers](pointers.md) +- [{{ verifmarker("Pointers to structured objects, verified") }}](verif-pointers.md) +- [Arrays and loops](arrays.md) +- [{{ verifmarker("Arrays and loops, verified") }}](verif-arrays.md) +- [Allocating and deallocating memory](alloc.md) +- [{{ verifmarker("Allocating and deallocating memory, verified") }}](verif-alloc.md) +- [Defining predicates](predicates.md) - [Lists](lists.md) -- [{{ verifmarker("Lists, Verified") }}](verif-lists.md) -- [{{ verifmarker("Case Analysis") }}](verif-splitcase.md) -- [{{ verifmarker("More on Numeric Types") }}](verif-numeric.md) -- [{{ verifmarker("Working with External Lemmas") }}](verif-external.md) +- [{{ verifmarker("Lists, verified") }}](verif-lists.md) +- [{{ verifmarker("Case analysis") }}](verif-splitcase.md) +- [{{ verifmarker("More on numeric types") }}](verif-numeric.md) +- [{{ verifmarker("Working with external lemmas") }}](verif-external.md) ## Case studies -- [Imperative Queues](../case-studies/imperative-queues.md) -- [{{ verifmarker("Imperative Queues, Verified") }}](../case-studies/verif-imperative-queues.md) +- [Imperative queues](../case-studies/imperative-queues.md) +- [{{ verifmarker("Imperative queues, verified") }}](../case-studies/verif-imperative-queues.md) - [Doubly-Linked Lists](../case-studies/doubly-linked-lists.md) -- [{{ verifmarker("Doubly-Linked Lists, Verified") }}](../case-studies/verif-doubly-linked-lists.md) +- [{{ verifmarker("Doubly-linked lists, verified") }}](../case-studies/verif-doubly-linked-lists.md) - [Airport simulation](../case-studies/the-runway.md) -- [{{ verifmarker("Airport Simulation, Verified") }}](../case-studies/verif-the-runway.md) +- [{{ verifmarker("Airport simulation, verified") }}](../case-studies/verif-the-runway.md) ## TODOs diff --git a/docs/getting-started/tutorials/arrays.md b/docs/getting-started/tutorials/arrays.md index c23c8192..73c4d8c2 100644 --- a/docs/getting-started/tutorials/arrays.md +++ b/docs/getting-started/tutorials/arrays.md @@ -1,4 +1,4 @@ -# Arrays and Loops +# Arrays and loops Another common datatype in C is arrays. Reasoning about memory ownership for arrays is more difficult than for the datatypes we have seen so far, for two reasons: (1) C allows the programmer to access arrays using _computed pointers_, and (2) the size of an array does not need to be known as a constant at compile time. @@ -31,7 +31,7 @@ In general, the syntax of `each` is as follows: each ( ; ) { } ``` -### First Array Example +### First array example Let’s see how this applies to a simple array-manipulating function. Function `read` takes three arguments: the base pointer `p` of an `unsigned int` array, the length `n` of the array, and an index `i` into the array; `read` then returns the value of the `i`-th array cell. @@ -48,7 +48,7 @@ The CN precondition requires On exit the array ownership is returned again. The postcondition also asserts that the return value of the function is indeed equal to the value of the array at index `i`. -### Writing to Arrays +### Writing to arrays Consider this next function `writei`, which sets the value of the `i`-th array cell to be `val`. @@ -80,7 +80,7 @@ exercises/array_swap.c --8<-- ``` -### Iterated Conditions +### Iterated conditions Suppose we are writing a function that returns the maximum value in an array. Informally, we would want a postcondition that asserts that the returned value is greater than or equal to _each_ value in the array. Formally, for an array `A` of length `n`, we use an _iterated condition_ to write diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 5a4bf67a..d4f7c863 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -1,10 +1,10 @@ -# A First Taste of CN: Specification and Testing +# A first taste of CN: specification and testing This section introduces the most basic features of CN: a notation for writing _specifications_ of C functions and a tool for _testing_ the behavior of the code against those specifications. -## A First Specification +## A first specification Suppose we are writing a function `min3`, which takes three `unsigned int` arguments. @@ -165,7 +165,7 @@ exercises/add.partial.c --8<-- ``` -## Specifications with Preconditions +## Specifications with preconditions Here's a silly way of writing a function that returns whatever number it is given as input: diff --git a/docs/getting-started/tutorials/pointers.md b/docs/getting-started/tutorials/pointers.md index fa063810..16584a87 100644 --- a/docs/getting-started/tutorials/pointers.md +++ b/docs/getting-started/tutorials/pointers.md @@ -1,4 +1,4 @@ -# Pointers and Simple Ownership +# Working with pointers So far we’ve only considered functions manipulating numeric values. Specifications become more interesting when _pointers_ are @@ -37,7 +37,7 @@ For the read `*p` to be safe, we need to know that the function has permission to access the memory pointed to by `p`. We next explain how to represent this permission. -## RW Resources +## RW resources Given a C-type `T` and pointer `p`, the resource `RW(p)` asserts _ownership_ of a memory region at location `p` of the size of the C type @@ -72,7 +72,7 @@ This specification can be read as follows: - the caller will receive back a resource `RW(p)` when `read` returns. -## Pointee Values +## Pointee values In addition to reasoning about memory accesed by pointers, we likely also want to reason about the actual values that the pointers point to. The `take P =` in @@ -134,7 +134,7 @@ and this incorrect implementation ``` should fail. -## Writing Through Pointers +## Writing through pointers We next have an example where data is written to a pointer. The function `incr` takes a pointer `p` and increments the value in the memory cell that it @@ -162,7 +162,7 @@ exercises/slf3_basic_inplace_double.c --8<-- ``` -## No Memory Leaks +## No memory leaks In the specifications we have written so far, functions that receive resources as part of their precondition also return this ownership in their postcondition. @@ -210,7 +210,7 @@ very undesirable. As a consequence, function specifications have to do precise bookkeeping of their resource footprint and, in particular, return any unused resources back to the caller. -## Disjoint Memory Regions +## Disjoint memory regions When functions manipulate multiple pointers, we can assert ownership of each one, just like before. But there is an additional twist: simultaneously owning @@ -240,7 +240,7 @@ exercises/slf8_basic_transfer.c --8<-- ``` -## Ownership of Structured Objects +## Ownership of structured objects So far, our examples have worked with just integers and pointers, but larger programs typically also manipulate compound values, often diff --git a/docs/getting-started/tutorials/predicates.md b/docs/getting-started/tutorials/predicates.md index 76ad9ed6..99564062 100644 --- a/docs/getting-started/tutorials/predicates.md +++ b/docs/getting-started/tutorials/predicates.md @@ -1,4 +1,4 @@ -# Defining Predicates +# Defining predicates {{ todo("BCP: The text becomes a bit sketchy from here on! But hopefully there's still enough structure here to make sense of the examples...") }} diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md index 583e6ed5..a1a731b9 100644 --- a/docs/getting-started/tutorials/verif-alloc.md +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -1,7 +1,7 @@ -# Allocating and Deallocating Memory, Verified +# Allocating and deallocating memory, verified -## W Resources +## W resources In low-level C code, it is sometimes useful to pass around memory that has been allocated but not yet initialized. CN provides an alternate diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 8bafc39b..45ba0ba9 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -1,4 +1,4 @@ -# Verifying Programs with Arrays and Loops +# Arrays and loops, verified Recall this specification for a simple function that reads from an array: diff --git a/docs/getting-started/tutorials/verif-external.md b/docs/getting-started/tutorials/verif-external.md index 5d6a8df2..91581457 100644 --- a/docs/getting-started/tutorials/verif-external.md +++ b/docs/getting-started/tutorials/verif-external.md @@ -1,4 +1,4 @@ -# Working with External Lemmas +# Working with external lemmas {{ later("BCP: This section should also show what the proof of the lemmas looks like on the Coq side! ") }} diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 09f1ca71..9a02cd31 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -1,4 +1,4 @@ -# More on Numeric Types (Verification) +# More on numeric types (verification) {{ todo("Section under construction...") }} @@ -12,7 +12,7 @@ So far, we have worked entirely with unsigned 32-bit integers. These are simpler to deal with than C's signed integers, which introduce the possibility of _undefined behavior_. -## Signed Arithmetic and Undefined Behavior +## Signed arithmetic and undefined behavior The simple arithmetic function `add` shown below takes `int` arguments `x` and `y` and returns their sum. diff --git a/docs/getting-started/tutorials/verif-pointers.md b/docs/getting-started/tutorials/verif-pointers.md index a7ca5606..11b40c20 100644 --- a/docs/getting-started/tutorials/verif-pointers.md +++ b/docs/getting-started/tutorials/verif-pointers.md @@ -1,4 +1,4 @@ -# Verification with Pointers to Structured Objects +# Pointers to structured objects, verified Verifying CN programs involving structured objects raises a number of new issues. @@ -18,7 +18,7 @@ exercises/init_point.c --8<-- ``` -As stated in its precondition, `init_point` receives ownership `RW(p)`. The `zero` function, however, works on `unsigned int` pointers and requires ownership `RW`, so CN cannot simply pass `init_point`'s struct ownership to `zero`. Instead, CN decomposes the `RW(p)` resource into two `RW` resources, one for each member pointer, and proves that the calls to `zero` with `&p->x` and `&p->y` are safe by supplying the respective `RW` resources. +As stated in its precondition, `init_point` receives ownership `RW(p)`. The `zero` function, however, works on `unsigned int` pointers and requires ownership `RW`, so CN cannot simply pass `init_point`'s struct ownership to `zero`. Instead, CN decomposes the `RW(p)` resource into two `RW` resources, one for each member pointer, and proves that the calls to `zero` with `&p->x` and `&p->y` are safe by supplying the respective `RW` resources. Later, the reverse happens. Since the postcondition of `init_point` requires ownership `RW(p)`, CN re-assembles the two `RW` resources (now both zero-initialised) back into a compound struct resource. The resulting pointee value `P_post` is a struct composed of the zeroed member values for `x` and `y`. @@ -65,7 +65,7 @@ The assignments to `p->x` and `p->y` update these member resources with new valu _Exercise:_ Insert CN `assert(false)` statements in different statement positions of `init_point` and check how the available resources evolve. _Exercise:_ Recreate the `transpose` function from before, now -using the `swap` function: write a specification for `swap` (as defined below) and verify the result in CN. +using the `swap` function: write a specification for `swap` (as defined below) and verify the result in CN. {{ todo("JWS: What exactly is it that they're supposed to do here? Seems like just copy-pasting the specification from above will work?") }} {{ todo("BCP: Maybe that's OK? Or maybe we can think of a more interesting variant...") }} {{ todo("CP: I tweaked the exercise so it includes (at least) giving a specification for `swap`; that's still an easy exercise and we could use more+more interesting ones, but maybe it's better than nothing, for now.") }} diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 17ee5cd8..96574d38 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -27,17 +27,17 @@ CN can be used in two distinct ways: The main thread of this tutorial is aimed at readers who want to get up to speed quickly with specifying and testing C programs using CN. Verification topics are covered in optional sections marked "{{ verifmarkername() }}". Most -readers — even readers whose +readers — even readers whose primary interest is verification — should skip these sections on a first reading and, if desired, come back to them on a second pass. -## Setup Instructions +## Setup instructions Before getting started, make sure you have a running installation of CN and a local copy of the source files for all the exercises and examples; these can be downloaded from [here](link:exercises.zip). -## Acknowledgment of Support and Disclaimer +## Acknowledgment of support and disclaimer This material is based upon work supported by the Air Force Research Laboratory (AFRL) and Defense Advanced Research Projects Agencies diff --git a/mkdocs.yml b/mkdocs.yml index 06149ff2..da60be0d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -109,12 +109,12 @@ nav: - Tutorial: - getting-started/tutorials/README.md - "Welcome": getting-started/tutorials/welcome.md - - "A First Taste of CN: Specification and Testing": getting-started/tutorials/first-taste.md - - "(V) A First Taste of Verification": getting-started/tutorials/verif-basics.md - - "Working with Pointers": getting-started/tutorials/pointers.md - - "(V) Pointers to Structured Objects, Verified": getting-started/tutorials/verif-pointers.md - - "Arrays and Loops": getting-started/tutorials/arrays.md - - "(V) Arrays and Loops, Verified": getting-started/tutorials/verif-arrays.md + - "A first taste of CN: specification and testing": getting-started/tutorials/first-taste.md + - "(V) A first taste of verification": getting-started/tutorials/verif-basics.md + - "Working with pointers": getting-started/tutorials/pointers.md + - "(V) Pointers to structured objects, verified": getting-started/tutorials/verif-pointers.md + - "Arrays and loops": getting-started/tutorials/arrays.md + - "(V) Arrays and loops, verified": getting-started/tutorials/verif-arrays.md # # - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md # # - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md From b0b8a1b7a599efcf017d59342b3d54b7603f4790 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Fri, 18 Apr 2025 15:19:09 -0400 Subject: [PATCH 139/158] Nest table of contents in sidebar --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index da60be0d..13e04d0d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -27,6 +27,7 @@ theme: - search.share - search.suggest - toc.follow + - toc.integrate language: en palette: - media: "(prefers-color-scheme)" From baf235545425c5d7d01b5517df254e267a5bcde7 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Fri, 18 Apr 2025 19:19:50 -0400 Subject: [PATCH 140/158] Start some advanced testing chapters --- docs/getting-started/tutorials/README.md | 8 +++ .../tutorials/test-distribs.md | 8 +++ .../getting-started/tutorials/unit-testing.md | 58 ++++++++++++++++--- 3 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 docs/getting-started/tutorials/test-distribs.md diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md index 21d6a4ff..d6809262 100644 --- a/docs/getting-started/tutorials/README.md +++ b/docs/getting-started/tutorials/README.md @@ -15,6 +15,14 @@ - [Lists](lists.md) - [{{ verifmarker("Lists, verified") }}](verif-lists.md) - [{{ verifmarker("Case analysis") }}](verif-splitcase.md) + +## More on Testing + +- [Unit testing](unit-testing.md) +- [Understanding and controlling test distributions](test-distribs.md) + +## More on Verification + - [{{ verifmarker("More on numeric types") }}](verif-numeric.md) - [{{ verifmarker("Working with external lemmas") }}](verif-external.md) diff --git a/docs/getting-started/tutorials/test-distribs.md b/docs/getting-started/tutorials/test-distribs.md new file mode 100644 index 00000000..0b32f253 --- /dev/null +++ b/docs/getting-started/tutorials/test-distribs.md @@ -0,0 +1,8 @@ +# Understanding and controlling test distributions + +TODO + +- `--coverage` +- Tyche? +- Using `assert` to skew distributions +- `--max-array-length`? diff --git a/docs/getting-started/tutorials/unit-testing.md b/docs/getting-started/tutorials/unit-testing.md index aa324fd3..5da4a752 100644 --- a/docs/getting-started/tutorials/unit-testing.md +++ b/docs/getting-started/tutorials/unit-testing.md @@ -1,18 +1,60 @@ -# Unit Testing (optional) +# Unit testing (optional) + + + +## Using unit testing with `cn test` + +While the automatic testing provided by `cn test` is great, +sometimes one might want to test specific inputs to a function. + +Two reasons would be regression testing and fixing flaky tests. + +### Regression testing + +Using the counterexample from [First Taste](./first-taste.md): + +```c +void test_min3() { + min3(10, 2, 14); +} +``` + +Running `cn test` will run `test_min3`. + +- an exercise to find a bug in a variant of min3 +- couple more (similar, optional) exercises -- instructions for running unit tests themselves - - an exercise to try it out on min3 - - an exercise to find a bug in a variant of min3 - - couple more (similar, optional) exercises +### Fixing flaky tests -TODO: Complete instructions for running Fulminate on the min3 example. +Due to `cn test` randomizing inputs, its possible that a failing input can be found on some runs, but not on others. -## Old fulminate insructions +```c +void capitalize(char *str) +/*@ + requires take StrP = Owned(str); + StrP >= 97u8 && StrP <= 122u8; + ensures take StrP_post = Owned(str); + StrP_post == StrP - 32u8; + +@*/ +{ + if(str != 0 && *str != 0 && *str >= 'a' && *str <= 'y') { + *str -= 0x20; + } +} +``` +- Run `cn test` multiple times +- Note how it passes sometimes +- `--print-seed` and `--seed` to reproduce? +- Tests that sometimes pass and sometimes fail are known as "flaky tests" +- We can make our tests less flaky by removing the randomness and making a unit test. + - Now we can be confident when re-running `cn test` that `'z'` is being included in our testing. + - Maybe include in main PBT pages to demonstrate how to handle flaky PBT. From cd5834a2d0f385d20529c2ff7ace0cc465a91afd Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 14:19:40 -0400 Subject: [PATCH 141/158] Thinking about unit testing --- .../getting-started/tutorials/unit-testing.md | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/getting-started/tutorials/unit-testing.md b/docs/getting-started/tutorials/unit-testing.md index 5da4a752..29b401fb 100644 --- a/docs/getting-started/tutorials/unit-testing.md +++ b/docs/getting-started/tutorials/unit-testing.md @@ -18,7 +18,16 @@ Two reasons would be regression testing and fixing flaky tests. ### Regression testing -Using the counterexample from [First Taste](./first-taste.md): +Consider the `min3` example from [First Taste](./first-taste.md). +Suppose we fix the bug, but want to prevent a later regression. + +We can define a new function that will test the previous counterexample: + +{{ todo("""ZKA: + I should add a compiler flag `__CN_TESTING`, which is true when running with `cn test`. + Then we can put unit tests like this inside an `#ifdef`. + Should also look into supporting user assertions (via a user-available library).""") +}} ```c void test_min3() { @@ -51,10 +60,13 @@ void capitalize(char *str) } ``` -- Run `cn test` multiple times -- Note how it passes sometimes -- `--print-seed` and `--seed` to reproduce? -- Tests that sometimes pass and sometimes fail are known as "flaky tests" -- We can make our tests less flaky by removing the randomness and making a unit test. - - Now we can be confident when re-running `cn test` that `'z'` is being included in our testing. - - Maybe include in main PBT pages to demonstrate how to handle flaky PBT. +1. Run `cn test` multiple times + 1. Note how it passes sometimes + 2. Tests that sometimes pass and sometimes fail are known as "flaky tests" + +2. `--print-seed` and `--seed` to reproduce? + 1. However, depends on the full testing workflow (functions under test, order tested) + 2. Could be better via per-input seeds... + +3. A more robust solution for making our tests less flaky would be to add a unit test. + 1. Now we can be confident that, when re-running `cn test`, `'z'` is being tested. From 0b381d1a2f1107953aaa754870a043d4c987d33c Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 14:42:18 -0400 Subject: [PATCH 142/158] Thinking about test distributions --- .../tutorials/test-distribs.md | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/tutorials/test-distribs.md b/docs/getting-started/tutorials/test-distribs.md index 0b32f253..6e6410be 100644 --- a/docs/getting-started/tutorials/test-distribs.md +++ b/docs/getting-started/tutorials/test-distribs.md @@ -1,8 +1,31 @@ # Understanding and controlling test distributions -TODO +Automatic test generation is powerful, +but it has its limits, +so it is important to understand how the tests are performing. + +We'll explore: + +- how to generate coverage reports +- get information about specific test inputs +- adjust the distribution of inputs + +## Coverage reports using `lcov` - `--coverage` -- Tyche? + - `lcov` reports + - Only line coverage + - For entire test run + +## Analytics with Tyche + +- Tyche + - Per test input information + - VSCode interface only? + +## Tweaking the distributions + - Using `assert` to skew distributions + {{ todo("Ideally, should support multiple specs, with some for testing only") }} + - Comparison to partition testing - `--max-array-length`? From a02e026e0e41f7a72628cb5ab4ce6f348b385de2 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 15:05:39 -0400 Subject: [PATCH 143/158] Already fixed the lemma --- docs/getting-started/case-studies/imperative-queues.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/getting-started/case-studies/imperative-queues.md b/docs/getting-started/case-studies/imperative-queues.md index 640babd7..bbebecc6 100644 --- a/docs/getting-started/case-studies/imperative-queues.md +++ b/docs/getting-started/case-studies/imperative-queues.md @@ -1,9 +1,5 @@ # Imperative queues -{{ todo("BCP: Zain points out that the lemma in `push_lemma.h` might -be wrong when `P.next` is `NULL`... To fix it, try taking ownership[ -of `p.next in both the pre- and the postcondition of the push lemma.")}} - A queue is a linked list with constant-time operations for adding things to one end (the "back") and removing them from the other (the "front"). Here are the C type definitions: From 3104569b3def5d89d1d470116475a7a5c3f13c7a Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 15:35:29 -0400 Subject: [PATCH 144/158] Navigation changes --- docs/README.md | 8 +- .../getting-started/tutorials/verif-basics.md | 2 +- docs/reference/README.md | 2 +- mkdocs.yml | 90 +++++++++++-------- 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/docs/README.md b/docs/README.md index 288f5471..995e37fd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,9 @@ +--- +hide: + - navigation + - toc +--- + # Welcome to CN _These tutorials and docs were developed by {{ text_authors() }}._ @@ -33,7 +39,7 @@ appreciated! Check out the tutorial to learn how to write, test, and verify your first spec - [:octicons-arrow-right-24: Tutorial](getting-started/tutorials/README.md) + [:octicons-arrow-right-24: Tutorial](getting-started/tutorials/welcome.md) - :material-scale-balance:{ .lg .middle } __Language reference__ diff --git a/docs/getting-started/tutorials/verif-basics.md b/docs/getting-started/tutorials/verif-basics.md index 8004aa7d..5e4430b0 100644 --- a/docs/getting-started/tutorials/verif-basics.md +++ b/docs/getting-started/tutorials/verif-basics.md @@ -1,4 +1,4 @@ -# CN Basics (with Verification) +# A first taste of verification ## Verifying `min3` diff --git a/docs/reference/README.md b/docs/reference/README.md index 2f2fefec..d13df56a 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -1,4 +1,4 @@ -# Reference +# Quick Reference A quick reference for CN keywords, symbols, and operations. diff --git a/mkdocs.yml b/mkdocs.yml index 13e04d0d..a527d55a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,12 +14,12 @@ theme: # - content.code.select - content.tooltips - navigation.footer - - navigation.indexes + # - navigation.indexes # - navigation.instant # - navigation.instant.prefetch # - navigation.instant.progress # - navigation.prune - - navigation.sections + # - navigation.sections - navigation.tabs - navigation.top - navigation.tracking @@ -104,46 +104,58 @@ markdown_extensions: # # Page tree nav: - - Getting Started: - - README.md - - Installation: getting-started/installation.md - - Tutorial: - - getting-started/tutorials/README.md - - "Welcome": getting-started/tutorials/welcome.md - - "A first taste of CN: specification and testing": getting-started/tutorials/first-taste.md - - "(V) A first taste of verification": getting-started/tutorials/verif-basics.md - - "Working with pointers": getting-started/tutorials/pointers.md - - "(V) Pointers to structured objects, verified": getting-started/tutorials/verif-pointers.md - - "Arrays and loops": getting-started/tutorials/arrays.md - - "(V) Arrays and loops, verified": getting-started/tutorials/verif-arrays.md + - Home: README.md -# # - "Defining predicates": getting-started/tutorials/verification/defining-predicates.md -# # - "Allocating and deallocating memory": getting-started/tutorials/verification/allocating-and-deallocating-memory.md -# # - "Lists": getting-started/tutorials/verification/lists.md -# # - "Working with external lemmas": getting-started/tutorials/verification/external-lemmas.md -# - "Case studies": -# - "Imperative queues": getting-started/case-studies/imperative-queues.md -# - "Doubly-linked lists": getting-started/case-studies/doubly-linked-lists.md -# - "Airport Simulation": getting-started/case-studies/the-runway.md -# - "Style guide": -# - getting-started/style-guide/README.md - - Specifications: + - Docs: + - Getting Started: + - getting-started/installation.md + + - A Tour of CN: + - getting-started/tutorials/welcome.md + - getting-started/tutorials/first-taste.md + - getting-started/tutorials/verif-basics.md + - getting-started/tutorials/pointers.md + - getting-started/tutorials/verif-pointers.md + - getting-started/tutorials/arrays.md + - getting-started/tutorials/verif-arrays.md + - getting-started/tutorials/alloc.md + - getting-started/tutorials/verif-alloc.md + - getting-started/tutorials/predicates.md + - getting-started/tutorials/verif-lists.md + - getting-started/tutorials/verif-splitcase.md + + - More on Testing: + - getting-started/tutorials/unit-testing.md + - getting-started/tutorials/test-distribs.md + + - More on Verification: + - getting-started/tutorials/verif-numeric.md + - getting-started/tutorials/verif-external.md + + - Case Studies: + - getting-started/case-studies/imperative-queues.md + - getting-started/case-studies/verif-imperative-queues.md + - getting-started/case-studies/doubly-linked-lists.md + - getting-started/case-studies/verif-doubly-linked-lists.md + - getting-started/case-studies/the-runway.md + - getting-started/case-studies/verif-the-runway.md + + - Reference: + - reference/README.md - specifications/README.md - - Function specifications: specifications/function-specifications.md - - Loop invariants: specifications/loop-invariants.md - - Conditions: specifications/conditions.md - - Expressions: specifications/expressions.md - - Resource predicates: specifications/resource-predicates.md + - specifications/function-specifications.md + - specifications/loop-invariants.md + - specifications/conditions.md + - specifications/expressions.md + - specifications/resource-predicates.md - Auxiliary definitions: - specifications/auxiliary-definitions/README.md - - Data structures: specifications/auxiliary-definitions/data-structures.md - - Logical functions: specifications/auxiliary-definitions/logical-functions.md - - Custom resource predicates: specifications/auxiliary-definitions/custom-resource-predicates.md - - Types: specifications/types.md - - Scoping: specifications/scoping.md - - "Tactics (proof hints)": specifications/tactics.md - - Interactive theorem proving: specifications/interactive-theorem-proving.md - - Reference: - - reference/README.md + - specifications/auxiliary-definitions/data-structures.md + - specifications/auxiliary-definitions/logical-functions.md + - specifications/auxiliary-definitions/custom-resource-predicates.md + - specifications/types.md + - specifications/scoping.md + - specifications/tactics.md + - specifications/interactive-theorem-proving.md From 7c8cb82b13085a22ac80aeac23fe50ddead34194 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 18:45:37 -0400 Subject: [PATCH 145/158] Tutorial README.md unused, structure in sidebar --- docs/getting-started/tutorials/README.md | 45 ------------------------ 1 file changed, 45 deletions(-) delete mode 100644 docs/getting-started/tutorials/README.md diff --git a/docs/getting-started/tutorials/README.md b/docs/getting-started/tutorials/README.md deleted file mode 100644 index d6809262..00000000 --- a/docs/getting-started/tutorials/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# CN Tutorial - -- [Welcome](welcome.md) - -## A Tour of CN -- [A first taste of CN: specification and testing](first-taste.md) -- [{{ verifmarker("A first taste of verification") }}](verif-basics.md) -- [Working with pointers](pointers.md) -- [{{ verifmarker("Pointers to structured objects, verified") }}](verif-pointers.md) -- [Arrays and loops](arrays.md) -- [{{ verifmarker("Arrays and loops, verified") }}](verif-arrays.md) -- [Allocating and deallocating memory](alloc.md) -- [{{ verifmarker("Allocating and deallocating memory, verified") }}](verif-alloc.md) -- [Defining predicates](predicates.md) -- [Lists](lists.md) -- [{{ verifmarker("Lists, verified") }}](verif-lists.md) -- [{{ verifmarker("Case analysis") }}](verif-splitcase.md) - -## More on Testing - -- [Unit testing](unit-testing.md) -- [Understanding and controlling test distributions](test-distribs.md) - -## More on Verification - -- [{{ verifmarker("More on numeric types") }}](verif-numeric.md) -- [{{ verifmarker("Working with external lemmas") }}](verif-external.md) - -## Case studies - -- [Imperative queues](../case-studies/imperative-queues.md) -- [{{ verifmarker("Imperative queues, verified") }}](../case-studies/verif-imperative-queues.md) -- [Doubly-Linked Lists](../case-studies/doubly-linked-lists.md) -- [{{ verifmarker("Doubly-linked lists, verified") }}](../case-studies/verif-doubly-linked-lists.md) -- [Airport simulation](../case-studies/the-runway.md) -- [{{ verifmarker("Airport simulation, verified") }}](../case-studies/verif-the-runway.md) - -## TODOs - -- [TODO list and discussion](todo.md) - - - - - From 25457b9841f4bef345dfab68ec003c14e07eafc7 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 18:46:28 -0400 Subject: [PATCH 146/158] Move `main.py` to `macros.py` --- docs/getting-started/tutorials/welcome.md | 2 +- main.py => macros.py | 9 --------- mkdocs.yml | 3 ++- 3 files changed, 3 insertions(+), 11 deletions(-) rename main.py => macros.py (89%) diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 96574d38..7d11b9fb 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -26,7 +26,7 @@ CN can be used in two distinct ways: The main thread of this tutorial is aimed at readers who want to get up to speed quickly with specifying and testing C programs using CN. Verification topics are -covered in optional sections marked "{{ verifmarkername() }}". Most +covered in optional sections whose names are italicized. Most readers — even readers whose primary interest is verification — should skip these sections on a first reading and, if desired, come back to them on a second pass. diff --git a/main.py b/macros.py similarity index 89% rename from main.py rename to macros.py index 4ae9c5eb..3ddd8334 100644 --- a/main.py +++ b/macros.py @@ -34,15 +34,6 @@ def hidden(mesg): "Format a TODO that should not actually appear right now" return "" - @env.macro - def verifmarkername(): - return '(V)' - - @env.macro - def verifmarker(title): - "format a title with a marker that it is a verification chapter" - return verifmarkername() + " " + title - ################################################################# # Authors and contributors diff --git a/mkdocs.yml b/mkdocs.yml index a527d55a..04f86dae 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,7 +56,8 @@ theme: plugins: - search - - macros + - macros: + module_name: macros # Extensions markdown_extensions: From 6084c725bfb1e2e99a902d8224480538508adba3 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 18:47:51 -0400 Subject: [PATCH 147/158] Mark pages with the "flow" they belong to Thinking being that there is a verification flow we want to mark. Didn't want to tie it to file name, that's a bit too magical for me. --- docs/getting-started/tutorials/verif-alloc.md | 4 ++++ docs/getting-started/tutorials/verif-arrays.md | 4 ++++ docs/getting-started/tutorials/verif-basics.md | 4 ++++ docs/getting-started/tutorials/verif-external.md | 4 ++++ docs/getting-started/tutorials/verif-lists.md | 4 ++++ docs/getting-started/tutorials/verif-numeric.md | 4 ++++ docs/getting-started/tutorials/verif-pointers.md | 4 ++++ docs/getting-started/tutorials/verif-splitcase.md | 4 ++++ 8 files changed, 32 insertions(+) diff --git a/docs/getting-started/tutorials/verif-alloc.md b/docs/getting-started/tutorials/verif-alloc.md index a1a731b9..16fbc0a2 100644 --- a/docs/getting-started/tutorials/verif-alloc.md +++ b/docs/getting-started/tutorials/verif-alloc.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # Allocating and deallocating memory, verified diff --git a/docs/getting-started/tutorials/verif-arrays.md b/docs/getting-started/tutorials/verif-arrays.md index 45ba0ba9..ac7e7de7 100644 --- a/docs/getting-started/tutorials/verif-arrays.md +++ b/docs/getting-started/tutorials/verif-arrays.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # Arrays and loops, verified Recall this specification for a simple function that reads from an array: diff --git a/docs/getting-started/tutorials/verif-basics.md b/docs/getting-started/tutorials/verif-basics.md index 5e4430b0..6cebf1fa 100644 --- a/docs/getting-started/tutorials/verif-basics.md +++ b/docs/getting-started/tutorials/verif-basics.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # A first taste of verification ## Verifying `min3` diff --git a/docs/getting-started/tutorials/verif-external.md b/docs/getting-started/tutorials/verif-external.md index 91581457..30a82911 100644 --- a/docs/getting-started/tutorials/verif-external.md +++ b/docs/getting-started/tutorials/verif-external.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # Working with external lemmas {{ later("BCP: This section should also show what the proof of the lemmas diff --git a/docs/getting-started/tutorials/verif-lists.md b/docs/getting-started/tutorials/verif-lists.md index 835ed681..d546d78d 100644 --- a/docs/getting-started/tutorials/verif-lists.md +++ b/docs/getting-started/tutorials/verif-lists.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # Lists, verified Now let's see what's needed to fully verify linked-list operations. diff --git a/docs/getting-started/tutorials/verif-numeric.md b/docs/getting-started/tutorials/verif-numeric.md index 9a02cd31..ee270dc5 100644 --- a/docs/getting-started/tutorials/verif-numeric.md +++ b/docs/getting-started/tutorials/verif-numeric.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # More on numeric types (verification) {{ todo("Section under construction...") }} diff --git a/docs/getting-started/tutorials/verif-pointers.md b/docs/getting-started/tutorials/verif-pointers.md index 11b40c20..ddd7cb39 100644 --- a/docs/getting-started/tutorials/verif-pointers.md +++ b/docs/getting-started/tutorials/verif-pointers.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # Pointers to structured objects, verified Verifying CN programs involving structured objects raises a number diff --git a/docs/getting-started/tutorials/verif-splitcase.md b/docs/getting-started/tutorials/verif-splitcase.md index 907d86c4..5c9a924c 100644 --- a/docs/getting-started/tutorials/verif-splitcase.md +++ b/docs/getting-started/tutorials/verif-splitcase.md @@ -1,3 +1,7 @@ +--- +flow: Verification +--- + # (Verification) Case Analysis {{ todo("This section is under construction...") }} From 927be3497031cacf790cd4bab9bd49e4327f6248 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Mon, 21 Apr 2025 18:49:05 -0400 Subject: [PATCH 148/158] Automatically italicize verification chapters --- hooks.py | 33 +++++++++++++++++++++++++++++++++ mkdocs.yml | 3 +++ 2 files changed, 36 insertions(+) create mode 100644 hooks.py diff --git a/hooks.py b/hooks.py new file mode 100644 index 00000000..877269a8 --- /dev/null +++ b/hooks.py @@ -0,0 +1,33 @@ +from mkdocs.structure.nav import Navigation +from mkdocs.structure.pages import Page +from mkdocs.utils.templates import TemplateContext + + +def on_page_markdown(markdown: str, page: Page, **kwargs) -> str | None: + if page.meta.get('flow') != 'Verification': + return markdown + + # Split the markdown into lines + lines = markdown.splitlines() + + # Replace the first line starting with '#' + for i, line in enumerate(lines): + line = line.lstrip() + if line.startswith('#'): + lines[i] = f'# *{line[1:].lstrip()}*' + break + + # Join the lines back into a single string + markdown = '\n'.join(lines) + + return markdown + + +def on_page_context(context: TemplateContext, **kwargs) -> TemplateContext | None: + nav: Navigation = context.get('nav') # type: ignore + + for page in nav.pages: + if page.meta.get('flow') == 'Verification': + page.title = f'{page.title}' + + return context diff --git a/mkdocs.yml b/mkdocs.yml index 04f86dae..2ec1848b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,6 +59,9 @@ plugins: - macros: module_name: macros +hooks: + - hooks.py + # Extensions markdown_extensions: - abbr From 1eb87627d68322e2a35cece93a3c4c6acbd0c5e2 Mon Sep 17 00:00:00 2001 From: Zain K Aamer Date: Tue, 22 Apr 2025 11:53:24 -0400 Subject: [PATCH 149/158] Nitpick --- docs/getting-started/tutorials/welcome.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/tutorials/welcome.md b/docs/getting-started/tutorials/welcome.md index 7d11b9fb..a245fedf 100644 --- a/docs/getting-started/tutorials/welcome.md +++ b/docs/getting-started/tutorials/welcome.md @@ -26,7 +26,7 @@ CN can be used in two distinct ways: The main thread of this tutorial is aimed at readers who want to get up to speed quickly with specifying and testing C programs using CN. Verification topics are -covered in optional sections whose names are italicized. Most +covered in optional sections whose names are _italicized_. Most readers — even readers whose primary interest is verification — should skip these sections on a first reading and, if desired, come back to them on a second pass. From fad549c1609c90690f8d5e186f4bdc951485f2a6 Mon Sep 17 00:00:00 2001 From: Cole Schlesinger Date: Tue, 22 Apr 2025 09:05:58 -0700 Subject: [PATCH 150/158] Patch from Gus to work around CI failure --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 30980a62..6eac1ff9 100644 --- a/Makefile +++ b/Makefile @@ -95,8 +95,9 @@ CONSISTENT=$(patsubst %, _temp/consistent/%, $(MD)) exercises: $(EXERCISES) $(SOLUTIONS) $(TESTED) $(VERIFIED) $(CONSISTENT) -CN=cn verify -CNTEST=cn test --output _temp --progress-level=function +CNWAR=--include $(MAKEFILE_DIR)/src/exercises/cn_wars.h +CN=cn verify $(CNWAR) +CNTEST=cn test --output _temp --progress-level=function $(CNWAR) # Control verbosity (run make with V= to show everything that's happening) V=@ @@ -177,7 +178,7 @@ WORKING_AUX=$(patsubst src/exercises/%, docs/solutions/%, $(WORKING)) ############################################################################## # Check that the examples all run correctly -CN_PATH?=cn verify +CN_PATH?=cn verify $(CNWAR) check-archive: @echo Check archive examples From bbc54db748c677c1bbc0d90b359fa4324712d7ff Mon Sep 17 00:00:00 2001 From: Aditya Zutshi Date: Tue, 22 Apr 2025 14:19:41 -0700 Subject: [PATCH 151/158] folded in feedback --- docs/getting-started/tutorials/first-taste.md | 63 ++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/docs/getting-started/tutorials/first-taste.md b/docs/getting-started/tutorials/first-taste.md index 205b81be..b789f96f 100644 --- a/docs/getting-started/tutorials/first-taste.md +++ b/docs/getting-started/tutorials/first-taste.md @@ -2,8 +2,8 @@ This section introduces two of the most basic features of CN: -1. A notation for writing _specifications_ of C functions, and -2. A tool for _testing_ the behavior of the code against those specifications. +- A notation for writing _specifications_ of C functions, and +- A tool for _testing_ the behavior of the code against those specifications. ## A First Specification @@ -47,12 +47,13 @@ Let’s break this down... - Each clause of the specification concludes with a semicolon. -{{ todo("AZ: Since these terms might be unfamiliar to a practicing software engineer, +{{ later("AZ: Since these terms might be unfamiliar to a practicing software engineer, it can be useful to explain more about pre- and post-conditions in an aside, or by linking references to it. For example wiki references might be enough: https://en.wikipedia.org/wiki/Precondition and https://en.wikipedia.org/wiki/Postcondition") }} -{{ todo("BCP: Sure. We could also add a little more material here -- + +{{ later("BCP: Sure. We could also add a little more material here -- e.g., another example or two focused just on thinking about pre- and postconditions. But let's leave that for a later pass.") }} @@ -83,19 +84,16 @@ inputs. For example, if the `min3` function ever returns a value that violates the specification (like returning `x` when `y` is the smallest), CN will notice and report it — giving concrete test inputs that fail the test (by violating the specifications). -{{ todo("AZ: Might be useful to have names for the testing and verification tools.") }} -{{ todo("BCP: Maybe better not to emphasize the difference between -testing and verification modes -- i.e., just call it CN throughout...") }} Specification-based testing shifts the focus from writing tests manually, to letting the -specification drive the testing process. This not only catches bugs more effectively, -but also makes specifications an active part of the development workflow. -{{ todo("BCP: I slightly disagree with the framing here: -Specification-based testing can be used in different modes -- 'point -testing' in the style of standard unit testing (but using the -specification to judge whether the output for a given test is OK, -rather than the using predicting what the output should be) and -'specification-based random testing'. i.e., setandard PBT.") }} +specification drive the testing process. This approach can be more effective at catching +bugs. Specification-based testing can be used in different modes: + +- _point testing_ similar to standard unit testing, but instead of predicting the + expected output, the specification is used to judge whether the result is correct. +- _specification-based random testing_ which is essentially standard property-based + testing (PBT). +{{ later("AZ: Perhaps expand on PBT or add a reference to PBT.") }} ### Running `cn test` @@ -104,13 +102,6 @@ To test the implementation, CN’s command-line tool can be invoked as `cn test To open a terminal inside VSCode (which will ensure your paths are set up correctly, etc.), use `View > Terminal`. -{{ todo("AZ: The bit about VS Code appears abruptly. Is the user expected to use VS Code, -or this is more like a 'tip' in case the user is using VS Code. If its the former, then -this might be a place to talk about or link to details about VS Code integrations if there -are any. If it is the latter, then consider writing it as a 'tip'.") }} -{{ todo("BCP: FOr VERSE, everyone will be using VSCode. -It's possible that people outside VERSE will have other ways, but this -should be presented as the default.") }} ``` $ cn test min3.broken.c @@ -140,13 +131,14 @@ CN reports that there seems to be an issue with our implementation. We'll return to that in a second, but first, let's explain what happened when we ran `cn test`. -#### Property-Based Testing vs Input-Output Testing +#### Property-Based Random Testing vs Input-Output Testing You may be accustomed to input-output testing, where the developer writes _unit tests_ that assert what the output of a function should be on a given input. -CN uses a different approach called _property-based random testing_. With -property-based random testing, things are much more automatic. CN works in two important -ways: +Though CN also supports a similar approach, here, CN uses a different approach called +_property-based random testing_. With property-based random testing, things are much more +automatic. CN works in two important ways: + {{ todo("BCP: Again, CN also supports 'specification-based unit testing' (or whatever it should be called -- I'm sure we don't actually want to call it that!). However, I don't think we want to @@ -155,6 +147,10 @@ should come later, IMO. Namely, it should be introduced as a tool to use to increase test coverage and/or deal with situations where the random testing is not doing a good enough job of finding bugs.") }} +{{ later("AZ: Modified the text above to highlight the 2 different approaches. + Need to address BCP's above comments about increasing test coverage.") }} + + 1. First, instead of requiring the developer to manually construct a suite of interesting test _inputs_, CN automatically generates a large number of random test inputs. 2. Second, instead of requiring the developer to manually calculate the expected _output_ @@ -228,10 +224,6 @@ Hooray! ### Exercises -{{ todo("AZ: It might be useful to number the exercises.")}} -{{ todo("BCP: Keeping the numbers consistent as we edit will be a big -pain in the neck!")}} - _Exercise:_ Improve the specification. The specification we wrote is @@ -296,12 +288,11 @@ A specification with both preconditions and postconditions says: if the preconditions hold at the point where the function is called, then the postconditions will hold when the function returns. -!!! note - The other new piece of syntax here is the `u32` type annotations. In - CN specifications, numeric types need to be annotated explicitly, and - we use `u32` for `unsigned int`. Try removing the annotations to see - the error message that results. -{{ todo("BCP: Shouldn't every reader see this information?")}} + +The other new piece of syntax here is the `u32` type annotations. In +CN specifications, numeric types need to be annotated explicitly, and +we use `u32` for `unsigned int`. Try removing the annotations to see +the error message that results. ### Exercises From d99f450479c9eea26c81dcbf2c563d07f2509308 Mon Sep 17 00:00:00 2001 From: Gus O'Hanley Date: Fri, 18 Apr 2025 14:39:30 -0500 Subject: [PATCH 152/158] Add a workaround file for unsupported C constructs --- src/exercises/cn_wars.h | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/exercises/cn_wars.h diff --git a/src/exercises/cn_wars.h b/src/exercises/cn_wars.h new file mode 100644 index 00000000..ab0d0756 --- /dev/null +++ b/src/exercises/cn_wars.h @@ -0,0 +1,6 @@ +#ifndef CN_WARS_H_ +#define CN_WARS_H_ + +#define __attribute__(...) + +#endif // CN_WARS_H_ From 730d22643f7ea89031b16d56589f043c949ee5b4 Mon Sep 17 00:00:00 2001 From: Gus O'Hanley Date: Tue, 22 Apr 2025 15:23:39 -0500 Subject: [PATCH 153/158] Do not put newlines into perl command --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 6eac1ff9..db078cbe 100644 --- a/Makefile +++ b/Makefile @@ -191,11 +191,11 @@ check: exercises check-archive _temp/consistent/% : % $(V)perl -0777 -ne \ - 'while (/c title=\"(.+)\"\n.+\n(.+)\n/g) { \ - if ($$1 ne $$2) { \ - print "Bad .md file ($<): $$1 does not match $$2\n"; \ - exit 1; \ - } }' \ + 'while (/c title=\"(.+)\"\n.+\n(.+)\n/g) {' \ + -e 'if ($$1 ne $$2) {' \ + -e 'print "Bad .md file ($<): $$1 does not match $$2\n";' \ + -e 'exit 1;' \ + -e '} }' \ $< $(V)-mkdir -p $(dir $@) $(V)touch $@ From 485a5a099fd2955a8e35241a01c91dd8706151b6 Mon Sep 17 00:00:00 2001 From: Gus O'Hanley Date: Tue, 22 Apr 2025 16:10:44 -0500 Subject: [PATCH 154/158] CI: install mkdocs-macros-plugin --- .github/workflows/test-tutorial-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-tutorial-build.yml b/.github/workflows/test-tutorial-build.yml index 34b1e90e..248125b7 100644 --- a/.github/workflows/test-tutorial-build.yml +++ b/.github/workflows/test-tutorial-build.yml @@ -76,7 +76,7 @@ jobs: python-version: 3.x - name: Install Material for MkDocs - run: pip install mkdocs-material + run: pip install mkdocs-material mkdocs-macros-plugin - name: Clean the build directory run: | From 592463ae818dc8c049634ac06820d4f1b9b175cf Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Wed, 23 Apr 2025 13:55:59 -0400 Subject: [PATCH 155/158] Remove (correctly) failing broken file from Makefile --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index db078cbe..d0bcf9eb 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,6 @@ TESTED = $(patsubst src/exercises/%, _temp/tested/%, $(TESTONLY)) \ _temp/tested/init_point.c \ _temp/tested/min3/min3.fixed.c \ _temp/tested/min3/min3.partial.c \ - _temp/tested/min3/min3.partial1.c \ _temp/tested/id_by_div/id_by_div.fixed.c \ _temp/tested/slf2_basic_quadruple.c \ _temp/tested/swap.c \ @@ -97,7 +96,7 @@ exercises: $(EXERCISES) $(SOLUTIONS) $(TESTED) $(VERIFIED) $(CONSISTENT) CNWAR=--include $(MAKEFILE_DIR)/src/exercises/cn_wars.h CN=cn verify $(CNWAR) -CNTEST=cn test --output _temp --progress-level=function $(CNWAR) +CNTEST=cn test --output-dir _temp --progress-level=function $(CNWAR) # Control verbosity (run make with V= to show everything that's happening) V=@ From 9d8b9fb1bb437a454081b2b06853bc4d214d626c Mon Sep 17 00:00:00 2001 From: "August Schwerdfeger (Galois)" Date: Wed, 23 Apr 2025 14:41:48 -0500 Subject: [PATCH 156/158] Added sections for 'lcov' and Tyche. (#132) * Added sections for 'lcov' and Tyche. * Forgot to 'git add' the images. * Clarified sentence on line-by-line data. --- .../tutorials/images/lcov-screenshot-1.png | Bin 0 -> 178608 bytes .../tutorials/images/lcov-screenshot-2.png | Bin 0 -> 575159 bytes .../tutorials/images/tyche-screenshot.png | Bin 0 -> 171290 bytes .../tutorials/test-distribs.md | 27 +++++++++++++----- 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 docs/getting-started/tutorials/images/lcov-screenshot-1.png create mode 100644 docs/getting-started/tutorials/images/lcov-screenshot-2.png create mode 100644 docs/getting-started/tutorials/images/tyche-screenshot.png diff --git a/docs/getting-started/tutorials/images/lcov-screenshot-1.png b/docs/getting-started/tutorials/images/lcov-screenshot-1.png new file mode 100644 index 0000000000000000000000000000000000000000..36da1783a24b358d4389909568c8a5f6a4b20cbe GIT binary patch literal 178608 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%0A-P0u&V?%56lU_A?9 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

    bTDkQLCC{4z`<8oQ- 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%0DZ7 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

    P`$PtgcFD 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�BoJ=3KIk_%pe$U#!D*oQuEP0*fX+7C|d2NoG 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Νx}CX)9XzW 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

    ;SUT9?D|LJI3|bcEcFvO`=^us!qGlc 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 P6i$@FCyCY@*__W-E&%K%mXod@CK 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 Date: Thu, 24 Apr 2025 06:55:30 -0400 Subject: [PATCH 157/158] Dev container --- .devcontainer/devcontainer.json | 15 +++++++++++++++ Dockerfile | 13 +++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 Dockerfile diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..640dd591 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +{ + "name": "Existing Dockerfile", + "build": { + "context": "..", + "dockerfile": "../Dockerfile" + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "ms-vscode.cpptools" + ] + } + } +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..7a648611 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM ghcr.io/rems-project/cn:release + +RUN apt-get install -y software-properties-common zip && \ + add-apt-repository ppa:deadsnakes/ppa && \ + apt-get install -y python3.13-full && \ + ln -s /usr/bin/python3.13 /usr/bin/python + +RUN python -m ensurepip && \ + python -m pip install mkdocs-material mkdocs-macros-plugin + +# ZKA: IMO, this should be done in the CN image itself... +RUN echo >> ~/.bashrc && echo >> ~/.bashrc && \ + echo "test -r /root/.opam/opam-init/init.sh && . /root/.opam/opam-init/init.sh > /dev/null 2> /dev/null || true" >> ~/.bashrc From 2ecc1def757dd84a2956d816e04e3e3b155b7fe7 Mon Sep 17 00:00:00 2001 From: Benjamin Pierce Date: Thu, 24 Apr 2025 11:14:09 -0400 Subject: [PATCH 158/158] Roll back (trivial) Python 3.10 dependencies --- hooks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hooks.py b/hooks.py index 877269a8..76c5b2b6 100644 --- a/hooks.py +++ b/hooks.py @@ -1,9 +1,9 @@ from mkdocs.structure.nav import Navigation from mkdocs.structure.pages import Page +from typing import Union from mkdocs.utils.templates import TemplateContext - -def on_page_markdown(markdown: str, page: Page, **kwargs) -> str | None: +def on_page_markdown(markdown: str, page: Page, **kwargs) -> Union [str, None]: if page.meta.get('flow') != 'Verification': return markdown @@ -23,7 +23,7 @@ def on_page_markdown(markdown: str, page: Page, **kwargs) -> str | None: return markdown -def on_page_context(context: TemplateContext, **kwargs) -> TemplateContext | None: +def on_page_context(context: TemplateContext, **kwargs) -> Union [TemplateContext, None]: nav: Navigation = context.get('nav') # type: ignore for page in nav.pages:

    LP9zL6js@2_aw?%~q2ZQL^J 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 literal 0 HcmV?d00001 diff --git a/docs/getting-started/tutorials/images/lcov-screenshot-2.png b/docs/getting-started/tutorials/images/lcov-screenshot-2.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff6496fb0fd486f120ef74384ba71bc943889d0 GIT binary patch literal 575159 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ⅅIm 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 z⁡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 z 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