Skip to content

Memory snapshot harness havoc #4351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 102 additions & 2 deletions doc/cprover-manual/goto-harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ having to manually construct an appropriate environment.

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

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

It is used similarly to how `goto-instrument` is used by modifying an existing
GOTO binary, as produced by `goto-cc`.
Expand Down Expand Up @@ -309,4 +310,103 @@ main.c function function

** 0 of 1 failed (1 iterations)
VERIFICATION SUCCESSFUL
```
```

### The memory snapshot harness

The `function-call` harness is used in situations in which we want the analysed
function to work in arbitrary environment. If we want to analyse a function
starting from a _real_ program state, we can call the `memory-snapshot` harness
instead.

Furthermore, the program state of interest may be taken at a particular location
within a function. In that case we do not want the harness to instrument the
whole function but rather to allow starting the execution from a specific
initial location (specified via `--initial-location func[:<n>]`). Note that the
initial location does not have to be the first instruction of a function: we can
also specify the _location number_ `n` to set the initial location inside our
function. The _location numbers_ do not have to coincide with the lines of the
program code. To find the _location number_ run CBMC with
`--show-goto-functions`. Most commonly, the _location number_ is the instruction
of the break-point used to extract the program state for the memory snapshot.

Say we want to check the assertion in the following code:

```C
// main.c
#include <assert.h>

unsigned int x;
unsigned int y;

unsigned int nondet_int() {
unsigned int z;
return z;
}

void checkpoint() {}

unsigned int complex_function_which_returns_one() {
unsigned int i = 0;
while(++i < 1000001) {
if(nondet_int() && ((i & 1) == 1))
break;
}
return i & 1;
}

void fill_array(unsigned int* arr, unsigned int size) {
for (unsigned int i = 0; i < size; i++)
arr[i]=nondet_int();
}

unsigned int array_sum(unsigned int* arr, unsigned int size) {
unsigned int sum = 0;
for (unsigned int i = 0; i < size; i++)
sum += arr[i];
return sum;
}

const unsigned int array_size = 100000;

int main() {
x = complex_function_which_returns_one();
unsigned int large_array[array_size];
fill_array(large_array, array_size);
y = array_sum(large_array, array_size);
checkpoint();
assert(y + 2 > x);
return 0;
}
```

But are not particularly interested in analysing the complex function, since we
trust that its implementation is correct. Hence we run the above program
stopping after the assignments to `x` and `x` and storing the program state,
e.g. using the `memory-analyzer`, in a JSON file `snapshot.json`. Then run the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any documentation for the memory-analyzer? I recall seeing some around, but I can't seem to be able to find it now? If we don't, would it be a good idea to write some separate documentation for that as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xbauch#3 I intent to make it part of #4261 once review-able.

harness and verify the assertion with:

```
$ goto-cc -o main.gb main.c
$ goto-harness \
--harness-function-name harness \
--harness-type initialise-with-memory-snapshot \
--memory-snapshot snapshot.json \
--initial-location checkpoint \
--havoc-variables x \
main.gb main-mod.gb
$ cbmc --function harness main-mod.gb
```

This will result in:

```
[...]

** Results:
main.c function main
[main.assertion.1] line 42 assertion y + 2 > x: SUCCESS

** 0 of 1 failed (1 iterations)
VERIFICATION SUCCESSFUL
```
8 changes: 8 additions & 0 deletions regression/goto-harness/havoc-global-int-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
int x = 1;

int main()
{
assert(x == 1);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what exactly is this test testing? Presumably this assertion would still fail if the snapshot harness didn't work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified.


return 0;
}
8 changes: 8 additions & 0 deletions regression/goto-harness/havoc-global-int-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c
--harness-type initialise-with-memory-snapshot --memory-snapshot ../load-snapshot-json-snapshots/global-int-x-1-snapshot.json --initial-location main:0 --havoc-variables x
^EXIT=10$
^SIGNAL=0$
\[main.assertion.1\] line [0-9]+ assertion x == 1: FAILURE
--
^warning: ignoring
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be helpful to document how the JSON snapshots were generated. There will be a day where we need to change them in some way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That documentation was intended to be a part of #4261 (as we used the memory-analyzer to generate the JSON). Do you think it should be documented here as well?

53 changes: 53 additions & 0 deletions regression/goto-harness/havoc-global-int-02/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <assert.h>

unsigned int x;
unsigned int y;

unsigned int nondet_int()
{
unsigned int z;
return z;
}

void checkpoint()
{
}

unsigned int complex_function_which_returns_one()
{
unsigned int i = 0;
while(++i < 1000001)
{
if(nondet_int() && ((i & 1) == 1))
break;
}
return i & 1;
}

void fill_array(unsigned int *arr, unsigned int size)
{
for(unsigned int i = 0; i < size; i++)
arr[i] = nondet_int();
}

unsigned int array_sum(unsigned int *arr, unsigned int size)
{
unsigned int sum = 0;
for(unsigned int i = 0; i < size; i++)
sum += arr[i];
return sum;
}

const unsigned int array_size = 100000;

int main()
{
x = complex_function_which_returns_one();
unsigned int large_array[array_size];
fill_array(large_array, array_size);
y = array_sum(large_array, array_size);
checkpoint();
assert(y + 2 > y); //y is nondet -- may overflow
assert(0);
return 0;
}
9 changes: 9 additions & 0 deletions regression/goto-harness/havoc-global-int-02/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
main.c
--harness-type initialise-with-memory-snapshot --memory-snapshot ../load-snapshot-json-snapshots/global-int-x-y-snapshot.json --initial-location main:9 --havoc-variables y
^\[main.assertion.1\] line \d+ assertion y \+ 2 > y: FAILURE$
^\[main.assertion.2\] line \d+ assertion 0: FAILURE$
^EXIT=10$
^SIGNAL=0$
--
^warning: ignoring
21 changes: 21 additions & 0 deletions regression/goto-harness/havoc-global-struct/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <assert.h>

struct simple_str
{
int i;
int j;
} simple;

void checkpoint()
{
}

int main()
{
simple.i = 1;
simple.j = 2;

checkpoint();
assert(simple.j > simple.i);
return 0;
}
8 changes: 8 additions & 0 deletions regression/goto-harness/havoc-global-struct/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c
--harness-type initialise-with-memory-snapshot --memory-snapshot ../load-snapshot-json-snapshots/global-struct-snapshot.json --initial-location main:3 --havoc-variables simple
^EXIT=10$
^SIGNAL=0$
^\[main.assertion.1\] line \d+ assertion simple.j > simple.i: FAILURE$
--
^warning: ignoring
Loading