Skip to content

Commit 126d582

Browse files
committed
Merge branch 'master' of github.com:diffblue/cbmc
2 parents 601db02 + 0b3fc40 commit 126d582

File tree

102 files changed

+14054
-1606
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+14054
-1606
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ src/big-int/test-bigint.exe
3030

3131
# files stored by editors
3232
*~
33+
34+
# libs downloaded by make [name]-download
3335
libzip/
36+
zlib/
37+
minisat*/
38+
glucose-syrup/
3439

3540
# flex/bison generated files
3641
src/ansi-c/ansi_c_lex.yy.cpp

COMPILING

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ environments:
1010

1111
- Solaris 11
1212

13-
- FreeBSD 10
13+
- FreeBSD 10 or 11
1414

1515
- Cygwin
1616
(We recommend the i686-pc-mingw32-g++ cross compiler, version 4.7 or above.)
@@ -83,8 +83,8 @@ COMPILATION ON SOLARIS 11
8383
It will mis-optimize MiniSat2.
8484

8585

86-
COMPILATION ON FREEBSD 10
87-
-------------------------
86+
COMPILATION ON FREEBSD 10/11
87+
----------------------------
8888

8989
1) As root, get the necessary tools:
9090

doc/html-manual/cover.shtml

Lines changed: 131 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ We assume that CBMC is installed on your system. If not so, follow
1717
<a href="installation-cbmc.shtml">these instructions</a>.</p>
1818

1919
<p class="justified">
20-
CBMC can be used to automatically generate test cases following a certain <a
20+
CBMC can be used to automatically generate test cases that satisfy a certain <a
2121
href="https://en.wikipedia.org/wiki/Code_coverage">code coverage</a>
2222
criterion. Common coverage criteria include branch coverage, condition
2323
coverage and <a
@@ -32,135 +32,168 @@ in a way that affects the outcome of the decision.
3232

3333
<p class="justified">
3434
In the following, we are going to demonstrate how to apply the test suite
35-
generation functionality in CBMC, by means of a case study. Even though it
36-
is simple, the following program (<a href="pid.c">pid.c</a>) is
37-
excerpted from a real-time embedded benchmark <a
35+
generation functionality in CBMC, by means of a case study. The program
36+
<a href="pid.c">pid.c</a> is an excerpt from a real-time embedded benchmark <a
3837
href="https://www.irit.fr/recherches/ARCHI/MARCH/rubrique.php3?id_rubrique=97">PapaBench</a>,
39-
which is an application for autopilot/fly-by-wire and is developed to be
40-
embedded on Unmanned Aerial Vehicles (UAVs). It is adjusted mildly for our
41-
purposes.
38+
and implements part of a fly-by-wire autopilot for an Unmanned Aerial Vehicle (UAV).
39+
It is adjusted mildly for our purposes.
4240
</p>
4341

