@@ -13,9 +13,10 @@ having to manually construct an appropriate environment.
1313
1414We 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
1817without 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
2021It is used similarly to how ` goto-instrument ` is used by modifying an existing
2122GOTO binary, as produced by ` goto-cc ` .
@@ -309,4 +310,103 @@ main.c function function
309310
310311** 0 of 1 failed (1 iterations)
311312VERIFICATION SUCCESSFUL
312- ```
313+ ```
314+
315+ ### The memory snapshot harness
316+
317+ The `function-call` harness is used in situations in which we want the analysed
318+ function to work in arbitrary environment. If we want to analyse a function
319+ starting from a _real_ program state, we can call the `memory-snapshot` harness
320+ instead.
321+
322+ Furthermore, the program state of interest may be taken at 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>]`). Note that the
326+ initial location does not have to be the first instruction of a function: we can
327+ also specify the _location number_ `n` to set the initial location inside our
328+ function. The _location numbers_ do not have to coincide with the lines of the
329+ program code. To find the _location number_ run CBMC with
330+ `--show-goto-functions`. Most commonly, the _location number_ is the instruction
331+ of the break-point used to extract the program state for the memory snapshot.
332+
333+ Say we want to check the assertion in the following code:
334+
335+ ```C
336+ // main.c
337+ #include <assert.h>
338+
339+ unsigned int x;
340+ unsigned int y;
341+
342+ unsigned int nondet_int() {
343+ unsigned int z;
344+ return z;
345+ }
346+
347+ void checkpoint() {}
348+
349+ unsigned int complex_function_which_returns_one() {
350+ unsigned int i = 0;
351+ while(++i < 1000001) {
352+ if(nondet_int() && ((i & 1) == 1))
353+ break;
354+ }
355+ return i & 1;
356+ }
357+
358+ void fill_array(unsigned int* arr, unsigned int size) {
359+ for (unsigned int i = 0; i < size; i++)
360+ arr[i]=nondet_int();
361+ }
362+
363+ unsigned int array_sum(unsigned int* arr, unsigned int size) {
364+ unsigned int sum = 0;
365+ for (unsigned int i = 0; i < size; i++)
366+ sum += arr[i];
367+ return sum;
368+ }
369+
370+ const unsigned int array_size = 100000;
371+
372+ int main() {
373+ x = complex_function_which_returns_one();
374+ unsigned int large_array[array_size];
375+ fill_array(large_array, array_size);
376+ y = array_sum(large_array, array_size);
377+ checkpoint();
378+ assert(y + 2 > x);
379+ return 0;
380+ }
381+ ```
382+
383+ But are not particularly interested in analysing the complex function, since we
384+ trust that its implementation is correct. Hence we run the above program
385+ stopping after the assignments to ` x ` and ` x ` and storing the program state,
386+ e.g. using the ` memory-analyzer ` , in a JSON file ` snapshot.json ` . Then run the
387+ harness and verify the assertion with:
388+
389+ ```
390+ $ goto-cc -o main.gb main.c
391+ $ goto-harness \
392+ --harness-function-name harness \
393+ --harness-type initialise-with-memory-snapshot \
394+ --memory-snapshot snapshot.json \
395+ --initial-location checkpoint \
396+ --havoc-variables x \
397+ main.gb main-mod.gb
398+ $ cbmc --function harness main-mod.gb
399+ ```
400+
401+ This will result in:
402+
403+ ```
404+ [...]
405+
406+ ** Results:
407+ main.c function main
408+ [main.assertion.1] line 42 assertion y + 2 > x: SUCCESS
409+
410+ ** 0 of 1 failed (1 iterations)
411+ VERIFICATION SUCCESSFUL
412+ ```
0 commit comments