Skip to content

Commit eeb1139

Browse files
Petr BauchPetr Bauch
Petr Bauch
authored and
Petr Bauch
committed
Add cprover manual entry
Covering memory-snapshot harness, but not the memory analyzer.
1 parent 8bd9f4c commit eeb1139

File tree

1 file changed

+96
-2
lines changed

1 file changed

+96
-2
lines changed

doc/cprover-manual/goto-harness.md

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ having to manually construct an appropriate environment.
1313

1414
We have two types of harnesses we can generate for now:
1515

16-
* The `memory-snapshot` harness. TODO: Daniel can document this.
1716
* The `function-call` harness, which automatically synthesises an environment
1817
without having any information about the program state.
18+
* The `memory-snapshot` harness, which loads an existing program state (in form
19+
of a JSON file) and selectively _havoc-ing_ some variables.
1920

2021
It is used similarly to how `goto-instrument` is used by modifying an existing
2122
GOTO binary, as produced by `goto-cc`.
@@ -309,4 +310,97 @@ main.c function function
309310

310311
** 0 of 1 failed (1 iterations)
311312
VERIFICATION SUCCESSFUL
312-
```
313+
```
314+
315+
### The memory snapshot harness
316+
317+
The `function-call` harness is used in situations when we want the analysed
318+
function to work in arbitrary environment. If we want a more restricted
319+
environment or if we have the program in which our function will only be called,
320+
we call the `memory-snapshot` harness instead.
321+
322+
Furthermore, the program state of interest may be taken a particular location
323+
within a function. In that case we do not want the harness to instrument the
324+
whole function but rather to allow starting the execution from a specific
325+
initial location (specified via `--initial-location func[:<n>]`).
326+
327+
Say we want to check the assertion in the following code:
328+
329+
```C
330+
// main.c
331+
#include <assert.h>
332+
333+
unsigned int x;
334+
unsigned int y;
335+
336+
unsigned int nondet_int() {
337+
unsigned int z;
338+
return z;
339+
}
340+
341+
void checkpoint() {}
342+
343+
unsigned int complex_function_which_returns_one() {
344+
unsigned int i = 0;
345+
while(++i < 1000001) {
346+
if(nondet_int() && ((i & 1) == 1))
347+
break;
348+
}
349+
return i & 1;
350+
}
351+
352+
void fill_array(unsigned int* arr, unsigned int size) {
353+
for (unsigned int i = 0; i < size; i++)
354+
arr[i]=nondet_int();
355+
}
356+
357+
unsigned int array_sum(unsigned int* arr, unsigned int size) {
358+
unsigned int sum = 0;
359+
for (unsigned int i = 0; i < size; i++)
360+
sum += arr[i];
361+
return sum;
362+
}
363+
364+
const unsigned int array_size = 100000;
365+
366+
int main() {
367+
x = complex_function_which_returns_one();
368+
unsigned int large_array[array_size];
369+
fill_array(large_array, array_size);
370+
y = array_sum(large_array, array_size);
371+
checkpoint();
372+
assert(y + 2 > x);
373+
return 0;
374+
}
375+
```
376+
377+
But are not particularly interested in the analysing the complex function, since
378+
we trust that its implementation is correct. Hence we run the above program
379+
stopping after the assignments to `x` and `x` and storing the program state,
380+
e.g. using the `memory-analyzer`, in a JSON file `snapshot.json`. Then run the
381+
harness and verify the assertion with:
382+
383+
```
384+
$ goto-cc -o main.gb main.c
385+
$ goto-harness \
386+
--harness-function-name harness \
387+
--harness-type initialise-with-memory-snapshot \
388+
--memory-snapshot snapshot.json \
389+
--initial-location checkpoint \
390+
--havoc-variables x \
391+
main.gb main-mod.gb
392+
$ cbmc --function harness main-mod.gb
393+
```
394+
395+
This will result in:
396+
397+
```
398+
[...]
399+
400+
** Results:
401+
main.c function main
402+
[main.assertion.1] line 42 assertion y + 2 > x: SUCCESS
403+
404+
** 0 of 1 failed (1 iterations)
405+
VERIFICATION SUCCESSFUL
406+
```

0 commit comments

Comments
 (0)