44-
<pre><code class="c numbered">01: // CONSTANTS:
45-
02: #define MAX_CLIMB_SUM_ERR 150
46-
03: #define MAX_CLIMB 1
47-
04:
48-
05: #define CLOCK 16
49-
06: #define MAX_PPRZ (CLOCK*600)
50-
07:
51-
08: #define CLIMB_LEVEL_GAZ 0.31
52-
09: #define CLIMB_GAZ_OF_CLIMB 0.2
53-
10: #define CLIMB_PITCH_OF_VZ_PGAIN 0.05
54-
11: #define CLIMB_PGAIN -0.03
55-
12: #define CLIMB_IGAIN 0.1
56-
13:
57-
14: const float pitch_of_vz_pgain=CLIMB_PITCH_OF_VZ_PGAIN;
58-
15: const float climb_pgain=CLIMB_PGAIN;
59-
16: const float climb_igain=CLIMB_IGAIN;
60-
17: const float nav_pitch=0;
61-
18:
62-
19: // OUTPUTS:
63-
20: float desired_gaz;
64-
21: float desired_pitch;
65-
22: float climb_sum_err;
66-
23:
67-
24: /** Computes desired_gaz and desired_pitch */
68-
25: void climb_pid_run (float desired_climb, float estimator_z_dot, float old_climb_sum_err) {
69-
26: /** Range of inputs */
70-
27: __CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB);
71-
28: __CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB);
72-
29: __CPROVER_assume(old_climb_sum_err>=-MAX_CLIMB_SUM_ERR && old_climb_sum_err<=MAX_CLIMB_SUM_ERR);
73-
30:
74-
31: float err=estimator_z_dot-desired_climb;
75-
32:
76-
33: float fgaz=climb_pgain*(err+climb_igain*old_climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb;
77-
34:
78-
35: float pprz=fgaz*MAX_PPRZ;
79-
36: desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0));
80-
37:
81-
38: /** pitch offset for climb */
82-
39: float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0;
83-
40: desired_pitch=nav_pitch+pitch_of_vz;
84-
41:
85-
42: climb_sum_err=err+old_climb_sum_err;
86-
43: if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR;
87-
44: if (climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR;
88-
45:
89-
46: }
90-
</code></pre>
91-
9242
<p class="justified">
93-
The function <code>climb_pid_run</code> is part of the PID control
94-
procedure. Its input arguments <code>desired_climb</code> and
95-
<code>estimator_z_dot</code> represent respectively the desired and
96-
estimated speed in meters per second in the vertical direction;
97-
<code>old_climb_sum_err</code> is the current accumulated error between
98-
<code>desired_climb</code> and <code>estimator_z_dot</code>. Given inputs,
99-
the function then computes the <code>desired_gaz</code> and
100-
<code>desired_pitch</code> parameters, and updates the accumulated
101-
<code>climb_sum_err</code>.
43+
The aim of function <code>climb_pid_run</code> is to control the vertical climb of the UAV.
44+
Details on the theory behind this operation are documented in the <a
45+
href="https://wiki.paparazziuav.org/wiki/Theory_of_Operation">wiki</a> for the Paparazzi UAV project.
46+
The behaviour of this simple controller, supposing that the desired speed is 0.5 meters per second,
47+
is plotted in the Figure below.
10248
</p>
10349

104-
<p class="justified">
105-
There are four conditional statements in the function: line 36, line 39, and
106-
line 43 and line 44. Suppose we aim to obtain code coverage
107-
that satisfies the MC/DC criterion. This can be done
108-
using CBMC by calling
109-
</p>
50+
<center>
51+
<!--<embed src="pid.pdf" width="400px" height="250px" /> -->
52+
<img src="pid.png" width="400px" height="250px" alt="The pid controller">
11053

