@@ -314,87 +314,121 @@ VERIFICATION SUCCESSFUL
314
314
315
315
### The memory snapshot harness
316
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.
317
+ The `function-call` harness is used in situations in which we want to analyze a
318
+ function in an arbitrary environment. If we want to analyze a function starting
319
+ from a _real_ program state, we can use the `memory-snapshot` harness instead.
320
+
321
+ The snapshot of the program state of interest may be taken at a particular
322
+ program location within a function (using the `memory-analyzer` tool). In that
323
+ case we want to generate a harness that behaves as if execution starts at a
324
+ particular program location. The initial program location can be specified via
325
+ the options `--initial-goto-location <function>[:<location-number>]` or
326
+ `--initial-source-location <file>:<line-number>`.
332
327
333
328
Say we want to check the assertion in the following code:
334
329
335
330
```C
336
331
// main.c
337
332
#include <assert.h>
333
+ #include <stdlib.h>
338
334
339
- unsigned int x;
340
- unsigned int y;
341
-
342
- unsigned int nondet_int() {
343
- unsigned int z;
344
- return z;
345
- }
335
+ int x;
336
+ int y;
337
+ int z;
346
338
347
- void checkpoint() {}
339
+ // complex function which returns 1
340
+ int get_one()
341
+ {
342
+ int i;
348
343
349
- unsigned int complex_function_which_returns_one() {
350
- unsigned int i = 0;
351
- while(++i < 1000001) {
352
- if(nondet_int() && ((i & 1) == 1))
344
+ for(i = 0; i < 100001; i++)
345
+ {
346
+ if(rand() && ((i & 1) == 1))
353
347
break;
354
348
}
349
+
355
350
return i & 1;
356
351
}
357
352
358
- void fill_array(unsigned int* arr, unsigned int size) {
359
- for (unsigned int i = 0; i < size; i++)
360
- arr[i]=nondet_int();
353
+ // return a random value (!= 0)
354
+ int get_random_value()
355
+ {
356
+ int r;
357
+ while((r = rand()) == 0) {}
358
+ return r;
361
359
}
362
360
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;
361
+ int clip(int i)
362
+ {
363
+ if(i > 99)
364
+ {
365
+ i = 99;
366
+ }
367
+
368
+ return i;
368
369
}
369
370
370
- const unsigned int array_size = 100000;
371
+ int main()
372
+ {
373
+ x = get_random_value();
374
+ y = get_one();
375
+
376
+ // snapshot taken here (line 46)
377
+
378
+ z = clip(x);
379
+
380
+ assert(y + z <= 100);
371
381
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
382
return 0;
380
383
}
381
384
```
382
385
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:
386
+ Assume we are interested in the code represented by the ` clip() ` function and
387
+ its effect on the assertion below. To that end, we want to take a memory
388
+ snapshot after the calls to ` get_random_value() ` and ` get_one() ` .
389
+
390
+ In order to take the snapshot with ` memory-analyzer ` , we need to first compile
391
+ the program which ` goto-gcc ` , which produces a binary containing both native
392
+ machine code and the corresponding goto program:
393
+
394
+ ``` sh
395
+ $ goto-gcc -g -o main.gb main.c
396
+ ```
397
+
398
+ Then we can execute the program with ` memory-analyzer ` and take a snapshot at
399
+ the specified breakpoint. The variables to be included in the snapshot need to
400
+ be specified via the ` --symbols ` option.
388
401
402
+ ``` sh
403
+ $ memory-analyzer \
404
+ --breakpoint 46 \
405
+ --symbols ' x, y, z' \
406
+ --symtab-snapshot \
407
+ --json-ui \
408
+ main.gb \
409
+ > snapshot.json
389
410
```
411
+
412
+ We then generate a harness with ` goto-harness ` that behaves as if execution
413
+ started from the state given by the memory snapshot at the specified program
414
+ location. We further overapproximate the value returned by ` get_random_value() `
415
+ by havocking the variable ` x ` .
416
+
417
+ ``` sh
390
418
$ goto-cc -o main.gb main.c
419
+
391
420
$ goto-harness \
392
421
--harness-function-name harness \
393
422
--harness-type initialise-with-memory-snapshot \
394
423
--memory-snapshot snapshot.json \
395
- --initial-location checkpoint \
424
+ --initial-source- location main.c:46 \
396
425
--havoc-variables x \
397
426
main.gb main-mod.gb
427
+ ```
428
+
429
+ We can now verify the resulting goto program with ` cbmc ` :
430
+
431
+ ``` sh
398
432
$ cbmc --function harness main-mod.gb
399
433
```
400
434
@@ -405,7 +439,7 @@ This will result in:
405
439
406
440
** Results:
407
441
main.c function main
408
- [main.assertion.1] line 42 assertion y + 2 > x : SUCCESS
442
+ [main.assertion.1] line 50 assertion y + z <= 100 : SUCCESS
409
443
410
444
** 0 of 1 failed (1 iterations)
411
445
VERIFICATION SUCCESSFUL
0 commit comments