Skip to content

Commit cd5ab37

Browse files
authored
Merge pull request #5377 from danpoe/docs/nondet-volatile
Add user documentation for goto-instrument nondet volatile options
2 parents c7067b0 + b540ecf commit cd5ab37

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

doc/architectural/nondet-volatile.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
\ingroup module_hidden
2+
\page nondet-volatile Modelling of Volatile Variables
3+
4+
This document describes the options available in goto-instrument for modelling
5+
the behaviour of volatile variables. The following options are provided:
6+
7+
- `--nondet-volatile`
8+
- `--nondet-volatile-variable <variable>`
9+
- `--nondet-volatile-model <variable>:<model>`
10+
11+
By default, cbmc treats volatile variables the same as non-volatile variables.
12+
That is, it assumes that a volatile variable does not change between subsequent
13+
reads, unless it was written to by the program. With the above options,
14+
goto-instrument can be instructed to instrument the given goto program such as
15+
to (1) make reads from all volatile expressions non-deterministic
16+
(`--nondet-volatile`), (2) make reads from specific variables non-deterministic
17+
(`--nondet-volatile-variable`), or (3) model reads from specific variables by
18+
given models (`--nondet-volatile-model`).
19+
20+
Below we give two usage examples for the options. Consider the following test,
21+
for function `get_celsius()` and with harness `test_get_celsius()`:
22+
23+
```C
24+
#include <assert.h>
25+
#include <limits.h>
26+
#include <stdint.h>
27+
28+
// hardware sensor for temperature in kelvin
29+
extern volatile uint16_t temperature;
30+
31+
int get_celsius()
32+
{
33+
if(temperature > (1000 + 273))
34+
{
35+
return INT_MIN; // value indicating error
36+
}
37+
38+
return temperature - 273;
39+
}
40+
41+
void test_get_celsius()
42+
{
43+
int t = get_celsius();
44+
45+
assert(t == INT_MIN || t <= 1000);
46+
assert(t == INT_MIN || t >= -273);
47+
}
48+
```
49+
50+
Here the variable `temperature` corresponds to a hardware sensor. It returns
51+
the current temperature on each read. The `get_celsius()` function converts the
52+
value in Kelvin to degrees Celsius, given the value is in the expected range.
53+
However, it has a bug where it reads `temperature` a second time after the
54+
check, which may yield a value for which the check would not succeed. Verifying
55+
this program as is with cbmc would yield a verification success. We can use
56+
goto-instrument to make reads from `temperature` non-deterministic:
57+
58+
```
59+
goto-cc -o get_celsius_test.gb get_celsius_test.c
60+
goto-instrument --nondet-volatile-variable temperature get_celsius_test.gb get_celsius_test-mod.gb
61+
cbmc --function test_get_celsius get_celsius_test-mod.gb
62+
```
63+
64+
Here the final invocation of cbmc correctly reports a verification failure.
65+
66+
However, simply treating volatile variables as non-deterministic may for some
67+
use cases be too inaccurate. Consider the following test, for function
68+
`get_message()` and with harness `test_get_message()`:
69+
70+
```C
71+
#include <assert.h>
72+
#include <stdint.h>
73+
74+
extern volatile uint32_t clock;
75+
76+
typedef struct message {
77+
uint32_t timestamp;
78+
void *data;
79+
} message_t;
80+
81+
void *read_data();
82+
83+
message_t get_message()
84+
{
85+
message_t msg;
86+
87+
msg.timestamp = clock;
88+
msg.data = read_data();
89+
90+
return msg;
91+
}
92+
93+
void test_get_message()
94+
{
95+
message_t msg1 = get_message();
96+
message_t msg2 = get_message();
97+
98+
assert(msg1.timestamp <= msg2.timestamp);
99+
}
100+
```
101+
102+
The harness verifies that `get_message()` assigns non-decreasing timestamps to
103+
the returned messages. However, simply treating `clock` as non-deterministic
104+
would not allow to prove this property. Thus, we can supply a model for reads
105+
from `clock`:
106+
107+
```C
108+
// model for reads of the variable clock
109+
uint32_t clock_read_model()
110+
{
111+
static uint32_t clock_value = 0;
112+
113+
uint32_t increment;
114+
__CPROVER_assume(increment <= 100);
115+
116+
clock_value += increment;
117+
118+
return clock_value;
119+
}
120+
```
121+
122+
The model is stateful in that it keeps the current clock value between
123+
invocations in the variable `clock_value`. On each invocation, it increments
124+
the clock by a non-determinstic value in the range 0 to 100. We can tell
125+
goto-instrument to use the model `clock_read_model()` for reads from the
126+
variable `clock` as follows:
127+
128+
```
129+
goto-cc -o get_message_test.gb get_message_test.c
130+
goto-instrument --nondet-volatile-model clock:clock_read_model get_message_test.gb get_message_test-mod.gb
131+
cbmc --function get_message_test get_message_test-mod.gb
132+
```
133+
134+
Now the final invocation of cbmc reports verification success.
135+

0 commit comments

Comments
 (0)