111-
<pre>
112-
<code>cbmc pid.c --cover mcdc --function climb_pid_run
54+
</center>
55+
56+
<pre><code class="c numbered">01: // CONSTANTS:
57+
02: #define MAX_CLIMB_SUM_ERR 100
58+
03: #define MAX_CLIMB 1
59+
04:
60+
05: #define CLOCK 16
61+
06: #define MAX_PPRZ (CLOCK*600)
62+
07:
63+
08: #define CLIMB_LEVEL_GAZ 0.31
64+
09: #define CLIMB_GAZ_OF_CLIMB 0.75
65+
10: #define CLIMB_PITCH_OF_VZ_PGAIN 0.05
66+
11: #define CLIMB_PGAIN -0.03
67+
12: #define CLIMB_IGAIN 0.1
68+
13:
69+
14: const float pitch_of_vz_pgain=CLIMB_PITCH_OF_VZ_PGAIN;
70+
15: const float climb_pgain=CLIMB_PGAIN;
71+
16: const float climb_igain=CLIMB_IGAIN;
72+
17: const float nav_pitch=0;
73+
18:
74+
19: // 1) the target speed in vertical direction
75+
20: float desired_climb;
76+
21: // 2) vertical speed of the UAV, estimated by a control function
77+
22: float estimator_z_dot;
78+
23:
79+
24: /** PID funciton OUTPUTS */
80+
25: float desired_gaz;
81+
26: float desired_pitch;
82+
27: // Accumulated error in the system
83+
28: float climb_sum_err;
84+
29:
85+
30: /** Computes desired_gaz and desired_pitch */
86+
31: void climb_pid_run()
87+
32: {
88+
33:
89+
34: float err=estimator_z_dot-desired_climb;
90+
35:
91+
36: float fgaz=climb_pgain*(err+climb_igain*climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb;
92+
37:
93+
38: float pprz=fgaz*MAX_PPRZ;
94+
39: desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0));
95+
40:
96+
41: /** pitch offset for climb */
97+
42: float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0;
98+
43: desired_pitch=nav_pitch+pitch_of_vz;
99+
44:
100+
45: climb_sum_err=err+climb_sum_err;
101+
46: if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR;
102+
47: if (climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR;
103+
48:
104+
49: /** Estimates the vertical speed */
105+
50: estimator_z_dot=climb_pgain * err + desired_climb;
106+
51: }
107+
52:
108+
53: int main()
109+
54: {
110+
55: /** Non-deterministic initialisation */
111+
56: desired_climb=nondet_float();
112+
57: estimator_z_dot=nondet_float();
113+
58:
114+
59: /** Range of initial values of variables */
115+
60: __CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB);
116+
61: __CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB);
117+
62:
118+
63: while(1)
119+
64: {
120+
65: climb_pid_run();
121+
66: }
122+
67:
123+
68: return 0;
124+
69: }
113125
</code></pre>
114126

115127
<p class="justified">
116-
The <code>--cover mcdc</code> option chooses the coverage criterion, and <code>--function climb_pid_run</code>
117-
specifies the function to be analyzed.
128+
In order to test the PID controller, we construct a main control loop,
129+
which repeatedly invokes the function <code>climb_pid_run</code> (line 65).
130+
In the beginning of the main function, the values of the desired speed <code>desired_climb</code>
131+
and the estimated speed <code>estimated_z_dot</code> are initialised non-deterministically.
132+
Subsequently, the <code>__CPROVER_assume</code> statement in lines 60 and 61 guarantees that
133+
their values are bounded within a range.
118134
</p>
119135

120136
<p class="justified">
121-
The printed outputs will display the configurations of conditions that have
122-
been covered by CBMC. For each conditional statement, the
123-
configuration for its decision to be <em>true</em>/<em>false</em> will be
124-
covered. To fullfil the requirement of MC/DC, further tests are required.
125-
For example, at line 36, there is
137+
To demonstrate the automatic test suite generation in CBMC,
138+
we call the following command
126139
</p>
127140

128-
<pre>
129-
<code> pprz>=0 && pprz<=MAX_PPRZ
141+
<pre><code>cbmc pid.c --cover mcdc --unwind 25 --trace --xml-ui
130142
</code></pre>
131143

132144
<p class="justified">
133-
To satisfy MC/DC on such a decision, three requirements for its conditions (boolean
134-
expressions) are finally generated and reported by CBMC:
145+
The option <code>--cover mcdc</code> specifies the code coverage criterion.
146+
There are four conditional statements in the PID function: in line 39, line 42,
147+
line 46 and line 47.
148+
To satisfy MC/DC, the test suite has to meet multiple requirements.
149+
For instance, each conditional statement needs to evaluate to <em>true</em> and <em>false</em>.
150+
Consider the condition <code>"pprz>=0 && pprz<=MAX_PPRZ"</code> at line 39. CBMC
151+
instruments three coverage goals to control the respective evaluated results of <code>"pprz>=0"</code> and
152+
<code>"pprz<=MAX_PPRZ"</code>.
153+
We list them in below and they satisfy the MC/DC rules.
154+
Note that <code>MAX_PPRZ</code> is defined as 16 * 600 at line 06 of the program.
135155
</p>
136156

