@@ -13,9 +13,10 @@ having to manually construct an appropriate environment.
13
13
14
14
We have two types of harnesses we can generate for now:
15
15
16
- * The ` memory-snapshot ` harness. TODO: Daniel can document this.
17
16
* The ` function-call ` harness, which automatically synthesises an environment
18
17
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.
19
20
20
21
It is used similarly to how ` goto-instrument ` is used by modifying an existing
21
22
GOTO binary, as produced by ` goto-cc ` .
@@ -309,4 +310,102 @@ main.c function function
309
310
310
311
** 0 of 1 failed (1 iterations)
311
312
VERIFICATION 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 a more restricted
319
+ environment or if we have the program in which our function will be called,
320
+ we can call the `memory-snapshot` harness 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 co-relate with the lines of the
329
+ program code. To find the _location number_ run CBMC with
330
+ `--show-goto-functions`.
331
+
332
+ Say we want to check the assertion in the following code:
333
+
334
+ ```C
335
+ // main.c
336
+ #include <assert.h>
337
+
338
+ unsigned int x;
339
+ unsigned int y;
340
+
341
+ unsigned int nondet_int() {
342
+ unsigned int z;
343
+ return z;
344
+ }
345
+
346
+ void checkpoint() {}
347
+
348
+ unsigned int complex_function_which_returns_one() {
349
+ unsigned int i = 0;
350
+ while(++i < 1000001) {
351
+ if(nondet_int() && ((i & 1) == 1))
352
+ break;
353
+ }
354
+ return i & 1;
355
+ }
356
+
357
+ void fill_array(unsigned int* arr, unsigned int size) {
358
+ for (unsigned int i = 0; i < size; i++)
359
+ arr[i]=nondet_int();
360
+ }
361
+
362
+ unsigned int array_sum(unsigned int* arr, unsigned int size) {
363
+ unsigned int sum = 0;
364
+ for (unsigned int i = 0; i < size; i++)
365
+ sum += arr[i];
366
+ return sum;
367
+ }
368
+
369
+ const unsigned int array_size = 100000;
370
+
371
+ int main() {
372
+ x = complex_function_which_returns_one();
373
+ unsigned int large_array[array_size];
374
+ fill_array(large_array, array_size);
375
+ y = array_sum(large_array, array_size);
376
+ checkpoint();
377
+ assert(y + 2 > x);
378
+ return 0;
379
+ }
380
+ ```
381
+
382
+ But are not particularly interested in analysing the complex function, since we
383
+ trust that its implementation is correct. Hence we run the above program
384
+ stopping after the assignments to ` x ` and ` x ` and storing the program state,
385
+ e.g. using the ` memory-analyzer ` , in a JSON file ` snapshot.json ` . Then run the
386
+ harness and verify the assertion with:
387
+
388
+ ```
389
+ $ goto-cc -o main.gb main.c
390
+ $ goto-harness \
391
+ --harness-function-name harness \
392
+ --harness-type initialise-with-memory-snapshot \
393
+ --memory-snapshot snapshot.json \
394
+ --initial-location checkpoint \
395
+ --havoc-variables x \
396
+ main.gb main-mod.gb
397
+ $ cbmc --function harness main-mod.gb
398
+ ```
399
+
400
+ This will result in:
401
+
402
+ ```
403
+ [...]
404
+
405
+ ** Results:
406
+ main.c function main
407
+ [main.assertion.1] line 42 assertion y + 2 > x: SUCCESS
408
+
409
+ ** 0 of 1 failed (1 iterations)
410
+ VERIFICATION SUCCESSFUL
411
+ ```
0 commit comments