137157
<pre>
138-
<code>C1: !(pprz >= (float)0) && pprz <= (float)(16 * 600)
139-
C2: pprz >= (float)0 && !(pprz <= (float)(16 * 600))
140-
C3: pprz >= (float)0 && pprz <= (float)(16 * 600)
158+
<code>!(pprz >= (float)0) && pprz <= (float)(16 * 600) id="climb_pid_run.coverage.1"
159+
pprz >= (float)0 && !(pprz <= (float)(16 * 600)) id="climb_pid_run.coverage.2"
160+
pprz >= (float)0 && pprz <= (float)(16 * 600) id="climb_pid_run.coverage.3"
141161
</code></pre>
142162

143163
<p class="justified">
144-
CBMC generates the following test suite:
164+
The "id" of each coverage goal is automatically assigned by CBMC. For every
165+
coverage goal, a trace (if there exists) of the program execution that
166+
satisfies such a goal is printed out in XML format, as the parameters
167+
<code>--trace --xml-ui</code> are given. Multiple coverage goals can share a
168+
trace, when the corresponding execution of the program satisfies all these
169+
goals at the same time. Each trace corresponds to a test case.
145170
</p>
171+
172+
<p class="justified">
173+
For the example above, the following test suites are generated.
146174
<pre><code>Test suite:
147-
T1: desired_climb=6.250003e-2f, estimator_z_dot=1.000000f, old_climb_sum_err=8.988036e+0f
148-
T2: desired_climb=0.000000f, estimator_z_dot=6.134232e-38f, old_climb_sum_err=-6.232042e-37f
149-
T3: desired_climb=6.750841e-20f, estimator_z_dot=-6.011939e-1f, old_climb_sum_err=1.156406e+2f
150-
T4: desired_climb=-9.999999e-1f, estimator_z_dot=1.000000f, old_climb_sum_err=150.000000f
151-
T5: desired_climb=9.999999e-1f, estimator_z_dot=-1.000000f, old_climb_sum_err=-150.000000f
175+
T1: desired_climb=-1.000000f, estimator_z_dot=1.000000f
176+
(goal id: climb_pid_run.coverage.1)
177+
T2: desired_climb=1.000000f, estimator_z_dot=-1.000000f
178+
(goal id: climb_pid_run.coverage.2)
179+
T3: desired_climb=0.000000f, estimator_z_dot=0.000000f
180+
(goal id: climb_pid_run.coverage.3)
152181
</code></pre>
182+
</p>
153183

154184
<p class="justified">
155-
The tests T1 and T3 are both tests that cause C3 evaluate to <em>true</em>, T3 and
156-
T4 cover C1, and T5 is for C2. Similar observations can be made for the conditional
157-
statements at line 39, 43 and 44.
185+
The option <code>--unwind 25</code> unwinds the loop inside the main
186+
function body 25 times. The number of the unwinding operation is
187+
adjustable, and an introduction to the use of loop unwinding can be found
188+
in <a href="cbmc-loops.shtml">Understanding Loop Unwinding</a>.
158189
</p>
159190

160191
<p class="justified">
161-
In addition to <code>--cover mcdc</code>, other coverage criteria
162-
like <code>branch</code>, <code>decision</code>, <code>path</code>
163-
etc. are also available when calling CBMC.
192+
In this small tutorial, we present the automatic test suite generation
193+
functionality of CBMC, by applying the MC/DC code coverage criterion to a
194+
PID controller case study. In addition to <code>--cover mcdc</code>, other
195+
coverage criteria like <code>branch</code>, <code>decision</code>,
196+
<code>path</code> etc. are also available when calling CBMC.
164197
</p>
165198

166199
<!--#include virtual="footer.inc" -->

doc/html-manual/pid.c

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// CONSTANTS:
2-
#define MAX_CLIMB_SUM_ERR 150
2+
#define MAX_CLIMB_SUM_ERR 100
33
#define MAX_CLIMB 1
44

55
#define CLOCK 16
66
#define MAX_PPRZ (CLOCK*600)
77

88
#define CLIMB_LEVEL_GAZ 0.31
9-
#define CLIMB_GAZ_OF_CLIMB 0.2
9+
#define CLIMB_GAZ_OF_CLIMB 0.75
1010
#define CLIMB_PITCH_OF_VZ_PGAIN 0.05
1111
#define CLIMB_PGAIN -0.03
1212
#define CLIMB_IGAIN 0.1
@@ -16,21 +16,25 @@ const float climb_pgain=CLIMB_PGAIN;
1616
const float climb_igain=CLIMB_IGAIN;
1717
const float nav_pitch=0;
1818

19-
// OUTPUTS:
19+
// 1) the target speed in vertical direction
20+
float desired_climb;
21+
// 2) vertical speed of the UAV detected by GPS sensor
22+
float estimator_z_dot;
23+
24+
/** PID funciton OUTPUTS */
2025
float desired_gaz;
2126
float desired_pitch;
27+
// Accumulated error in the system
2228
float climb_sum_err;
2329

30+
2431
/** Computes desired_gaz and desired_pitch */
25-
void climb_pid_run (float desired_climb, float estimator_z_dot, float old_climb_sum_err) {
26-
/** Range of inputs */
27-
__CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB);
28-
__CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB);
29-
__CPROVER_assume(old_climb_sum_err>=-MAX_CLIMB_SUM_ERR && old_climb_sum_err<=MAX_CLIMB_SUM_ERR);
32+
void climb_pid_run()
33+
{
3034

3135
float err=estimator_z_dot-desired_climb;
3236

33-
float fgaz=climb_pgain*(err+climb_igain*old_climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb;
37+
float fgaz=climb_pgain*(err+climb_igain*climb_sum_err)+CLIMB_LEVEL_GAZ+CLIMB_GAZ_OF_CLIMB*desired_climb;
3438

3539
float pprz=fgaz*MAX_PPRZ;
3640
desired_gaz=((pprz>=0 && pprz<=MAX_PPRZ) ? pprz : (pprz>MAX_PPRZ ? MAX_PPRZ : 0));
@@ -39,9 +43,31 @@ void climb_pid_run (float desired_climb, float estimator_z_dot, float old_climb
3943
float pitch_of_vz=(desired_climb>0) ? desired_climb*pitch_of_vz_pgain : 0;
4044
desired_pitch=nav_pitch+pitch_of_vz;
4145

42-
climb_sum_err=err+old_climb_sum_err;
46+
climb_sum_err=err+climb_sum_err;
4347
if (climb_sum_err>MAX_CLIMB_SUM_ERR) climb_sum_err=MAX_CLIMB_SUM_ERR;
4448
if (climb_sum_err<-MAX_CLIMB_SUM_ERR) climb_sum_err=-MAX_CLIMB_SUM_ERR;
4549

50+
/** The control function for estimating the vertical speed */
51+
estimator_z_dot=climb_pgain * err + desired_climb;
52+
53+
}
54+
55+
56+
int main()
57+
{
58+
/** Non-deterministic initialisation */
59+
desired_climb=nondet_float();
60+
estimator_z_dot=nondet_float();
61+
62+
/** Range of initial values of variables */
63+
__CPROVER_assume(desired_climb>=-MAX_CLIMB && desired_climb<=MAX_CLIMB);
64+
__CPROVER_assume(estimator_z_dot>=-MAX_CLIMB && estimator_z_dot<=MAX_CLIMB);
65+
66+
while(1)
67+
{
68+
climb_pid_run();
69+
}
70+
71+
return 0;
4672
}
4773

doc/html-manual/pid.png

4.47 KB
Loading
Binary file not shown.

0 commit comments

Comments
 (0)