Professional Documents
Culture Documents
Frama C Acsl Implementation
Frama C Acsl Implementation
8
Implementation in Neon-20140301
1
2,4,3 , Virgile Prevosto1
Benjamin Monate , Yannick Moy
1 CEA LIST, Software Reliability Laboratory, Saclay, F-91191
2 France Tlcom, Lannion, F-22307
3 INRIA Saclay - le-de-France, ProVal, Orsay, F-91893
4 LRI, Univ Paris-Sud, CNRS, Orsay, F-91405
2009-2013
This work has been supported by the ANR project CAT (ANR-05-RNTL-0030x), by the
ANR CIFRE contract 2005/973, by the ANR project U3CAT (08-SEGI-021-xx), and ANR
PICF project DEVICE-Soft (2009-CARN-006-01).
CONTENTS
Contents
1 Introduction
11
1.1
11
1.2
. . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.2.1
Kinds of annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.2.2
13
1.2.3
About preprocessing . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.2.4
About keywords
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.3
2 Specication language
15
2.1
Lexical rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.2
Logic expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2.2.1
Operators precedence
. . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.2.2
Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.2.3
Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.2.4
. . . . . . . . . . . . . . . . .
20
2.2.5
. . . . . . . . . . . . . . . .
23
2.2.6
. . . . . . . . . . . . . . . . . . . . . . . . . . .
25
2.2.7
26
2.2.8
String literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
2.3
2.4
Function contracts
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
\old
and
\result
28
2.3.1
Built-in constructs
. . . . . . . . . . . . . . . . . . . .
29
2.3.2
. . . . . . . . . . . . . . . . . . . . . . . . .
29
2.3.3
. . . . . . . . . . . . . . . . . . . . .
30
2.3.4
33
2.3.5
35
Statement annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
2.4.1
Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
2.4.2
Loop annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
CONTENTS
2.5
2.6
\at
2.4.3
Built-in construct
. . . . . . . . . . . . . . . . . . . . . . . . . . .
40
2.4.4
Statement contracts
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
Termination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.5.1
Integer measures
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.5.2
General measures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
2.5.3
. . . . . . . . . . . . . . . . . . . . . . . . . .
44
2.5.4
Non-terminating functions . . . . . . . . . . . . . . . . . . . . . . . . .
45
Logic specications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
2.6.1
47
2.6.2
Lemmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
2.6.3
Inductive predicates
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
2.6.4
Axiomatic denitions . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
2.6.5
. . . . . . . . . . . . . . . . . . . . . . . . . .
49
2.6.6
50
2.6.7
50
2.6.8
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
2.6.9
51
reads
clause . . . . . . . . . . . . . . .
53
. . . . . . . . . . . . . . . . . . . . . . . . . . .
54
. . . . . . . . . . . . . . . . . . . . . . . . . .
55
2.7.1
. . . . . . . . . . . . . . . .
55
2.7.2
Separation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
2.7.3
57
2.8
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
2.9
Abrupt termination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
64
2.11.1 Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
. . . . . . . . . . . . . . . . . . . . .
67
68
72
73
2.13.1 Initialization
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
73
CONTENTS
3 Libraries
3.1
3.2
3.3
75
. . . . . . . . . . . . . . . . . . . . . . . . . .
75
3.1.1
Real numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
3.1.2
Finite lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
3.1.3
75
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
76
3.2.1
. . . . . . . . . . . . . . . . . . . . .
76
3.2.2
Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
Memory leaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
4 Conclusion
79
A Appendices
81
A.1
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
A.2
81
A.2.1
. . . . . . . . . . . . . .
82
A.2.2
85
A.2.3
Syntactic dierences
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
Typing rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
86
A.3.1
86
A.3.2
87
A.3
A.4
Specication Templates
A.4.1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
87
. . . . . . . . . . . . . . . . . .
87
A.5
Illustrative example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
88
A.6
Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
A.6.1
Version 1.8
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
A.6.2
Version 1.7
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
A.6.3
Version 1.6
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
A.6.4
Version 1.5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
A.6.5
Version 1.4
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
A.6.6
Version 1.3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
A.6.7
Version 1.2
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
Bibliography
97
List of Figures
99
Index
101
CONTENTS
Foreword
This is the version 1.8 of ACSL design. Several features may still evolve in the future. In
particular, some features in this document are considered experimental, meaning that their
syntax and semantics is not already xed. These features are marked with Experimental.
They must also be considered as advanced features, which are not supposed to be useful for
a basic use of that specication language.
Acknowledgements
We gratefully thank all the people who contributed to this document: Sylvie Boldo, Jean-Louis
Colao, Pierre Crgut, David Delmas, Catherine Dubois, Stphane Duprat, Arnaud Gotlieb,
Philippe Herrmann, Thierry Hubert, Dillon Pariente, Pierre Rousseau, Julien Signoles, Jean
Souyris, Asma Tafat.
Chapter 1
Introduction
This document is a reference manual for the ACSL implementation provided by the Frama-C
framework [11]. ACSL is an acronym for ANSI/ISO C Specication Language. This is a
Behavioral Interface Specication Language (BISL) implemented in the Frama-C framework.
It aims at specifying behavioral properties of C source code. The main inspiration for this
language comes from the specication language of the Caduceus tool [9, 10] for deductive
verication of behavioral properties of C programs. The specication language of Caduceus
is itself inspired from the Java Modeling Language (JML [19]) which aims at similar goals for
Java source code: indeed it aims both at runtime assertion checking and static verication
using the ESC/Java2 tool [15], where we aim at static verication and deductive verication
(see Appendix A.2 for a detailed comparison between ACSL and JML).
Going back further in history, JML design was guided by the general design-by-contract principle proposed by Bertrand Meyer, who took his own inspiration from the concepts of preconditions and postconditions on a routine, going back at least to Dijkstra, Floyd and Hoare in
the late 60's and early 70's, and originally implemented in the Eiffel language.
In this document, we assume that the reader has a good knowledge of the ISO C programming
language [14, 13].
As a summary, the features that are not currently implemented into Frama-C include in
particular:
11
CHAPTER 1. INTRODUCTION
/*@
or
//@
In some contexts, it is not possible to modify the source code. It is strongly recommended that
a tool which implements ACSL specications provides technical means to store annotations
separately from the source. It is not the purpose of this document to describe such means.
Nevertheless, some of the specications, namely those at a global level, can be given in separate
les: logical specications can be imported (see Section 2.6.11) and a function contract can
be attached to a copy of the function prole (see Section 2.3.5).
Global annotations:
function contract : such an annotation is inserted just before the declaration or the
denition of a function. See section 2.3.
global invariant : this is allowed at the level of global declarations. See section 2.11.
type invariant : this allows to declare both structure or union invariants, and invariants on type names introduced by
typedef .
logic specications : denitions of logic functions or predicates, lemmas, axiomatizations by declaration of new logic types, logic functions, predicates with axioms
they satisfy. Such an annotation is placed at the level of global declarations. See
section 2.6
Statement annotations:
assertion : these are allowed everywhere a C label is allowed, or just before a block
closing brace. See section 2.4.1.
for
while
do
...
while
statement contract : very similar to a function contract, and placed before a statement or a block. Semantical conditions must be checked (no goto going inside, no
goto going outside). See Section 2.4.4.
12
ghost code : regular C code, only visible from the specications, that is only allowed
to modify ghost variables. See section 2.12. This includes ghost braces for enclosing
blocks.
This
return
x /* @ +1 */ ;
In our language, this is forbidden. Technically, the current implementation of Frama-C isolates
the comments in a rst step of syntax analysis, and then parses a second time. Nevertheless,
the grammar and the corresponding parser must be carefully designed to avoid interaction of
annotations with the code. For example, in code such as
if
1
2
(c) // @
c =1;
the statement
c=1
assert
P;
assert
if.
ensures )
+
notations e to denote repetition of zero, one or more occurrences of e, e for repetition of one
?
or more occurrences of e, and e for zero or one occurrence of e. For the sake of simplicity, we
only describe annotations in the usual
//@
/*@ ... */
13
Chapter 2
Specication language
2.1 Lexical rules
Lexical structure mostly follows that of ANSI/ISO C. A few dierences must be noted.
Some UTF8 characters may be used in place of some constructs, as shown in the following table:
>=
<=
>
<
!=
==
==>
<==>
&&
||
^^
!
- (unary
minus)
\forall
\exists
integer
real
boolean
>
<
6
Z
R
B
0x2265
0x2264
0x003E
0x003C
0x2262
0x2261
0x21D2
0x21D4
0x2227
0x2228
0x22BB
0x00AC
0x2212
0x2200
0x2203
0x2124
0x211D
0x1D539
Comments can be put inside ACSL annotations. They use the C++ format, i.e. begin
with
//
15
bin-op
unary-op
term
::=
|
|
|
|
\true | \false
integer
real
string
character
::=
|
|
|
+ | - | * | / | % | << | >>
== | != | <= | >= | > | <
&& | || | ^^
& | | | --> | <--> | ^
::=
|
|
|
|
+ |
!
~
*
&
::=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
literal
id
unary-op term
term bin-op term
term [ term ]
{ term \with [ term ] = term }
term . id
{ term \with . id = term }
term -> id
( type-expr ) term
id ( term (, term) )
( term )
term ? term : term
\let id = term ; term
sizeof ( term )
sizeof ( C-type-expr )
id : term
string : term
boolean constants
integer constants
real constants
string constants
character constants
boolean operations
bitwise operations
unary plus and minus
boolean negation
bitwise complementation
pointer dereferencing
address-of operator
literal constants
variables
array access
array functional modier
structure eld access
eld functional modier
cast
function application
parentheses
ternary condition
local binding
syntactic naming
syntactic naming
These
In
that grammar, we distinguish between predicates and terms , following the usual distinction
between propositions and terms in classical rst-order logic. The grammar for binders and
type expressions is given separately in Figure 2.3.
With respect to C pure expressions, the additional constructs are as follows:
16
Quantication
(UTF8:
), ||
\exists x1 ,. . .,xn ; e.
quantication by
expression
&&
x = e1 ;e2
(UTF8:
for expression
e1
e2 .
c ? e1 : e2 .
term or a predicate. In case of a predicate, the two branches must be also predicates,
so that this construct acts as a connective with the following semantics:
equivalent to
\let :
c ? e1 : e2
is
Functional modier
ith
s,
id
that is equal to
rel-op
::=
== |
pred
::=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\true | \false
term (rel-op term)+
id ( term (, term) )
( pred )
pred && pred
pred || pred
pred ==> pred
pred <==> pred
! pred
pred ^^ pred
term ? pred : pred
pred ? pred : pred
\let id = term ; pred
\let id = pred ; pred
\forall binders ; pred
\exists binders ; pred
id : pred
string : pred
!= |
<= |
>= |
> |
<
comparisons (see remark)
predicate application
parentheses
conjunction
disjunction
implication
equivalence
negation
exclusive or
ternary condition
local binding
universal quantication
existential quantication
syntactic naming
syntactic naming
17
::=
binder
binder
::=
type-expr variable-ident
(,variable-ident )
type-expr
::=
logic-type-expr | C-type-expr
logic-type-expr
::=
|
built-in-logic-type
id
built-in-logic-type
::=
boolean |
variable-ident
::=
|
|
id | * variable-ident
variable-ident []
( variable-ident )
(,
binder )
type identier
integer |
real
Logic functions
tions, but of logic functions or predicates; see Section 2.6 for detail.
several
consecutive
The
t1 relop1 t2 relop2 t3 tk
construct
comparison
It
is
operators
is
required
that
the
shortcut
must be in the same direction, i.e. they must all belong either to
{>,>=,==}.
Expressions such as
x < y > z
or
x != y != z
for
relopi operators
{<, <=, ==} or to
To enforce the same interpretation as in C expressions, one may need to add extra paren-
theses:
to
\let x = b < c; a == x.
There is a subtlety regarding comparison operators: they are predicates when used in predicate
position, and boolean functions when used in term position.
Example 2.1
int
f(
int
a,
b) {
return
a < b; }
\result == a < b
\result == a && a < b.
int
boolean
an
(the type of
equivalent
(a<b))
post-condition,
( \result != 0) == (a<b).
which
does
rely
on
implicit
conversion,
is
not
as a boolean term.
cates.
18
associativity
operators
selection
left
unary
right
multiplicative
left
additive
left
shift
left
comparison
left
comparison
left
bitwise and
left
bitwise xor
left
bitwise or
left
bitwise implies
left
bitwise equiv
left
connective and
left
connective xor
left
connective or
left
connective implies
right
connective equiv
left
ternary connective
right
[ ] -> .
! ~ + - * & (cast) sizeof
*/%
+<< >>
< <= > >=
== !=
&
^
|
-->
<-->
&&
^^
||
==>
<==>
? :
binding
left
naming
right
\forall
\exists
\let
2.2.2 Semantics
The semantics of logic expressions in ACSL is based on mathematical rst-order logic [25]. In
particular, it is a 2-valued logic with only total functions. Consequently, expressions are never
undened. This is an important design choice and the specication writer should be aware of
that. (For a discussion about the issues raised by such design choices, in similar specication
languages such as JML, see the comprehensive list compiled by Patrice Chalin [4, 5].)
Having only total functions implies than one can write terms such as
1/0,
or
*p
when
is null
(or more generally when it points to a non-properly allocated memory cell). In particular,
the predicates
1/0
*p
of rst-order logic.
==
==
1/0
*p
x, x = x
consistent assertions. For example, when introducing the following lemma (see Section 2.6):
19
lemma div_mul_identity :
\ f o r a l l r e a l x , r e a l y;
/* @
@
@ */
y != 0.0 == > y *( x/ y) == x;
to be non zero.
2.2.3 Typing
The language of logic expressions is typed (as in multi-sorted rst-order logic).
Types are
mathematical types:
bers,
boolean
integer
\true
and
\false );
real
C integral types
integer ;
integer
and
C types
oat
and
double
long ,
real ;
real .
Notes:
The expression
x<y
in term
position is a boolean, and the same expression is also allowed in predicate position.
There is an im-
x && y
instead of
Quantication can be made over any type: logic types and C types. Quantication over
pointers must be used carefully, since it depends on the memory state where dereferencing is done (see Section 2.2.4 and Section 2.6.9).
Generally speak-
ing, division rounds the result towards zero. The results are not specied if divisor is zero;
otherwise if
and
20
divided by
then:
and
is zero if
is positive if
is negative if
|q|
and
|n| |d|
and
and
and
q d + r = n;
|r| < |d|;
r
Example 2.2
n.
The following examples illustrate the results of division and modulo depending
5/3
is 1 and
5%3
is 2;
(-5)/3
is -1 and
(-5)%3
is -2;
5/(-3)
is -1 and
5%(-3)
is 2;
(-5)/(-3)
is 1 and
(-5)%(-3)
is -2.
Suxes
and
for C
short , int ,
(such as
char ,
etc.) is allowed and is interpreted as follows: the result is the unique value of the
corresponding type that is congruent to the mathematical result modulo the cardinal of this
8 sizeof (t) .
type, that is 2
is
i.e.
232.
To express in the logic the value of a C expression, one has to add all the necessary
casts.
For example, the logic expression denoting the value of the C expression
Example 2.4
// @
logic int
f(
int
x+1,
// @
logic integer
// @
logic int
or
is
The declaration
x*y+z
f(
x) = x +1 ;
f(
int
int
x) = x +1 ;
x) = (
i n t )( x +1)
21
int .
One should
Example 2.5
\ f o r a l l char
c; c <= 1000
is equivalent to
\forall integer
where the the bounds
CHAR_MIN
and
CHAR_MAX
are dened in
limits.h
hence the semantics of terms involving such types is also architecture-dependent. The
sizeof
operator may be used in annotations and is consistent with its C counterpart. For instance,
it should be possible to verify the following code:
1
2
/* @
int
ensures \ r e s u l t <= s i z e o f ( i n t );
return s i z e o f ( char ); }
f () {
*/
Constants giving maximum and minimum values of those types may be provided in a library.
Enum types
Enum types are also interpreted as mathematical integers. Casting an integer into an enum
in the logic gives the same result as if the cast was performed in the C code.
Bitwise operations
Like arithmetic operations, bitwise operations apply to any mathematical integer: any mathematical integer has a unique innite 2-complement binary representation with innitely many
zeros (for non-negative numbers) or ones (for negative numbers) on the left. Bitwise operations apply to this representation.
Example 2.6
7 & 12 == 00111 & 001100 == 00100 == 4
-8 | 5 == 11000 | 00101 == 11101 == -3
~5 == ~ 00101 == 111010 == -6
-5 << 2 == 11011 << 2 == 11101100 == -20
5 >> 2 == 00101 >> 2 == 0001 == 1
-5 >> 2 == 11011 >> 2 == 1110 == -2
22
Example 2.7
In an annotation,
1e+300 * 1e+300
is equal to
1e+600,
2 0.1
0.2,
is no "rounding".
Unlike the promotion of C integer types to mathematical integers, there are special oat
values which do not naturally map to a real number, namely the IEEE-754 special values for
not-a-number,
and
real_of_float
and
real_of_double
is left unspecied.
0xhh.hhpdd
hh.hh 2dd , e.g.
In logic, real literals can also be expressed under the hexadecimal form of C99:
and
dd
In particular,
Or equivalently,
real_of_float(x) real_of_float(y)
x y
for
x, y
Special predicates are also available to express the comparison operators of oat (resp. double)
numbers as in C:
(resp.
for
double).
/* @
*/
type
rounding_mode =
\Up
\Down
\ToZero
\NearestAway
\NearestEven ;
l o g i c f l o a t \round_float ( rounding_mode m , r e a l x );
l o g i c double \round_double ( rounding_mode m , r e a l x );
Cast operators
( oat )
and
(double)
are
equivalent to apply rounding functions above with the nearest-even rounding mode (which is
the default rounding mode in C programs) If the source real number is too large, this may
also result into one of the special values +innity and -innity.
Example 2.8
( oat )0.1
0.100000001490116119384765625
We
have
13421773 227
23
which
is
equal
to
and
of a C operation
e1 op e2
on oats, if
there is no overow and if the default rounding mode is not changed in the program, has the
\eq_oat
\eq_oat
to
0.0,
of oats:
which is
Finally, additional predicates are provided on oat and double numbers, which check that
their argument is NaN or a nite number respectively:
1
2
3
4
predicate
predicate
predicate
predicate
\is_NaN ( f l o a t x );
\is_NaN ( double x );
\ i s _ f i n i t e ( f l o a t x );
\ i s _ f i n i t e ( double x );
Quantication
Quantication over a variable of type
real
Quantication over oat (resp. double) types is allowed too, and is supposed to range over all
real numbers representable as oats (resp doubles). In particular, this does not include NaN,
+innity and -innity in the considered range.
Mathematical functions
Classical mathematical operations like exponential, sine, cosine, and such are available as
built-in:
i n t e g e r \min ( i n t e g e r x , i n t e g e r
i n t e g e r \max ( i n t e g e r x , i n t e g e r
r e a l \min ( r e a l x , r e a l y) ;
r e a l \max ( r e a l x , r e a l y) ;
i n t e g e r \abs ( i n t e g e r x) ;
r e a l \abs ( r e a l x) ;
r e a l \sqrt ( r e a l x) ;
r e a l \pow ( r e a l x , r e a l y) ;
i n t e g e r \ c e i l ( r e a l x) ;
i n t e g e r \ f l o o r ( r e a l x) ;
r e a l \exp ( r e a l x) ;
r e a l \log ( r e a l x) ;
r e a l \log10 ( r e a l x) ;
r e a l \cos ( r e a l x) ;
r e a l \sin ( r e a l x) ;
r e a l \tan ( r e a l x) ;
r e a l \cosh ( r e a l x) ;
r e a l \sinh ( r e a l x) ;
r e a l \tanh ( r e a l x) ;
r e a l \acos ( r e a l x) ;
r e a l \asin ( r e a l x) ;
r e a l \atan ( r e a l x) ;
r e a l \atan2 ( r e a l y , r e a l x) ;
r e a l \hypot ( r e a l x , r e a l y) ;
y) ;
y) ;
24
\exact(x)
\round_error(x)
Example 2.9
is a shortcut for
|x \exact(x)|
/* @
@
@
@
@ */
0 x1p -24;
0 x3p -24;
address-of operator should be used with caution. Values in logic do not lie in C memory so
it does not mean anything to talk about their address.
Unlike in C, there is no implicit cast from from an array type to a pointer type. Nevertheless,
arithmetic and dereferencing over arrays lying in C memory are allowed like in C.
Example 2.10
int
int
int
tab [10] = { 1 } ;
x ;
*p = &x ;
requires
void
assert
assert
int
assert
// @
p == &x
main (
){
// @
tab [0]==1 && *p == x;
// @
* tab == 1;
*q = & tab [3];
// @
q +1 == tab +4;
...
int
(*p).s.
On the contrary,
lying in C memory.
dierences between
t[i]
25
Example 2.11
int
int
i n t x );
i n t x );
// @ r e q u i r e s p == &f
void h( i n t (* p )( i n t ))
f(
g(
...
}
|| p == &g;
{
They can be passed as parameters (and also returned) to logic functions, tested for
Example 2.12
Array types in logic may be declared either with or without an explicit non-
negative length. Access to the length of a logic array can be done with
// @
// @
type point = s t r u c t { r e a l x; r e a l y; };
type triangle = point [3];
l o g i c point origin = { . x = 0.0 , .y = 0.0
l o g i c triangle t_iso = { [0] = origin ,
// @
/* @
@
@
@ */
\length .
};
logic
/* @
point centroid ( triangle t ) = {
@
.x = mean3 (t [0]. x ,t [1]. x , t [2]. x );
@
.y = mean3 (t [0]. y ,t [1]. y , t [2]. y );
@ };
@ */
// @
/* @
@
@ */
\length (p )]))
Beware that because of the principle of only total functions in logic, t[i] can appear in ACSL
annotations even if i is outside the array bounds.
Functional updates
Syntax for functional update is similar to initialization of aggregate objects.
Example 2.13
{ t_iso
\with
26
\with
.x = 3.0 }
object
of an union
\with
\with
{ { object
.x = 3.0 }
.y = 2.0 } == { { object
==
\with
\with
.y = 2.0 }
.x = 3.0 }
same type. Then equality amounts the recursively check equality of elds. Equality of arrays
of dierent lengths returns false. Beware that equality of unions is also equality of all elds.
C aggregate types
C aggregates types (struct, union or array) naturally map to logic types, by recursively mapping their elds.
Example 2.14
s t r u c t S { i n t x; f l o a t y; i n t t [10]; };
// @ l o g i c i n t e g e r f( s t r u c t S s) = s.t [3];
// @ l o g i c s t r u c t S g( i n t e g e r n , s t r u c t S s)
= { s
\with
.x = (
i n t )n
};
logic struct S
i n t )n ,
/* @
@
.x = (
@
};
@ */
i n t e g e r n, i n t
f l o a t )0.0 ,
h(
.y = (
a [10]) = {
.t = a
Example 2.15
// @
logic
An explicit cast from an array type to a pointer type is allowed only for arrays that lies in C
memory. As in C, the result of the cast is the address of the rst element of the array (see
Section 2.2.6).
Conversely, an explicit cast from a pointer type to an array type or a structure type is allowed,
and acts as collecting the values it points to.
Subtyping and cast recursively applies to elds.
Example 2.16
27
::=
requires-clause terminates-clause ?
decreases-clause ? simple-clause
named-behavior completeness-clause
requires-clause
::=
requires predicate ;
terminates-clause
::=
terminates pred ;
decreases-clause
::=
decreases term
simple-clause
::=
|
assigns-clause | ensures-clause
allocation-clause | abrupt-clause-fn
assigns-clause
::=
assigns locations ;
locations
::=
location
location
::=
tset
ensures-clause
::=
ensures predicate ;
named-behavior
::=
behavior id : behavior-body
behavior-body
::=
assumes-clause
::=
assumes predicate ;
completeness-clause
::=
|
complete behaviors
disjoint behaviors
(,
for ident)? ;
location) | \nothing
id
(id
id ) )? ;
? ;
(, id ) )
(,
term
pred
::=
|
\old ( term )
\result
::=
\old ( pred )
old value
result of a function
Figure 2.6:
\old
s t r u c t { f l o a t u ,v; } p [10];
// @ a s s e r t centroid (( point [3]) p)
// @ a s s e r t perimeter (( point []) p)
Precisely, conversion of a pointer
array
and
\result
in terms
== ...
== ...
of type
[]
returns a logic
such that
length(t)
= (\block_length(p)
Allocation-clauses
28
Location
Section 2.7.3.
This section is organized as follows. First, the grammar for terms is extended with two new
constructs. Then Section 2.3.2 introduces simple contracts. Finally, Section 2.3.3 denes more
general contracts involving named behaviors.
decreases
The
terminates
and
Abrupt-clauses
to specify what happens when the function does not return normally but
allow
exits abruptly;
they
\old
and
\result
Post-conditions usually require to refer to both the function result and values in the pre-state.
Thus terms are extended with the following new constructs (shown in Figure 2.6).
\old (e)
\result
\old (e)
and
\result
to the pre-state.
returns
void .
In addition,
\result
ensures
C function parameters are obtained by value from actual parameters that mostly remain
unaltered by the function calls.
are dened such that they always refer implicitly to their values interpreted in the pre-state.
Thus,
\old
r e q u i r e s P1 ; r e q u i r e s P2 ; ...
assigns L1 ; assigns L2 ; ...
ensures E1 ; ensures E2 ; ...
/* @
@
@
@ */
1
2
3
4
The caller of the function must guarantee that it is called in a state where the property
holds.
All memory locations that are allocated in both the pre-state and the post-state
holds.
1 and
L1 L 2 . . .
Having multiple
L1 L2 . . .
The set
requires , assigns ,
or
ensures
Functions that allocate or free memory can be specied with additional clauses described in section 2.7.3.
29
/* @
@
@
@ */
If no clause
assigns
requires
is given, it defaults to
\true ,
ensures
clause. Giving no
clause means that locations assigned by the function are not specied, so the caller
has no information at all on this function's side eects. See Section 2.3.5 for more details on
default status of clauses.
Example 2.17
The following function is given a simple contract for computation of the in-
r e q u i r e s x >= 0;
ensures \ r e s u l t >= 0;
ensures \ r e s u l t * \ r e s u l t
ensures x < ( \ r e s u l t + 1)
int
i n t x );
/* @
@
@
@
@ */
isqrt (
<= x;
* (
\result
+ 1);
The contract means that the function must be called with a nonnegative argument, and returns
a value satisfying the conjunction of the three
the use of the construct
parameter
x,
\old (x)
ensures
ensures
clauses,
because function calls modify a copy of the eective parameters, and the eective
isqrt
calls which
has the same value interpreted in the pre-state than in the post-state.
Example 2.18
r e q u i r e s \valid (p );
assigns *p;
ensures *p == \old (* p)
void incrstar ( i n t *p );
/* @
@
@
@ */
+ 1;
The contract means that the function must be called with a pointer
allocated memory location (see Section 2.7 for details on the
does not modify any memory location but the one pointed to by
species that the value
*p
\valid
p.
Finally, the
ensures
It
clause
is incremented by one.
1
2
3
4
5
6
7
8
9
10
11
12
r e q u i r e s P;
behavior b 1 :
assumes A1 ;
r e q u i r e s R1 ;
assigns L1 ;
ensures E1 ;
behavior b 2 :
assumes A2 ;
r e q u i r e s R2 ;
assigns L2 ;
ensures E2 ;
/* @
@
@
@
@
@
@
@
@
@
@
@ */
30
The caller of the function must guarantee that the call is performed in a state where
the property
holds.
i,
requires
clauses in the behaviors are proposed mainly to improve readibility (to avoid some
duplication of formulas), since the contract above is equivalent to the following simplied one:
1
2
3
4
5
6
7
8
9
10
r e q u i r e s P &&
behavior b1 :
assumes A1 ;
assigns L1 ;
ensures E2 ;
behavior b2 :
assumes A2 ;
assigns L2 ;
ensures E2 ;
/* @
@
@
@
@
@
@
@
@
@ */
requires
/* @
P;
assigns
L;
ensures
E; */
1
2
3
4
5
6
r e q u i r e s P;
behavior < any name >:
assumes \true ;
assigns L;
ensures E;
/* @
@
@
@
@
@ */
Similarly, global
assigns
and
ensures
1
2
3
4
5
6
7
r e q u i r e s P;
assigns L;
ensures E;
behavior b1 :
behavior b2 :
/* @
@
@
@
@
@ ...
@ */
...
...
is equivalent to
1
2
3
4
5
6
7
8
9
r e q u i r e s P;
behavior < any name >:
assumes \true ;
assigns L;
ensures E;
behavior b1 : ...
behavior b2 : ...
/* @
@
@
@
@
@
@
@ ...
@ */
Example 2.19
indices
1
2
3
/* @
@
@
and
In the following,
n-1.
bsearch(t,n,v)
31
in array
between
behavior
ensures \ r e s u l t
\result
behavior
assumes
\forall integer
ensures \ r e s u l t
\forall integer
int
double
int
double
@
success :
@
>= 0 == > t[
] == v;
@
failure :
@
t_is_sorted :
k1 ,
k2 ;
@
0 <= k1 <= k2 <= n -1 == > t[ k1 ] <= t[ k2 ];
@
== -1 == >
@
k; 0 <= k < n == > t [k] != v;
@ */
bsearch (
t [] ,
n,
v );
integer
to
n-1.
behaviors correspond respectively to the successful behavior and the failing behavior.
Since the function is performing a binary search, it requires the array
creasing order: this is the purpose of the predicate named
of the behavior named
failure.
t_is_sorted
to be sorted in in-
in the
assumes
clause
Example 2.20
assigns
clauses
behavior p_changed :
assumes n > 0;
r e q u i r e s \valid (p );
assigns *p;
ensures *p == n ;
behavior q_changed :
assumes n <= 0;
r e q u i r e s \valid (q );
assigns *q;
ensures *q == n ;
void f( i n t n , i n t *p , i n t
i f (n > 0) *p = n; e l s e
/* @
@
@
@
@
@
@
@
@
@
@ */
}
*q) {
*q = n;
or by
q,
n.
Completeness of behaviors
In a contract with named behaviors, it is not required that the disjunction of the
Ai
is true,
i.e. it is not mandatory to provide a complete set of behaviors. If such a condition is seeked,
it is possible to add the following clause to a contract:
/* @ ...
@
@ */
complete behaviors
b 1 ,...,b n ;
b1 ,. . .,bn
R == > ( A 1 || A 2 || ... || A n )
holds, where
/* @ ...
@
@ */
complete behaviors ;
means that all behaviors given in the contract should be taken into account.
Similarly, it is not required that two distinct behaviors are disjoint. If desired, this can be
specied with the following clause:
32
pred
a the
::=
|
|
|
|
|
|
|
|
|
|
|
|
|
\empty
tset -> id
tset . id
* tset
& tset
tset [ tset ]
term? .. term?
\union ( tset (, tset) )
\inter ( tset (, tset) )
tset + tset
( tset )
{ tset | binders (; pred )? }
{ term }a
term
::=
empty set
range
union of locations
intersection
set comprehension
explicit singleton
implicit singleton
set inclusion
/* @ ...
@
@ */
d i s j o i n t behaviors
b 1 ,...,b n ;
It means that the given behaviors are pairwise disjoint i.e. that, for all distinct
and
j,
R == > ! (A i && A j )
holds. The simplied version of that clause
/* @ ...
@
@ */
d i s j o i n t behaviors ;
means that all behaviors given in the contract should be taken into account. Multiple
and
disjoint
complete
loop assigns
assigns
is then any set of terms denoting a set of l-values. Moreover, a location given as argument
to an
assigns
generally, we introduce syntactic constructs to denote sets of terms which are also usefull for
\separated
The grammar for sets of terms is given in Figure 2.7. The semantics is given below, where
denotes any
\empty
tset.
33
x->id
x.id
x s.
for each
for each
x s.
*s
*x
for each
x s.
&s
&x
for each
x s.
x1 [x2 ]
for each
s1 [s2 ]
t1 .. t2
same as
x1 s1
\empty
\union(s1 ,. . .,sn )
s1 +s2
(s)
x1 +x2
for each
t1
s1 ,s2 , . . .
and
and
and
t2 ,
included. If
t1 > t2 ,
this the
sn ;
s1 ,s2 , . . .
x1 s1
x2 s 2 .
and
and
sn ;
x2 s2 ;
s;
{ s | b ; P } denotes set comprehension, that is the union of the sets denoted by s for
each value b of binders satisfying predicate P (binders b are bound in both s and P).
Note that
assigns \nothing
Example 2.21
1
2
3
4
5
6
7
8
9
is equivalent to
/* @
@
@
@
@ */
{t[0],. . .,t[n-1]}
Example 2.22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
assigns \empty;
assigns
is modied.
s t r u c t list {
i n t hd ;
s t r u c t list
};
* next ;
inductive
case
case
\valid
struct
\forall struct
\forall struct
struct
requires
assigns
void
while
\null
struct
struct
34
::=
{ declaration
statement assertion+ }
statement
::=
assertion statement
assertion
::=
|
; */
The
assigns
clause species that the set of modied memory locations is the set of elds
reachable from
next
following
reachable.
q->hd
requires
On the other hand, a function may have no contract at all, or a contract with missing clauses.
Missing
requires
unspecied.
ensures
and
clauses default to
\true .
If no
assigns
If the function under consideration has only a declaration but no body, then
assigns
clause means in practice that it is left to tools to compute an over-approximation of the sets
of assigned locations.
Loop annotations:
while , for ,
and
invariant , assigns
do ... while.
clause,
2.4.1 Assertions
The syntax of assertions is given in Figure 2.8, as an extension of the grammar of C statements.
assert P
means that
must hold in the current state (the sequence point where the
assertion occurs).
The variant
idi ,
each of them being a behavior identier for the current function (or a behavior of
an enclosing block as dened later in Section 2.4.4). It means that this assertion must
hold only for the considered behaviors.
35
::=
|
/*@ loop-annot */
while ( expr ) statement
/*@ loop-annot */
for ( expr ; expr ; expr
statement
/*@ loop-annot */
do statement
while ( expr ) ;
loop-annot
::=
loop-clause loop-behavior
loop-variant?
loop-clause
::=
|
loop-invariant | loop-assigns
loop-allocation
loop-invariant
::=
loop-assigns
::=
loop-behavior
::=
for id
loop-variant
::=
|
(,
id ) : loop-clause
id
id
Loop-allocation
heap;
1
2
3
4
loop i n v a r i a n t I;
loop assigns L;
/* @
@
@ */
...
The predicate
for
The predicate
is also true, and if execution of the loop body in that state ends
continue
statement,
state. If the loop condition has side eects, these are included in the loop body in a
suitable way:
for a
while (c) s
loop,
36
followed by
s;
for a
by
for a
c.
step;
Note that if
has side-eects, the invariant might not be true at the exit of the loop:
c,
which
in the end evaluates to false and exits the loop. Likewise, if a loop is exited through a
break
statement,
state in which
does not necessarily hold, as side eects may occur between the last
break
statement.
At any loop iteration, any location that was allocated before entering the loop, and is
not member of
(interpreted in the current state) has the same value as before entering
loop assigns
L.
Loop behaviors
A loop annotation preceded by
behaviors
id_1,. . .,id_k
assumption of their
assumes
clauses.
Remarks
The
\old
\at
break
or
return
or
Example 2.23
requires
\valid
assigns \nothing
ensures
\result
behavior
ensures \ r e s u l t
\result
behavior
assumes
\forall integer
ensures \ r e s u l t
\forall integer
int
double
int
double
int
loop i n v a r i a n t
for
loop i n v a r i a n t
\forall integer
while
int
if
else if
e l s e return
return
/* @
n >= 0 &&
(t +(0.. n -1));
@
;
@
-1 <=
<= n -1;
@
success :
@
>= 0 == > t[
] == v;
@
failure :
@
t_is_sorted :
k1 ,
k2 ;
@
0 <= k1 <= k2 <= n -1 == > t[ k1 ] <= t [ k2 ];
@
== -1 == >
@
k; 0 <= k < n == > t [k] != v;
@ */
bsearch (
t [] ,
n,
v) {
l = 0, u = n -1;
/* @
0 <= l && u <= n -1;
@
failure :
@
k; 0 <= k < n && t[ k] == v == > l <= k <= u;
@ */
(l <= u ) {
m = l + (u -l )/2; // better than (l +u )/2
(t[ m] < v) l = m + 1;
(t[ m] > v) u = m - 1;
m;
}
-1;
}
37
int
::=
|
; */
Loop variants
Optionally, a loop annotation may include a loop variant of the form
/* @
where
loop variant
m; */
is a term of type
integer .
The semantics is as follows: for each loop iteration that terminates normally or with
the value of
continue ,
at end of the iteration must be smaller that its value at the beginning of the
iteration. Moreover, its value at the beginning of the iteration must be nonnegative. Note
that the value of
Example 2.24
1
2
3
4
5
6
void f( i n t x) {
// @ loop variant
while (x >= 0) {
x;
x -= 2;
It is also possible to specify termination orderings other than the usual order on integers,
using the additional
for
Such
Example 2.25
\lambda
In the following example, the natural invariant holds at this point (\max and
are introduced later in Section 2.6.7). It would be less convenient to set an invariant
/* @
@
@ */
v = t[i ++];
m = v > m ? v : m;
/* @
m ==
}
(i < n );
m;
invariant
while
return
\max (0 ,i -1 ,( \lambda i n t e g e r
gotos.
k ; t[k ]));
k ; t[k ])); */
38
assert .
it must be preserved
across a loop iteration. Several invariants are allowed at dierent places in a loop body. These
extensions are useful when dealing with complex control ows.
Example 2.26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
r e q u i r e s n > 0;
ensures \ r e s u l t == \max (0 ,n -1 , \lambda i n t e g e r k; t[k ]);
double max_array ( double t [] , i n t n) {
double m; i n t i =0;
goto L;
do {
i f (t[ i] > m) { L: m = t[i ]; }
/* @ i n v a r i a n t
@
0 <= i < n && m == \max (0 ,i , \lambda i n t e g e r k; t[k ]);
/* @
@
@ */
}
}
@ */
i ++;
while (i <
return m;
n );
i0
m < t[i]
m t[i]
do
m t[i]
inv
ii+1
i<n
in
The invariant is inductively preserved by the two paths that go from node inv to itself.
Example 2.27
1
2
3
4
5
6
7
8
9
int
int
The program
x = 0;
y = 10;
loop i n v a r i a n t
while (y > 0) {
/* @
@ */
x ++;
y - -;
39
1
2
3
4
5
6
7
8
9
x ++;
// @
y - -;
// @
= 0;
= 10;
(y > 0) {
invariant
invariant
0 <= y < 10
0 < x < 11 cannot
and executing x++.
since
while
1
2
3
4
5
6
x ++;
// @
y - -;
// @
0 <= y < 10
0 < x < 11
invariant
invariant
\at
id.
\at (e,id)
id
int , t,
id. It
t (and
in state at label
referring to the
The label
y>0
id,
and
since
y--;
(y > 0) {
after executing
state). Namely, if
t[0]
has changed
described in Section 2.12. This label must be declared in the same function as the occurrence
of
\at (e,id),
but unlike
gotos,
the label
id
the label
id
\at (e,id)
in the source;
These rules are exactly the same rules as for the visibility of local variables within C statements
(see [14], Section A11.1).
The label
Here
\at (e,Old).
where the annotation appears; and in all contracts, where it refers to the pre-state for
the
The label
Old
is visible in
assigns
and
ensures
and for statement contracts described below in Section 2.4.4), and refers to the pre-state
of this contract.
The label
Pre
40
The label
Post
is visible in
assigns
and
ensures
the post-state.
The label
LoopEntry
statement enclosed in a loop. It refers to the state just before entering that loop for the
rst time but after initialization took place in the case of a
(section 2.4.2). When
for
loop, as for
loop invariant
The label
a statement enclosed in a loop. It refers to the state at the beginning of the current step
of the loop (see section 2.4.2 for more details on what constitutes a loop step in presence
of side-eects in the condition). When
LoopCurrent
loop frees
assigns
and
ensures
Pre,
and any
Post.
\at
of formal parameters.
No logic label is visible in global logic declarations such as lemmas, axioms, denition of
predicate or logic functions.
Example 2.28
The code below implements the famous extended Euclid's algorithm for com-
and
such that
requires
behavior
ensures
/* @
x >= 0 && y >= 0;
@
bezoutProperty :
@
(* p )* x +(* q )* y ==
@ */
extended_Euclid (
x,
y,
a = 1, b = 0, c = 0, d = 1;
/* @
x >= 0 && y >= 0
@
bezoutProperty :
@
a*
(x , Pre )+ b *
(y , Pre ) ==
@
c*
(x , Pre )+ d *
(y , Pre ) ==
@
y;
@ */
(y > 0) {
r = x % y;
q = x / y;
ta = a , tb = b;
x = y; y = r;
a = c; b = d;
c = ta - c * q ; d = tb - d * q;
}
*p = a; *q = b;
x;
}
int
int
int
loop i n v a r i a n t
for
\at
\at
loop variant
while
int
int
int
\result;
int
i n t *p , i n t
*q) {
loop i n v a r i a n t
\at
x &&
\at
y ;
return
Example 2.29
41
\at
and labels:
::=
statement-contract
/*@ statement-contract
id )
*/ statement
for id (,
requires-clause
simple-clause-stmt named-behavior-stmt
:)?
::=
::=
|
simple-clause
allocation-clause | abrupt-clause-stmt
named-behavior-stmt
::=
behavior id : behavior-body-stmt
behavior-body-stmt
::=
assumes-clause
requires-clause simple-clause-stmt
simple-clause-stmt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int
int
i;
t [10];
ensures
// @
int
any ();
assigns
ensures
ensures
\let
\result
0 <=
<= 9;
\at
\old \at
/* @
i ,t[
(i , Post )];
@
@
t[ i] ==
(t[
(i , Here )]) + 1;
@
@
j = i; t[j] ==
(t[ j ]) + 1;
@ */
f () {
i = any ();
t[i ]++;
}
\old
void
ensures
The two
wrong because in
Also, the
assigns
\old (t[i]), i
clause
i,t[i]
t[i] == \old(t[i]) + 1
would be
n the pre-state.
t[i],
the value of
in the
pre-state is considered.
Example 2.30
1
2
3
4
5
6
7
8
9
10
i n t f ( i n t n) {
for ( i n t i = 0; i < n; i ++) {
/* @ a s s e r t \at (i , LoopInit ) == 0; */
i n t j = 0;
while (j ++ < i) {
/* @ a s s e r t \at (j , LoopInit ) == 0; */
/* @ a s s e r t \at (j , LoopCurrent ) + 1 ==
LoopEntry
and
LoopCurrent
j; */
decreases
for id:....
assumes
clause.
ensures clause does not constrain the post-state when the annotated statement is termigoto jumping out of it, by a break , continue or return statement, or by a call to the
nated by a
42
2.5. TERMINATION
exit
abrupt clauses
be used.
On the other hand, it is dierent with
assigns
clauses.
modied during the path execution, starting at the begining of the annoted statement and
leading to a
goto
Example 2.31
clause
1
2
3
4
5
6
7
8
assigns
ensures
/* @
@
@ */
if
assigns \nothing ;
The clause
ensures x==\old(x);
x;
x ==
assigns
clause.
holds:
\old (x );
(c) {
x ++;
L;
goto
L: ...
Allocation-clauses
heap;
2.5 Termination
The property of termination concerns both loops and recursive function calls. Termination
is guaranteed by attaching a measure function to each loop (aspect already addressed in
Section 2.4.2) and each recursive function.
and measures are compared using the usual ordering over integers (Section 2.5.1). It is also
possible to dene measures into other domains and/or using a dierent ordering relation
(Section 2.5.2).
// @
decreases
e;
// @
loop variant
e;
has type
integer .
dened by
Example 2.32
The clause
u-l
@ ...
@
...
loop variant
while
u -l; */
43
for .
For functions
it becomes
// @
decreases
for
R;
for
// @
loop variant
R;
and
must be relation on
that is a
// @
predicate
R( x , y)
Example 2.33
is a well-founded relation.
// @
int
// @
ensures \ r e s u l t
dummy ();
>= 0;
/* @
@
@
@
@
@ */
p2 ) =
// @
void
}
}
x - -; y = dummy ();
else
y - -;
decreases
f.
Example 2.34
(syntactically).
g is smaller
g is f itself.
(w.r.t
R)
must occur
44
Then,
in the
2.5. TERMINATION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
requires
decreases
int
int
if
return
return
/* @
n <= 12;
@
n;
@ */
fact (
n) {
(n <= 1)
1;
n * fact (n -1);
}
decreases n;
i n t fib ( i n t n) {
i f (n <= 1) return 1;
return fib (n -1) + fib (n -2);
// @
Example 2.35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* @
r e q u i r e s n >=0;
decreases n;
*/
i n t even ( i n t n) {
i f (n == 0) return
return odd (n -1);
1;
/* @
r e q u i r e s x >=0;
decreases x;
*/
i n t odd ( i n t x) {
i f (x == 0) return
return even (x -1);
0;
while (1)
main function
More generally, a function can be expected to terminate only if some preconditions are met.
In those cases, a
terminates
following form:
// @
terminates
p;
terminate (more precisely, its termination must be proved). If such a clause is not present (and
in particular if there is no function contract at all), it defaults to
function is supposed to always terminate, which is the expected behavior of most functions.
Note that nothing is specied for the case where
or not. In particular,
terminates \false ;
1
2
3
4
ensures \ f a l s e ;
terminates \ f a l s e ;
*/
void f () { while (1); }
/* @
45
::=
/*@ logic-def +
logic-def
::=
|
|
|
logic-const-def
logic-function-def
predicate-def
lemma-def
type-var
::=
id
type-expr
::=
|
type-var
id
< type-expr
>
(, type-expr )
type-var-binders
::=
type variable
polymorphic type
< type-var
(,
poly-id
*/
type-var ) >
::=
|
id
id type-var-binders
logic-const-def
::=
logic type-expr
poly-id = term ;
logic-function-def
::=
logic type-expr
poly-id parameters =
term ;
predicate-def
::=
predicate
poly-id parameters ? =
pred ;
parameters
::=
( parameter
(,
normal identier
polymorphic object identier
parameter ) )
parameter
::=
type-expr id
lemma-decl
::=
lemma poly-id :
pred ;
Example 2.36
incr_list
this function:
1
2
3
4
5
6
7
8
// this time , the specification accepts circular lists , but does not ensure
// that the function terminates on them ( as a matter of fact , it does not ).
/* @
reachable (p ,
);
@
{ q -> hd |
list *q ; reachable (p ,q) } ;
@ */
incr_list (
list *p ) {
(p) { p -> hd ++ ; p = p -> next ; }
}
terminates
assigns
void
while
\null
struct
struct
46
::=
inductive-def
inductive-def
::=
inductive
poly-id parameters ? { indcase }
indcase
::=
The language of logic expressions used in annotations can be extended by declarations of new
logic types, and new constants, logic functions and predicates. These declarations follows the
classical setting of algebraic specications.
Figure 2.12.
Example 2.37
1
2
3
4
predicate
logic integer
integer
real
// @
is_positive (
x) = x > 0;
/* @
get_sign (
x) =
@
x > 0.0 ? 1 : ( x < 0.0 ? -1 : 0);
@ */
sign
is_positive
2.6.2 Lemmas
Lemmas are user-given propositions, a facility that might help theorem provers to establish
validity of ACSL specications.
Example 2.38
1
// @
lemma
mean_property :
\forall integer
1
2
3
4
5
6
inductive
case c 1
case c k
/* @
@
...
@
@ }
@ */
P(x 1 , . . . ,x n ) {
: p1 ;
: pk ;
47
ci
pi
is a proposition.
is the
smallest predicate (in the sense that it is false the most often) satisfying the propositions
p1 , . . . ,pk .
With this general form, the existence of a least xpoint is not guaranteed, so tools
might enforce syntactic conditions on the form of inductive denitions. A standard syntactic
restriction could be to allow only propositions
\forall
where
pi
h1 , . . . ,hl
wikipedia.org/wiki/Horn_clause).
Example 2.39
of the form
and
y.
inductive is_gcd ( i n t e g e r a , i n t e g e r
case gcd_zero :
\ f o r a l l i n t e g e r n; is_gcd (n ,0 , n );
case gcd_succ :
\ f o r a l l i n t e g e r a ,b ,d ; is_gcd (b , a
/* @
@
@
@
@
@ }
@ */
b,
isgcd(x,y,d)
integer
meaning that
http://en.
is the great-
d) {
% b , d) == > is_gcd (a ,b , d );
Example 2.40
LISP.
1
2
3
4
5
6
7
8
9
10
11
12
axiomatic IntList {
type int_list ;
l o g i c int_list nil ;
l o g i c int_list cons ( i n t e g e r n , int_list l );
l o g i c int_list append ( int_list l1 , int_list
axiom append_nil :
\ f o r a l l int_list l; append ( nil ,l) == l;
axiom append_cons :
\ f o r a l l i n t e g e r n , int_list l1 , l2 ;
/* @
@
@
@
@
@
@
@
@
@
@ }
@ */
l2 );
Like inductive denitions, there is no syntactic conditions which would guarantee axiomatic
denitions to be consistent. It is usually up to the user to ensure that the introduction of
axioms does not lead to a logical inconsistency.
Example 2.41
48
::=
axiomatic-decl
axiomatic-decl
::=
axiomatic id { logic-decl }
logic-decl
::=
|
|
|
|
|
logic-def
logic-type-decl
logic-const-decl
logic-predicate-decl
logic-function-decl
axiom-decl
logic-type-decl
::=
type logic-type ;
logic-type
::=
|
id
id type-var-binders
logic-const-decl
::=
logic type-expr
logic-function-decl
::=
logic type-expr
poly-id parameters ;
logic-predicate-decl
::=
predicate
poly-id parameters ? ;
axiom-decl
::=
polymorphic type
poly-id ;
axiomatic sign {
l o g i c i n t e g e r get_sign ( r e a l x );
axiom sign_pos : \ f o r a l l r e a l x;
axiom sign_neg : \ f o r a l l r e a l x;
/* @
@
@
@
@ }
@ */
1
2
3
4
5
6
sign(0.0) == 1
and
sign(0.0) == -1,
hence
-1 == 1
// @
type
list <char*>),
<real>
>2 ), etc.
The grammar of Figure 2.12 contains rules for declaring polymorphic types and using polymorphic type expressions.
In this latter case, note that the two '>' must be separated by a space, to avoid confusion with the shift
operator.
49
::=
|
ext-quantier
::=
|
abstraction
Declarations in the
same bunch of logic declarations are implicitly mutually recursive, so that mutually recursive
functions are possible too.
Example 2.42
1
2
3
4
logic integer
int
integer
/* @
max_index {L }(
t [] ,
@
(n ==0) ? 0 :
@
(t [n -1]==0) ? n : max_index (t , n -1);
@ */
n) =
between
and
n-1
such that
t[i]=0.
There is no syntactic condition on such recursive denitions, such as limitation to primitive recursion.
e is just a
\forall args; f(args) = e. In
curs in expression
Of course, tools
Abstraction
maps
The term
x1 , . . . ,xn
to
Extended quantiers
numof
\lambda 1 x1 ,. . .,n xn ; t
t.
are extended
denotes the
\forall
n-ary
and
\exists
Terms
unary function with an integer argument, and a numeric value (integer or real) except
\numof for which it should have a boolean value. Their meanings are given as follows:
\max(i,j,f) = max{ f ( i ), f ( i +1), . . . , f ( j )}
\min(i,j,f) = min{ f ( i ), f ( i +1), . . . , f ( j )}
\sum(i,j,f) = f ( i ) + f ( i +1) + + f ( j )
\product (i,j,f) = f ( i ) f ( i +1) f ( j )
\numof(i,j,f) = #{k | i k j f (k)}
=
\sum(i,j,\lambda integer k ; f(k) ? 1 : 0)
for
If
50
is 1, and
/* @
@
@ */
t[k ]);
k; t[k ]);
is available. Grammar rules for these additional constructions are given in Figure 2.16
Example 2.44
1
// @
type
The declaration
/* @
@
@
@
@
@ */
};
pointer dereferencing:
array access:
address-of operator:
*p, p->f;
t[i];
&x;
51
\valid
::=
type logic-type =
logic-type-def ;
logic-type-def
::=
|
record-type | sum-type
type-expr
record-type
::=
{ type-expr id
; type-expr id )
;?
sum-type
::=
|? constructor
( | constructor )
constructor
::=
|
id
id
type-expr
term
::=
::=
|
|
|
|
type abbreviation
constant constructor
( type-expr
(, type-expr )
( type-expr
+
(, type-expr )
non-constant constructor
product type
term . id
\match term
{ match-cases }
( term (, term)+ )
{ (. id = term ;)+ }
\let ( id (, id )+ ) =
term ; term
match-cases
::=
match-case +
match-case
::=
pat
::=
|
|
|
|
|
|
|
id
id ( pat
pat | pat
pat)
constant constructor
non-constant constructor
or pattern
any pattern
cst
{ (. id = pat) }
( pat ( , pat ) )
pat as id
numeric constant
record pattern
tuple pattern
pattern binding
poly-id
label-binders
::=
|
|
|
::=
id
id type-var-binders
id label-binders
id label-binders
type-var-binders
{ id
(,
normal identier
identier for polymorphic object
normal identier with labels
polymorphic identier with labels
id ) }
52
expressions, it is allowed to omit a label whenever there is only one label in the context.
Example 2.45
occurrences of a given double in a memory block storing doubles between the given indexes,
together with the related axioms. It should be noted that without labels, this axiomatization
would be inconsistent, since the function would not depend on the values stored in t, hence the
two last axioms would say both that
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
axiomatic
a==b+1
and
a==b
for some
and
b.
/* @
NbOcc {
@
// nb_occ (t ,i ,j ,e) gives the number of occurrences of e in t[i .. j]
@
// ( in a given memory state labelled L)
@
nb_occ {L }(
*t ,
i,
j,
@
e );
@
nb_occ_empty {L }:
@
*t , e ,
i, j;
@
i > j == > nb_occ (t ,i ,j ,e) == 0;
@
nb_occ_true {L }:
@
*t , e ,
i, j;
@
i <= j && t [j] == e == >
@
nb_occ (t ,i ,j ,e) == nb_occ (t ,i ,j -1 , e) + 1;
@
nb_occ_false {L }:
@
*t , e ,
i, j;
@
i <= j && t [j] != e == >
@
nb_occ (t ,i ,j ,e) == nb_occ (t ,i ,j -1 , e );
@ }
@ */
logic integer
axiom
\ f o r a l l double
axiom
\ f o r a l l double
double
double
integer
integer
integer
axiom
\ f o r a l l double
Example 2.46
integer
integer
This second example denes a predicate which indicates whether two memory
blocks of the same size are a permutation of each other. It illustrates the use of more than a
single label. Thus, the
\at
operator is mandatory here. Indeed the two blocks may come from
two distinct memory states. Typically, one of the post condition of a sorting function would
be
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
permut{Pre,Post}(t,t).
axiomatic
/* @
@ //
@ //
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@ }
@ */
Permut {
permut {L1 , L2 }( t1 , t2 ,n) is true whenever t1 [0.. n -1] in state L1
is a permutation of t2 [0.. n -1] in state L2
permut {L1 , L2 }(
*t1 ,
*t2 ,
n );
permut_refl {L }:
*t ,
n; permut {L ,L }(t ,t , n );
permut_sym { L1 , L2 } :
*t1 , *t2 ,
n;
permut {L1 , L2 }( t1 ,t2 , n) == > permut {L2 , L1 }( t2 ,t1 ,n) ;
permut_trans {L1 ,L2 , L3 } :
*t1 , *t2 , *t3 ,
n;
permut {L1 , L2 }( t1 ,t2 , n) && permut {L2 , L3 }( t2 ,t3 , n)
== > permut {L1 , L3 }( t1 ,t3 ,n ) ;
permut_exchange {L1 , L2 } :
*t1 , *t2 ,
i , j , n;
( t1 [i], L1 ) ==
( t2 [j], L2 ) &&
( t1 [j], L1 ) ==
( t2 [i], L2 ) &&
(
k; 0 <= k < n && k != i && k != j == >
( t1 [k], L1 ) ==
( t2 [k], L2 ))
== > permut {L1 , L2 }( t1 , t2 ,n );
predicate
axiom
\ f o r a l l double
axiom
\ f o r a l l double
axiom
\ f o r a l l double
double
integer
integer
double
integer
integer
axiom
\ f o r a l l double
integer
\at
\at
\at
\at
\forall integer
\at
\at
53
reads
clause
::=
logic-predicate-decl
::=
predicate poly-id
parameters ? reads-clause ;
reads-clause
::=
reads locations
logic-function-def
::=
logic-predicate-def
::=
predicate poly-id
parameters ? reads-clause = pred ;
reads
reads
clauses
which extends the one of Figure 2.12. This feature allows to specify the footprint of an hybrid
predicate or function, that is the set of memory locations which it depends on. From such
an information, one might deduce properties of the form
known that between states
L1
and
L2 ,
if it is
footprint.
Example 2.47
1
2
3
4
5
6
7
8
9
10
axiomatic
logic integer
reads
axiom
/* @
Nb_occ {
@
nb_occ {L }(
@
@
t[i .. j ];
@
@
nb_occ_empty {L }: // ...
@
@ // ...
@ }
@ */
double
double
*t ,
e)
integer
i,
integer
reads
clause.
j,
i..j,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* @ module List {
@
@
list <A > = Nil | Cons (A , list <A >);
@
@
length <A >( list <A > l) =
@
l {
@
Nil : 0
@
Cons (h ,t ) : 1+ length (t) } ;
@
@
A fold_right <A ,B >(( A -> B -> B) f , list <A > l , B acc ) =
@
l {
@
Nil : acc
@
Cons (h ,t ) : f(h , fold_right (f ,t , acc )) } ;
@
@
list <A > filter <A >(( A ->
) f , list <A > l) =
@
fold_right ((
A x , list <A > acc ;
@
f(x) ? Cons (x , acc ) : acc ), Nil ) ;
type
logic integer
\match
case
case
logic
\match
case
case
logic
\lambda
boolean
54
::=
|
|
|
|
\null
\base_addr one-label ? ( term )
\block_length one-label ? ( term )
\oset one-label ? ( term )
\allocation one-label ? ( term )
pred
::=
|
|
|
|
|
one-label
::=
{ id
two-labels
::=
{ id ,
id }
location-addresses
::=
location-address
location-address
::=
tset
(,
location-address )
19
20
21
@
@ }
@ */
List::length.
Predened algebraic specications can be provided as libraries (see section 3), and imported
using a construct like
// @ open List ;
list.acsl
List
module above.
Location-address
calloc, malloc
or
realloc
address, i.e. the address of the declared object (the rst declared object in case of an array
declarator), or the pointer returned by the allocating function (when the allocation succeed)
and their length.
ACSL provides the following built-in functions to deal with allocated blocks.
All of them
takes an optional label identier as argument. The default value of that label is dened in
Section 2.4.3.
55
valid if
*p
is said to be
\valid
s is safe at label
\valid {L}(\empty)
\valid {id} : set< *> boolean
\valid_read
L,
\valid {L}(s)
L.
*p
applies to a set of terms of some pointer type and holds if and only if it is
\valid {L}(s) implies \valid_read {L}(s) but the reverse is not true.
In particular, it is allowed
to read from a string literal, but not to write in it (see [13], 6.4.56).
The status of
Namely,
hand, if we ignore potential alignment constraints, the following equivalence is true for any
pointer
p:
\valid {L }( p)
and
<== >
\valid_read {L }( p)
*) p )+(0..
s i z e o f (* p )))
*) p )+(0..
s i z e o f (* p )))
\null
a shortcut for
( void *)0).
L.
Of course,
As in
In addition,
address
Again, if there is no alignment constraints, the following property holds: for any set of
pointers
and label
L, \valid_read {L}(s)
\ o f f s e t {L }( p)
>= 0 &&
\ o f f s e t {L }( p)
s i z e o f (* p)
ps:
<=
\block_length {L }( p)
2.7.2 Separation
ACSL provides a built-in function to deal with separation of locations:
56
::=
|
allocates dyn-allocation-addresses ;
frees dyn-allocation-addresses ;
loop-allocation
::=
|
dyn-allocation-addresses
::=
|
location-addresses
\nothing
\separated
applies
and
forall
== >
to
sets
of
terms
(see
Section
2.3.4)
s1
s2
and
0 <= j <
of
some
pointer
type.
ps1
s i z e o f (* q)
In fact,
Allocation-clauses
to
allocates \empty
and
allocates
and
frees
f r e e s P1 ,P2 ,...;
a l l o c a t e s Q1 ,Q2 ,...;
/* @
@
@ */
means that any memory address that does not belong to the union of sets of terms
Pi
and
Qj
one
is that sets
sets
Qi
Pi
/* @
type
*/
allocation_status =
|
|
\static
Built-in function
the label
allocation_status
L,
\register
\automatic
\allocation {L}(p)
the pointer
\dynamic
\ a l l o c a t i o n {L }( p)
==
\unallocated ;
and label
\ a l l o c a t i o n {L }( \base_addr (p ))
and
57
== > !
\valid_read {L }( p)
\ f o r a l l char * p ;
\separated ( \union (Q 1 ,. . . ,Qn ),p )== >
( \base_addr { Here }( p )== \base_addr { Pre }( p)
&& \block_length { Here }( p )== \block_length { Pre }( p)
&& \valid { Here }( p ) <== > \valid { Pre }( p)
&& \valid_read { Here }( p ) <== > \valid_read { Pre }( p)
&& \ a l l o c a t i o n { Here }( p )== \ a l l o c a t i o n { Pre }( p ))
allocation-clauses
assigns
\allocable {L}(p)
L,
to the base
and label
\ a l l o c a b l e {L }( p)
\freeable {L}(p)
<== > (
\ a l l o c a t i o n {L }( p )== \unallocated
and label
\ f r e e a b l e {L }( p)
\fresh {L0 ,L1 }(p,n)
<== > (
&& p ==
free.
\ a l l o c a t i o n {L }( p )== \dynamic
&& p ==
\base_addr {L }( p )).
L,
to an allocated
\base_addr {L }( p )).
and
<== > (
free
assigns \nothing ;
allocates \result;
ensures \ r e s u l t == \null
/* @
@
@
@ */
void
\ a l l o c a b l e {L 0 }( p) &&
\ f r e e a b l e {L 1 }( p) &&
\block_length {L 1 }( p )== n &&
\valid {L 1 }(( char *) p +(0.. n ))
||
* malloc ( size_t n );
/* @
@
@
@
@ */
Default labels for constructs dedicated to memory are such that logic label
58
Here
can be omitted.
\nothing .
given, the meaning is dierent for anonymous behaviors and named behaviors:
a named behavior without allocation clause does not specify anything about allocations
and deallocations. The allocated and deallocated memory blocks are in fact specied
by the anonymous behavior of the contract. There is no condition to verify for these
named behaviors about allocations and deallocations;
for an anonymous behavior, no allocation clause means that there is no newly allocated
nor deallocated memory block. That is equivalent to give
allocates \nothing .
These rules are such that contracts without any allocation clause should be considered as having only one
Example 2.49
assumption of
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
More precise specications can be given using named behaviors under the
assumes
clauses.
ghost i n t heap_status ;
axiomatic dynamic_allocation {
predicate is_allocable ( size_t n)
reads heap_status ;
// @
/* @
@
@
@ }
@ */
allocates \result;
behavior allocation :
assumes is_allocable (n );
assigns heap_status ;
ensures \fresh ( \result ,n );
behavior no_allocation :
assumes ! is_allocable ( n );
assigns \nothing ;
a l l o c a t e s \nothing ;
ensures \ r e s u l t == \null ;
complete behaviors ;
d i s j o i n t behaviors ;
/* @
@
@
@
@
@
@
@
@
@
@
@
@ */
void
* malloc ( size_t n );
f r e e s p;
behavior deallocation :
assumes p != \null ;
r e q u i r e s \ f r e e a b l e (p );
assigns heap_status ;
ensures \ a l l o c a b l e (p );
behavior no_deallocation :
assumes p == \null ;
assigns \nothing ;
frees
\nothing ;
complete behaviors ;
d i s j o i n t behaviors ;
void free ( void *p );
/* @
@
@
@
@
@
@
@
@
@
@
@
@ */
allocation
and
59
/* @
@
loop allocates
and
loop frees
loop f r e e s P1 ,P 2 ,...;
loop a l l o c a t e s Q1 ,Q 2 ,...;
*/
means that any memory address that does not belong to the union of sets of terms
Pi
and
Qi
has the same allocation status in the current state than before entering the loop. The only
dierence between these two clauses is that sets
the loop (label
LoopEntry),
Namely, as for
and
loop assigns ,
Qi
Pi
loop annotations
loop frees
and
loop allocates
LoopCurrent).
dene a loop
invariant.
More precisely, the following loop annotation:
// @
loop a l l o c a t e s
Q 1 ,...,Q n ; */
\ f o r a l l char * p ;
\separated ( \union (Q 1 ,. . . ,Qn ),p ) == >
( \base_addr { Here }( p )== \base_addr { LoopEntry }( p)
&& \block_length { Here }( p )== \block_length { LoopEntry }( p)
&& \valid { Here }( p ) <== > \valid { LoopEntry }( p)
&& \valid_read { Here }( p ) <== > \valid_read { LoopEntry }( p)
&& \ a l l o c a t i o n { Here }( p )== \ a l l o c a t i o n { LoopEntry }( p ))
Example 2.50
1
2
3
4
5
6
7
8
9
10
11
12
/* @
/* @
@
@
loop frees
The rst
loop frees
loop invariant
On
indicates that the remaining blocks have not been freed since the
free(q[i])
The
catches the set of the memory blocks that may have been released by the
q[0..n]
\freeable
assert ,
and
loop-clause without allocation clause implicitly contents loop allocates \nothing . That means
the allocation status is not modied by the loop body. A loop-behavior without allocation
clause means that the allocated and deallocated memory blocks are in fact specied by the
allocation clauses of the
loop-clauses
(Grammar of
in Figure 2.9).
60
loop-clauses
and
loop-behaviors
is given
set<A>
where
case,
the
set
is
of
type
Example 2.51
set<char*>
and
each
of
its
elements
is
In
converted
to
The following example denes the footprint of a structure, that is the set of
struct S {
char *x;
i n t *y;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
};
// @
/* @
@
@ */
/* @
*/
axiomatic Conv {
axiom conversion : \ f o r a l l s t r u c t S s;
footprint (s ) == \union (s.x ,( char *) s.y
set<char*>
+ (0 ..
sizeof (int)
set<char*>
and a
- 1));
the result is
(accordingly to typing of union). In other words, the two denitions above are
equivalent.
This logic function can be used as argument of
Thus, the
s2
of type
1
2
3
4
5
6
\separated
\separated
or
assigns
set<2 *>)
and a clause
assigns L1 ,. . .,Ln
\ f o r a l l char *
p;
s1
of type
set<1 *>
and
== >
clause.
== > *p ==
\old (* p)
ensures
clause of function and statement contracts does not constrain the post-state when
the annotated function and statement terminates respectively abruptly. In such cases,
clauses
simple clause
or
behavior body.
in Figure 2.21.
61
abrupt
::=
exits-clause
exits-clause
::=
exits predicate
abrupt-clauses-stmt
::=
|
exits-clause
breaks-clause | continues-clause | returns-clause
breaks-clause
::=
breaks predicate ;
continues-clause
::=
continues predicate ;
returns-clause
::=
returns predicate ;
term
::=
\exit_status
The clauses
breaks , continues
and
returns
state properties on the program state which hold when the annotated statement terminates
abruptly with the corresponding statement (
Inside these clauses, the construct
ensures , assigns
break , continue
or
return ).
the visibility in
same as
For the
Example 2.52
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
The
i n t f( i n t x) {
while (x > 0) {
/* @ breaks x % 11 == 0 && x == \old (x );
@ continues (x +1) % 11 != 0 && x % 7 == 0 && x == \old (x ) -1;
@ returns ( \ r e s u l t +2) % 11 != 0 && ( \ r e s u l t +1) % 7 != 0
@
&& \ r e s u l t % 5 == 0 && \ r e s u l t == \old (x ) -2;
@ ensures (x +3) % 11 != 0 && ( x +2) % 7 != 0 && (x +1) % 5 != 0
@
&& x == \old (x ) -3;
{
}
}
@ */
if
if
if
(x % 11 == 0)
x - -;
(x % 7 == 0)
x - -;
(x % 5 == 0)
x - -;
return
exits
x;
clause can be used in both function and statement contracts to give behavioral
properties to the
the
exit
break ;
continue ;
return x;
main
function or to any function that may exit the program, e.g. by calling
function.
\old (e) is allowed and denotes the value of e in the pre-state of the function
\exit_status is bound to the return code, e.g the value returned by main or
the argument passed to exit. The construct \exit_status can be used only in exits, assigns
and allocates clauses. On the contrary, \result cannot be used in exits clauses.
In such clauses,
or statement, and
62
::=
|
Example 2.53
main
exit
function:
assigns \nothing ;
ensures \ f a l s e ;
\exit_status == status ;
void
i n t status );
i n t status ;
/* @ assigns status ;
@ exits
! cond && \exit_status ==
@ */
void may_exit ( i n t cond , i n t val ) {
i f (! cond ) {
/* @
@
@ exits
@ */
exit (
status = val ;
exit (1);
}
status
may_exit
between the exit case and the normal case, as in the following specication:
8
9
10
11
12
13
14
15
16
17
18
behavior
assumes
assigns
behavior
assumes
assigns
ensures
/* @
no_exit :
@
cond ;
@
;
@
exits
;
@
no_return :
@
! cond ;
@
status ;
@
exits
@
;
@ */
may_exit (
cond ,
void
Contrary to
ensures
\nothing
\false
\exit_status == 1 &&
\false
int
i n t val ) ;
clauses,
assigns
status == val ;
allocates
and
frees
contracts constrain the post-state even when the annotated function and statement terminates
respectively abruptly. This is shown in example 2.53 for a function contract.
assigns
\from
involved in the computation of the modied values must be present, but some of locations
might not be used in practice. If the
\from
the given point of the program are supposed to be used. Moreover, for a single location, it is
63
Example 2.54
array_sum function
total.
in exam-
ple 2.43, in which the values of the array are added to a global variable
1
2
3
4
5
6
7
8
9
10
11
k; t[k ]);
Example 2.55
The composite element modier operators can be useful for writing such func-
tional expressions.
1
2
3
4
5
6
7
8
9
10
11
} };
global invariants and type invariants: the former only apply to specied global variables,
whereas the latter are associated to a static type, and apply to any variables of the
corresponding type;
during program execution (more precisely at any sequence point as dened in the C
standard), whereas weak invariants must be valid at function boundaries (function entrance and exit) but can be violated in between.
The syntax for declaring data invariants is given in Figure 2.23. The strength modier defaults
to
weak.
Example 2.56
positive (weakly, so this property might be violated temporarily between functions calls);
2. a strong type invariant for variables of type
64
temperature;
::=
/*@ data-inv-decl
data-inv-decl
::=
data-invariant | type-invariant
data-invariant
::=
inv-strength? global
id : pred ;
type-invariant
::=
inv-strength
::=
weak |
*/
invariant
strong
int
struct S.
a;
@
t >= -273.15 ;
@ */
struct S {
i n t f;
};
// @ type i n v a r i a n t
S_f_is_positive (
struct
t) =
S s ) = s.f >= 0 ;
2.11.1 Semantics
The distinction between strong and weak invariants has to do with the sequence points where
the property is supposed to hold. The distinction between global and type invariants has to
do with the set of values on which they are supposed to hold.
Weak global invariants are properties which apply to global data and hold at any function entrance and function exit.
Strong global invariants are properties which apply to global data and hold at any step
during execution (starting after initialization of these data).
If the result of
the result must also satisfy its weak invariant at function exit.
However, it says nothing about elds, array elements, memory locations, etc. of type
any global variable, local variable, or formal parameter with static type
of the function has type
If the result
exit. Again, it says nothing about elds, array elements, memory locations, etc. of type
Example 2.57
The following example illustrates the use of a data invariant on a local static
variable.
65
Example 2.58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
typedef enum
type i n v a r i a n t
/* @
@
(
@
@
@
&&
@
@
@ &&
@
@
@ */
/* @
@
@
@ */
t[i ] = t[j ];
t[j ] = tmp ;
typedef s t r u c t
i n t n;
flag {
color * colors ;
} flag ;
/* @
@
f. n >= 0 &&
@
@ */
/* @
@
@
@ */
j,
/* @
@
@
@
@
@
@
@ */
r;
isMonochrome ( f. colors ,0 ,b -1 , BLUE ) &&
isMonochrome ( f. colors ,b ,r -1 , WHITE ) &&
isMonochrome ( f. colors ,r , f.n -1 , RED ) &&
permut { Old , Here }( f . colors ,f. colors ,f.n -1);
66
@
permut { Pre , Here }( t ,t ,f.n -1);
@
b ,i ,r ,t [0 .. f .n -1];
@
r - i;
@ */
(i < r) {
(t[ i ]) {
BLUE :
swap (t , b ++ , i ++);
;
WHITE :
i ++;
;
RED :
swap (t , --r , i );
;
}
loop assigns
loop variant
while
switch
case
break
case
break
case
break
}
model.
Its type
must be a logic type. Analogously, types may have model elds. These are used to provide
abstract specications to functions whose concrete implementation must remain private.
The precise syntax for declaring model variables and elds is given in Figure 2.24.
It is
Model variables can only appear in specications. They are not lvalues, thus they cannot
be assigned directly (unlike ghost variables, see below).
Thus, in practice, the only way to prove that a function body satises a contract with model
variables is to provide an invariant relating model variables and concrete variables, as in the
example below.
Model elds behave the same, but they are attached to any value whose static type is the one
of the model declaration. A model eld can be attached to any C type, not only to
struct.
When it is attached to a compound type, however, it must not have the same name as a C
eld of the corresponding type. In addition, model elds are inherited by a
declaration
::=
|
|
C-declaration
/*@ model parameter ; */
/*@ model C-type { parameter ;? } ; */
typedef
model variable
model eld
67
in the
m1,
while
typedef i n t t1 ;
typedef t1 t2 ;
/* @ model t1 { i n t
/* @ model t2 { i n t
1
2
3
4
Example 2.59
t2
m1
and
m2.
t1
has
m1 }; */
m2 }; */
integers. The contract is given in term of a model variable which is intended to represent the
set of forbidden values, e.g. the values that have already been generated.
/* public interface */
1
2
3
4
5
6
7
8
9
// @
/* @
@
@
@ */
gen ();
int
the value returned is not in the set of forbidden values, thus it is fresh;
the new set of forbidden values contains both the value returned and the previous forbidden values.
An implementation of this function might be as follows, where a decision has been made to
generate values in increasing order, so that it is sucient to record the last value generated.
This decision is made explicit by an invariant.
1
2
3
4
5
6
7
8
/* implementation */
gen () {
x = 0;
/* @
I:
k;
@
Set :: mem (k , forbidden ) == > x > k;
@ */
x ++;
}
int
static int
global i n v a r i a n t
\forall integer
return
Remarks
Although the syntax of model variables is close to JML model variables, they
dier in the sense that the type of a model variable is a logic type, not a C type. Also, the
semantics above is closer to the one of B machines [1].
verication with model variables does not have a well-established theoretical background [20,
18], so we deliberately do not provide a precise semantics in this document .
or
ghost
68
denition is given in the gure represents the corresponding C-non-term entry, in which any
// and extend until the end of the line (the ghost code
/* ... */ would thus lead to incorrect C code).
It is however possible to write multi-line annotations for ghost code. These annotations
are enclosed between
/@
and
@/.
As in normal annotations,
integer
real
@/)
@s
A non-ghost function can take ghost parameters. If such a ghost clause is present in the
or
declarator, then the list of ghost parameters must be non-empty and xed (no vararg
ghost).
The call to the function must then provide the appropriate number of ghost
parameters.
switch
else
default : clause
if it does not have a non-ghost one (there are however semantical restrictions for valid
ghost labelled statements in a switch, see next paragraph for details).
Informally, the semantics requires that ghost statements do not change the regular program
execution
If
assign
*p.
Body of a ghost function is ghost code, hence do not modify non-ghost variables or
elds.
If a non-ghost C function is called in ghost code, it must not modify non-ghost variables
or elds.
sizeof
return
enclosing block.
In
69
::=
|
C-type-specier
logic-type-name
declaration
::=
|
C-declaration
/*@ ghost
ghost-declaration */
direct-declarator
::=
|
C-direct-declarator
direct-declarator
( parameter-type-list? )
/*@ ghost
( parameter-list )
*/
postx-expression
::=
|
ghost args
C-postx-expression
postx-expression
( argument-expression-list? )
/*@ ghost
( argument-expression-list )
*/
statement
::=
|
C-statement
statements-ghost
statements-ghost
::=
/*@ ghost
ghost-selection-statement
::=
|
C-selection-statement
if ( expression )
statement
/*@ ghost else
C-statement+
ghost-statement+ */
*/
struct-declaration
::=
|
C-struct-declaration
/*@ ghost
C-struct-declaration */
ghost eld
Semantics is specied as follows. First, the execution of a program with ghost code involves
a ghost memory heap and a ghost stack, disjoint from the regular heap and stack.
Ghost
variables lie in the ghost heap, so as the ghost eld of structures. Thus, every memory sideeect can be classied as ghost or non-ghost. Then, the semantics is that memory side-eects
of ghost code must always be in the ghost heap or the ghost stack.
Notice that this semantics is not statically decidable. It is left to tools to provide approximations, correct in the sense that any code statically detected as ghost must be semantically
ghost.
Example 2.60
1
2
void
f(
int
x,
int
*q) {
70
ghost i n t
ghost
// @
*p = q;
// @
*p = 0;
// above assignment is wrong : it modifies *q which lies
// in regular memory heap
ghost
ghost
// @
p = &x;
// @
*p = 0;
// above assignment is wrong : it modifies x which lies
// in regular memory stack
}
Example 2.61
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
i n t f ( i n t x , i n t y) {
// @ ghost i n t z = x + y;
switch (x) {
case 0: return y;
// @ ghost case 1: z=y ;
// above statement is correct .
// @ ghost case 2: { z ++; break ; }
// invalid , would bypass the non - ghost
d ef au lt : y ++;
}
return y;
default
i n t g( i n t x) {
// @ ghost i n t z = x;
i f (x > 0) { return x; }
// @ ghost e l s e { z ++; return
// invalid , would bypass the
return x +1;
x; }
non - ghost return
A ghost variable is an
additional specication variable which is assigned in ghost code like any C variable. On the
other hand, a model variable cannot be assigned, but one can state it is modied and can
express properties about the new value, in a non-deterministic way, using logic assertions and
invariants. In other words, specications using ghost variable assignments are executable.
Example 2.62
The example 2.59 can also be specied with a ghost variable instead of a model
variable:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// @
/* @
@
@
@ */
i n t gen () {
s t a t i c i n t x = 0;
/* @ global i n v a r i a n t I: \ f o r a l l i n t e g e r
@
\subset (k , forbidden ) == > x > k;
@ */
x ++;
// @
ghost
return x;
forbidden =
k;
\union (x , forbidden );
71
declaration
::=
//@
volatile locations
reads id )?
(writes
id )?
1
2
v o l a t i l e x;
// @ v o l a t i l e x reads
where
3
4
f(
g(
and
f writes g;
volatile
volatile
* p );
* p , v );
This must be understood as a special construct to instrument the C code, where each access
to the variable
replaced by
Example 2.63
of variable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
x,
volatile
construct.
The following code is instrumented in order to inject xed values at each read
v o l a t i l e i n t x;
/* @ ghost // @ r e q u i r e s p == &x ;
@ i n t reads_x ( v o l a t i l e i n t *p) {
@
s t a t i c i n t injector_x [] = { 1, 2, 3 };
@
s t a t i c i n t injector_count = 0;
@
i f (p == & x)
@
return injector_x [ injector_count ++];
@
else
@
return 0; // should not happen
@ }
@ */
// @
// @
/* @
@
@
@
@
@
@ }
@ */
// @
/* @
@
@ */
main () {
i , sum = 0;
= v;
writes_x ;
collector_x [2] == 2;
int
int
72
for
}
}
(i =0 ; i < 3; i ++) {
sum += x;
x = i;
return
sum ;
Example 2.64
1
2
3
4
5
6
7
L.
i n t f( i n t n) {
i n t x;
i f (n > 0) x = n ; e l s e x = -n;
// @ a s s e r t \ i n i t i a l i z e d { Here }(& x );
return x;
{Here}
can be omitted.
L:
(that is, the value is not the address of a local variable refered to outside of its scope).
Example 2.65
1
2
3
4
5
6
7
8
9
10
11
i n t * f ()
i n t a;
return
{
&a;
i n t * g () {
i n t * p = f ();
// @ a s s e r t \ s p e c i f i e d { Here }( p );
return p +1;
73
Chapter 3
Libraries
Disclaimer: this chapter is unnished, it is left here to give an idea of what it will look like in
the nal document.
This chapter is devoted to libraries of specication, built upon the ACSL specication language. Section 3.2 describes additional predicates introduced by the Jessie plugin of Frama-C,
to propose a slightly higher level of annotation.
abs, exp, power, log, sin, cos, atan, etc. over reals
isFinite predicate over oats and doubles (means not NaN nor innity)
75
CHAPTER 3. LIBRARIES
compatible with pointer casts or unions (although there is ongoing work to support some of
them [21]). As a consequence, a valid pointer of some type
block which contains values of type
/* @
@
@
@/
1
2
3
4
\oset_min {L}(p)
L.
\oset_max{L}(p)
L.
*p );
*p );
such that
(p+i)
such that
(p+i)
1
2
\offset_min {L }( p+i)
\offset_max {L }( p+i)
==
==
\offset_min {L }( p)-i
\offset_max {L }( p)-i
1
2
3
4
/* @
j) =
*/
and
the
ACSL
built-in
\valid_range {L}(p,a,b).
\valid {L}(p+(a..b))
predicate
is
now
equivalent
to
3.2.2 Strings
ExperimentalThe logic function
// @
l o g i c i n t e g e r \ s t r l e n ( char *
p );
denotes the length of a 0-terminated C string. It is a total function, whose value is nonnegative
if and only if the pointer in argument is really a string.
Example 3.1
1
2
3
4
5
6
7
8
9
10
/*
//
@
@ //
@
@ //
@
@
@
@ */
*
strcpy
function:
76
src [k ];
77
Chapter 4
Conclusion
This document presents a Behavioral Interface Specication Language for ANSI C source
code. It provides a common basis that could be shared among several tools. The specication
language described here is intended to evolve in the future, and remain open to additional
constructions.
sense, such as liveness properties, which can sometimes be simulated by regular specications
with ghost variables [12], or properties on evolution of data over the time, such as the history
constraints of JML, or in the Lustre assertion language.
79
Appendix A
Appendices
A.1 Glossary
pure expressions
++
or
--,
volatile object. The set of pure expression is a subset of the set of C expressions without
side eect (C standard [14, 13], 5.1.2.3, alinea 2).
left-values
A left-value (lvalue for short) is an expression which denotes some place in the
memory during program execution, either on the stack, on the heap, or in the static
data segment. It can be either a variable identier or an expression of the form
e.id
or
e->id,
where
id
*e, e[e],
const
explicit length.
For a given function call, the pre-state denotes the program state
at the beginning of the call, including the current values for the function parameters.
The post-state denotes the program state at the return of the call.
function behavior
the pre-state and the post-state for a possibly restricted set of pre-states (behavior
assumptions ).
function contract
ACSL is a BISL for C, a low-level structured language, while JML is a BISL for Java, an
object-oriented inheritance-based high-level language. Not only the language features
81
APPENDIX A. APPENDICES
are not the same but the programming styles and idioms are very dierent, which
entails also dierent ways of specifying behaviors. In particular, C has no inheritance
nor exceptions, and no language support for the simplest properties on memory (e.g,
the size of an allocated memory block).
JML relies on runtime assertion checking (RAC) when typing, static analysis and automatic deductive verication fail.
spec_public
clauses, etc), that are necessary to express the desired inheritance-related specications while
respecting visibility and modularity. Since C has no inheritance, these intricacies are avoided
in ACSL.
Example A.1
as follows: On a domain error, [...] the integer expression errno acquires the value EDOM.
Example A.2
follows: The fclose function returns [...] EOF if any errors were detected.
Example A.3
occured.
Example A.4
signal errors as follows: If the space cannot be allocated, a null pointer is returned.
82
/* @
ensures \ r e s u l t
== error_value || normal_postcondition ; */
1
2
3
4
5
6
s t a t i c void
if
return
for i n t
a.length
a,
it could easily be
char
a.
public
Java_nullify (
[] a) {
(a == null )
;
(
i = 0; i < a. length ; ++ i) {
a[i ] = 0;
}
}
On the contrary, the precondition of the same function in C, whose denition follows, is more
involved. First, remark that the C programmer has to add an extra argument for the size of
the array, or rather a lower bound on this array size.
1
2
3
4
5
6
7
n) {
a[i ] = 0;
/* @
r e q u i r e s \valid (a
+ 0..( n -1)); */
\valid is the one dened in Section 2.7.1. (note that \valid (a + 0..(-1))
\valid (\empty) and thus is true regardless of the validity of a itself ). When n
where predicate
the same as
null,
n.
is strictly positive,
is
is
must point to an
specication:
/* @
requires
n == 0 ||
\valid (a
+ 0..( n -1)); */
Usually, many memory requirements are only necessary for some paths through the function,
which correspond to some particular behaviors, selected according to some tests performed
along the corresponding paths. Since C has no memory primitives, these tests involve other
variables that the C programmer added to track additional information, like
To make it easier, it is possible in ACSL to distinguish between the
n in our example.
that species the tests that need to succeed for this behavior to apply, and the
that species the additional preconditions that must be true when a behavior applies. The
specication for our example can then be translated into:
1
2
3
4
5
6
behavior n_is_null :
assumes n == 0;
behavior n_is_not_null :
assumes n > 0;
r e q u i r e s \valid (a + 0..( n -1));
/* @
@
@
@
@
@ */
83
APPENDIX A. APPENDICES
This is equivalent to the previous requirement, except here behaviors can be completed with
postconditions that belong to one behavior only.
for a function do not necessarily cover all cases of use for this function, as mentioned in
Section 2.3.3.
This allows for partial specications, whereas JML behaviors cannot oer
such exibility.
unsigned int ,
Here, Our two behaviors are clearly mutually exclusive, and, since
is an
our they cover all the possible cases. We could have specied that as well, by
1
2
3
4
@ ...
@
@
@ */
d i s j o i n t behaviors ;
complete behaviors ;
requires
and
ensures
ensures
requires
and
clauses. Although it is not possible in JML to mix both styles, we can dene here
what it would mean to have both, by conjoining the conditions on the pre- and the post-state.
Here is an hypothetical JML contract mixing lightweight and heavyweight styles:
1
2
3
4
5
6
7
8
9
10
11
12
13
r e q u i r e s P1 ;
r e q u i r e s P2 ;
ensures Q1 ;
ensures Q2 ;
behavior x1 :
r e q u i r e s A1 ;
r e q u i r e s R1 ;
ensures E1 ;
behavior x2 :
r e q u i r e s A2 ;
r e q u i r e s R2 ;
ensures E2 ;
/* @
@
@
@
@
@
@
@
@
@
@
@
@ */
Q1 && Q2 &&
(
( A1 && R1 ) == > E1 ) && (
\old
\old ( A2
&& R2 ) == > E2 )
1
2
3
4
5
6
7
8
9
10
11
12
13
r e q u i r e s P1 ;
r e q u i r e s P2 ;
ensures Q1 ;
ensures Q2 ;
behavior x1 :
assumes A1 ;
r e q u i r e s R1 ;
ensures E1 ;
behavior x2 :
assumes A2 ;
r e q u i r e s R2 ;
ensures E2 ;
/* @
@
@
@
@
@
@
@
@
@
@
@
@ */
84
assumes
clauses. Its translation to assume-guarantee is however quite dierent. It assumes from the
pre-state the condition:
Q1 && Q2 && (
\old ( A1 )
== > E1 ) && (
\old (A2 )
== > E2 )
Thus, ACSL allows to distinguish between the clauses that control which behavior is active
assumes clauses) and the clauses that are preconditions for a particular behavior (the
internal requires clauses). In addition, as mentioned above, there is by default no requirement
(the
in ACSL for the specication to be complete (The last part of the JML condition on the prestate). If desired, this has to be precised explicitly with a
complete behaviors
clause as seen in
Section 2.3.3.
This is certainly
understandable when relying on RAC: methods called should be dened so that the runtime
can call them, and they should not have side-eects in order not to pollute the program they
are supposed to annotate.
In our setting, it is desirable to allow calls to logical functions in specications. These functions
may be dened, like program ones, but they may also be only declared (with a suitable
declaration of
reads
85
APPENDIX A. APPENDICES
JML
ACSL
modiable,assignable
assigns
measured_by
decreases
loop_invariant
loop invariant
decreases
loop variant
( \forall x ; P ; Q)
( \exists x ; P ; Q)
\max x ; a <= x <= b ; f)
( \forall x ; P ==> Q)
( \exists x ; P && Q)
\max(a,b,\lambda x ; f)
if
`e:
` e : integer
signed or unsigned
Variables:
` id :
id :
if
` t : integer
` op t : integer
Boolean negation:
Pointer dereferencing:
Address operator:
Binary
if
op {+, , }
` t : boolean
`! t : boolean
` t :
` t :
`t:
` &t :
` t1 : integer
` t2 : integer
` t1 op t2 : integer
` t1 : real
` t2 :
` t1 op t2 : real
real
` t1 : integer
` t2 : integer
` t1 op t2 : boolean
` t1 : real
` t2 : real
` t1 op t2 : boolean
if
if
if
if
op {+, , , /, %}
op {+, , , /}
86
if
(to be continued)
, ` s : , b
meaning that
is true.
is
, ` id : , true
, ` id : , true
if
id :
if
id :
, ` s : , b
, ` s : , true
id : s : set < struct S >
` s > id : set < >
, b ` e : tset
, ` {e | b; P } : tset
, ` e1 : , b , ` e2 : , b
, ` e1 , e2 : , b
1
2
3
4
5
6
7
8
i n t x;
assigns x;
i n t g ();
i n t f( i n t x) {
// ...
return g ();
// @
assigns clause for f, we must access the global variable x, since f calls
g, which can modify x. This is not possible with C scoping rules, as x refers to the parameter
of f in the scope of the function.
In order to write the
x,
87
APPENDIX A. APPENDICES
1
2
3
4
5
6
7
8
9
10
11
12
int
// @
// @
int
x;
ghost i n t * const
assigns x;
ghost_ptr_x = &x;
g ();
assigns * ghost_ptr_x ;
i n t f( i n t x) {
// ...
return g ();
// @
memory_free,
memory_alloc
as possible of ACSL.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
and
@
1 + list_length ( next_elem , next_elem ( ptr )) ;
@
@
@
lower_length <A >(( A* -> A *) next_elem ,
@
A* ptr1 , A* ptr2 ) =
@
finite_list ( next_elem , ptr1 ) && finite_list ( next_elem , ptr2 )
@
&& list_length ( next_elem , ptr1 ) < list_length ( next_elem , ptr2 ) ;
@ */
predicate
// forward reference
_memory_slice ;
struct
typedef s t r u c t
ghost boolean
unsigned i n t
unsigned i n t
unsigned i n t
char
struct
data
88
strong type i n v a r i a n t
/* @
inv_memory_block ( memory_block mb ) =
@
mb . packed == >
@
(0 < mb . size && mb . used <= mb . next <= mb . size
@
&&
( mb .
) == 0
@
&&
( mb .
) == mb . size ) ;
@
@
valid_memory_block ( memory_block * mb ) =
@
( mb ) && mb -> packed ;
@ */
\offset
data
\block_length
data
predicate
\valid
typedef s t r u c t
ghost boolean
unsigned i n t
unsigned i n t
char
data
strong type i n v a r i a n t
/* @
inv_memory_chunk ( memory_chunk mc ) =
@
mc . packed == >
@
(0 < mc . size && valid_memory_block ( mc . block )
@
&& mc . offset + mc . size <= mc . block -> next ) ;
@
@
valid_memory_chunk ( memory_chunk * mc ,
s) =
@
( mc ) && mc -> packed && mc -> size == s ;
@
@
used_memory_chunk ( memory_chunk mc ) =
@
mc . free == false ;
@
@
freed_memory_chunk ( memory_chunk mc ) =
@
mc . free == true ;
@ */
predicate
\valid
predicate
int
predicate
/* A memory chunk list links memory chunks in the same memory block .
* Newly allocated chunks are put first , so that the offset of chunks
* decreases when following the [ next ] pointer . Allocated chunks should
* fill the memory block up to its own [ next ] index .
*/
_memory_chunk_list {
memory_chunk *
chunk ;
// current list element
_memory_chunk_list * next ;
// tail of the list
} memory_chunk_list ;
typedef s t r u c t
struct
/* @
@
@
@
@
@
@
@
@
@
@
@
logic
predicate valid_memory_chunk_list
( memory_chunk_list * mcl , memory_block * mb ) =
\valid ( mcl ) && valid_memory_chunk ( mcl -> chunk , mcl -> chunk - > size )
&& mcl - > chunk -> block == mb
&& ( mcl -> next == \null ||
valid_memory_chunk_list ( mcl -> next , mb ))
&& mcl - > offset == mcl -> chunk -> offset
&& (
// it is the last chunk in the list
89
APPENDIX A. APPENDICES
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@ */
||
\null
\null
)
&& finite_list ( next_chunk , mcl ) ;
predicate
valid_complete_chunk_list
( memory_chunk_list * mcl , memory_block * mb ) =
valid_memory_chunk_list ( mcl , mb )
&& mcl -> next -> chunk -> offset +
mcl -> next -> chunk -> size == mb -> next ;
predicate
/* A memory slice holds together a memory block [ block ] and a list of chunks
* [ chunks ] on this memory block .
*/
_memory_slice {
// @
packed ;
// ghost field [ packed ] is meant to be used as a guard that tells when
// the invariant of a structure of type [ memory_slice ] holds
memory_block *
block ;
memory_chunk_list * chunks ;
} memory_slice ;
typedef s t r u c t
ghost boolean
strong type i n v a r i a n t
/* @
inv_memory_slice ( memory_slice * ms ) =
@
ms . packed == >
@
( valid_memory_block ( ms -> block ) && ms -> block -> slice == ms
@
&& (ms -> chunks ==
@
|| valid_complete_chunk_list (ms -> chunks , ms -> block ))) ;
@
@
valid_memory_slice ( memory_slice * ms ) =
@
( ms ) && ms -> packed ;
@ */
\null
predicate
\valid
typedef s t r u c t
ghost boolean
struct
logic
/* @
memory_slice_list * next_slice ( memory_slice_list * ptr ) =
@
ptr -> next ;
@
@
inv_memory_slice_list ( memory_slice_list * msl ) =
@
msl . packed == >
@
( valid_memory_slice ( msl -> slice )
@
&& ( msl - > next ==
||
@
valid_memory_slice_list ( msl -> next ))
@
&& finite_list ( next_slice , msl )) ;
@
@
valid_memory_slice_list ( memory_slice_list * msl ) =
@
( msl ) && msl -> packed ;
@
@
slice_lower_length ( memory_slice_list * ptr1 ,
@
memory_slice_list * ptr2 ) =
@
lower_length ( next_slice , ptr1 , ptr2 )
@ } */
strong type i n v a r i a n t
\null
predicate
\valid
predicate
90
behavior
assumes
assigns \nothing
ensures \ r e s u l t
behavior
assumes
requires
ensures \ r e s u l t
* mp ) =
;
/* @
zero_size :
@
s == 0;
@
;
@
== 0;
@
@
positive_size :
@
s > 0;
@
valid_memory_pool ( arena );
@
== 0
@
|| ( valid_memory_chunk (
,s) &&
@
used_memory_chunk (*
));
@ */
memory_chunk * memory_alloc ( memory_pool * arena ,
s) {
memory_slice_list * msl = * arena ;
memory_chunk_list * mcl ;
memory_slice * ms ;
memory_block * mb ;
memory_chunk * mc ;
mb_size ;
// @
mcl_offset ;
* mb_data ;
// guard condition
(s == 0)
0;
// iterate through memory blocks ( or slices )
/* @
@
valid_memory_slice_list ( msl );
@
msl
slice_lower_length ;
@ */
( msl != 0) {
ms = msl -> slice ;
mb = ms -> block ;
mcl = ms -> chunks ;
// does [ mb ] contain enough free space ?
(s <= mb -> size - mb -> next ) {
// @
ms - >
= false ;
// unpack the slice
// allocate a new chunk
mc = ( memory_chunk *) malloc (
( memory_chunk ));
( mc == 0)
0;
mc -> offset = mb -> next ;
mc -> size = s;
mc -> free = false ;
mc -> block = mb ;
// @
mc - >
= true ;
// pack the chunk
// update block accordingly
// @
mb - >
= false ;
// unpack the block
mb -> next += s ;
mb -> used += s ;
// @
mb - >
= true ;
// pack the block
// add the new chunk to the list
mcl = ( memory_chunk_list *) malloc (
( memory_chunk_list ));
( mcl == 0)
0;
mcl -> chunk = mc ;
mcl -> next = ms -> chunks ;
ms -> chunks = mcl ;
// @
ms - >
= true ;
// pack the slice
mc ;
}
// iterate through memory chunks
/* @
@
valid_memory_chunk_list ( mcl , mb );
@
mcl
chunk_lower_length ;
@ */
( mcl != 0) {
mc = mcl -> chunk ;
// is [ mc ] free and large enough ?
\result
\result
unsigned i n t
unsigned i n t
ghost unsigned i n t
char
if
return
loop i n v a r i a n t
loop variant
while
if
ghost
if
for
ghost
sizeof
return
ghost
ghost
ghost
ghost
ghost
ghost
if
return
ghost
return
ghost
loop i n v a r i a n t
loop variant
while
sizeof
for
91
APPENDIX A. APPENDICES
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
if
return
}
// try next chunk
mcl = mcl - > next ;
}
msl = msl - > next ;
}
// allocate a new block
mb_size = ( DEFAULT_BLOCK_SIZE < s) ? s : DEFAULT_BLOCK_SIZE ;
mb_data = (
*) malloc ( mb_size );
( mb_data == 0)
0;
mb = ( memory_block *) malloc (
( memory_block ));
( mb == 0)
0;
mb - > size = mb_size ;
mb - > next = s ;
mb - > used = s ;
mb - >
= mb_data ;
// @
mb - >
= true ;
// pack the block
// allocate a new chunk
mc = ( memory_chunk *) malloc (
( memory_chunk ));
( mc == 0)
0;
mc - > offset = 0;
mc - > size = s ;
mc - > free = false ;
mc - > block = mb ;
// @
mc - >
= true ;
// pack the chunk
// allocate a new chunk list
mcl = ( memory_chunk_list *) malloc (
( memory_chunk_list ));
( mcl == 0)
0;
// @
mcl -> offset = 0;
mcl -> chunk = mc ;
mcl -> next = 0;
// allocate a new slice
ms = ( memory_slice *) malloc (
( memory_slice ));
( ms == 0)
0;
ms - > block = mb ;
ms - > chunks = mcl ;
// @
ms - >
= true ;
// pack the slice
// update the block accordingly
mb - > slice = ms ;
// add the new slice to the list
msl = ( memory_slice_list *) malloc (
( memory_slice_list ));
( msl == 0)
0;
msl -> slice = ms ;
msl -> next = * arena ;
// @
msl ->
= true ;
// pack the slice list
* arena = msl ;
mc ;
char
if
if
return
return
data
ghost
if
if
ghost
if
if
sizeof
return
sizeof
ghost
return
ghost
return
sizeof
ghost
return
ghost
ghost
return
ghost
sizeof
sizeof
ghost
behavior
assumes
\null
assigns \nothing
behavior
assumes
\null
requires
requires
requires
ensures
/* @
null_chunk :
@
chunk ==
;
@
;
@
@
valid_chunk :
@
chunk !=
;
@
valid_memory_pool ( arena );
@
valid_memory_chunk ( chunk , chunk -> size );
@
used_memory_chunk ( chunk );
@
@
// if it is not the last chunk in the block , mark it as free
@
( valid_memory_chunk ( chunk , chunk - > size )
@
&& freed_memory_chunk ( chunk ))
@
||
@
// if it is the last chunk in the block , deallocate the block
@
!
( chunk );
@ */
memory_free ( memory_pool * arena , memory_chunk * chunk ) {
\valid
void
92
A.6. CHANGES
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
if
if
ghost
ghost
while
if
ghost
break
ghost
ghost
ghost
loop i n v a r i a n t
loop variant
while
ghost
ghost
data
for
ghost
ghost
return
return
A.6 Changes
A.6.1 Version 1.8
93
APPENDIX A. APPENDICES
Modied syntax for naming terms and predicates (gures 2.2 and 2.1)
Introduction of
\valid_read
tion 2.7.1).
Introduction of built-in
Introduction of
Improvements to the
allocates
and
frees
assigns
volatile
and
\fresh
(section 2.7.3).
at
(section 2.4.3).
break
Introduction of
requires
\with
in presence of
Predicate
\initialized
94
A.6. CHANGES
Introduction of
axiomatic
\separated .
95
BIBLIOGRAPHY
Bibliography
[1] Jean-Raymond Abrial. The B-Book: Assigning Programs to Meanings. Cambridge University Press, 1996.
[2] Ali Ayad and Claude March. Behavioral properties of oating-point programs. Hisseo
publications, 2009.
http://hisseo.saclay.inria.fr/ayad09.pdf.
[3] Sylvie Boldo and Jean-Christophe Fillitre. Formal Verication of Floating-Point Programs. In 18th IEEE International Symposium on Computer Arithmetic, pages 187194,
Montpellier, France, June 2007.
[4] Patrice Chalin. Reassessing JML's logical foundation. In Proceedings of the 7th Workshop
on Formal Techniques for Java-like Programs (FTfJP'05), Glasgow, Scotland, July 2005.
[5] Patrice Chalin. A sound assertion semantics for the dependable systems evolution verifying compiler. In Proceedings of the International Conference on Software Engineering
(ICSE'07), pages 2333, Los Alamitos, CA, USA, 2007. IEEE Computer Society.
[6] David R. Cok and Joseph R. Kiniry. ESC/Java2 implementation notes. Technical report,
http://secure.ucd.ie/products/opensource/ESCJava2/ESCTools/docs/
Escjava2-ImplementationNotes.pdf.
may 2007.
[7] Jeremy Condit, Matthew Harren, Scott McPeak, George C. Necula, and Westley Weimer.
Ccured in the real world. In PLDI '03: Proceedings of the ACM SIGPLAN 2003 confer-
http://frama-c.cea.fr/.
[12] A. Giorgetti and J. Groslambert. JAG: JML Annotation Generation for verifying temporal properties. In FASE'2006, Fundamental Approaches to Software Engineering, volume
3922 of LNCS, pages 373376, Vienna, Austria, March 2006. Springer.
97
BIBLIOGRAPHY
[13] International Organization for Standardization (ISO).
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf.
[14] Brian Kernighan and Dennis Ritchie. The C Programming Language (2nd Ed.). PrenticeHall, 1988.
[15] Joseph Kiniry. ESC/Java2.
[16] Gary Leavens. Jml.
http://kind.ucd.ie/products/opensource/ESCJava2/.
http://www.eecs.ucf.edu/~leavens/JML/.
behavioral interface specication language for Java. Technical Report 98-06i, Iowa State
University, 2000.
[18] Gary T. Leavens, K. Rustan M. Leino, and Peter Mller. Specication and verication
challenges for sequential object-oriented programs. Form. Asp. Comput., 19(2):159189,
2007.
[19] Gary T. Leavens, K. Rustan M. Leino, Erik Poll, Clyde Ruby, and Bart Jacobs. JML:
notations and tools supporting detailed design in Java. In OOPSLA 2000 Companion,
tation and Proof, volume 4600 of Lecture Notes in Computer Science, pages 235258.
Springer-Verlag, 2007.
[21] Yannick Moy. Union and cast in deductive verication. Technical Report ICIS-R07015,
Radboud University Nijmegen, jul 2007.
union_and_cast.pdf.
http://www.lri.fr/~moy/union_and_cast/
[22] George C. Necula, Scott McPeak, and Westley Weimer. CCured: Type-safe retrotting
of legacy code. In Symposium on Principles of Programming Languages, pages 128139,
2002.
[23] Arun D. Raghavan and Gary T. Leavens. Desugaring JML method specications. Technical Report 00-03a, Iowa State University, 2000.
[24] David Stevenson et al. An american national standard: IEEE standard for binary oating
point arithmetic. ACM SIGPLAN Notices, 22(2):925, 1987.
[25] Wikipedia. First order logic.
[26] Wikipedia. IEEE 754.
http://en.wikipedia.org/wiki/First_order_logic.
http://en.wikipedia.org/wiki/IEEE_754-1985.
98
LIST OF FIGURES
List of Figures
2.1
Grammar of terms
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2.2
Grammar of predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.3
. . . . . . . . . . . . . . . . . . . .
18
2.4
Operator precedence
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.5
2.6
\old
. . . . . . . . . . . . . . . . . . . . . . . . . .
28
in terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
2.7
33
2.8
35
2.9
and
\result
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
36
. . . . . . . . . . . . . . . . . . . .
38
42
. . . . . . . . . . . . . . . . . . . . . . .
46
47
. . . . . . . . . . . . . . . . . . . . . . .
49
50
. . . . . . . . . . . .
52
52
reads
clauses . . . . . . . . . . . . . . . .
54
. . . . . . . . . .
55
57
62
63
65
67
. . . . . . . . . . . . . . . . . . . . . . . . . .
70
72
99
INDEX
Index
?,
_,
do, 36
\dynamic,
16, 17
52
57
dynamic allocation, 57
abrupt clause, 61
\allocable , 55, 58
allocates , 57, 63
allocation, 57
\allocation ,
55, 57
allocation_status,
57
annotation, 35
loop, 35
as,
exits,
52
assert ,
35
assertion, 35
43, 63
\base_addr, 55, 56
behavior , 28, 30, 42, 81
behaviors , 28
\block_length , 28, 55, 56
boolean, 18, 20
breaks , 62
case ,
else , 70
\empty, 33
ensures , 28, 29, 42,
\eq_double, 23
\eq_oat , 23
\exists , 17
\exit_status , 62
47, 52
61
62
42
\freeable , 55, 58
frees , 57, 63
\fresh , 55, 58
\from, 63
\ge_double, 23
\ge_oat , 23
ghost , 68, 70
global , 65
cast, 2023
global invariant, 64
complete,
grammar entries
28
C-global-decl, 46
abrupt-clauses-fn, 62
abrupt-clauses-stmt, 62
allocation-clause, 57
assertion, 35, 38
assigns-clause, 28, 63
assumes-clause, 28
axiom-decl, 49
axiomatic-decl, 49
behavior-body-stmt, 42
behavior-body, 28
complete behaviors, 32
comprehension, 34
continues ,
62
decreases ,
28, 43
dependency, 63
disjoint
, 28
disjoint behaviors, 32
101
INDEX
bin-op, 16
binders, 18
binder, 18
breaks-clause, 62
built-in-logic-type, 18
completeness-clause, 28
compound-statement, 35
constructor, 52
continues-clause, 62
data-inv-decl, 65
data-invariant, 65
declaration, 65, 67, 70, 72
decreases-clause, 28
direct-declarator, 70
dyn-allocation-addresses, 57
ensures-clause, 28
exits-clause, 62
ext-quantier, 50
function-contract, 28
ghost-selection-statement, 70
ghost-type-specier, 70
indcase, 47
inductive-def, 47
inv-strength, 65
label-binders, 52
lemma-decl, 46
literal, 16
location-addresses, 55
location-address, 55
locations, 28
location, 28
logic-const-decl, 49
logic-const-def, 46
logic-decl, 49
logic-def, 46, 47, 49, 52
logic-function-decl, 49, 54
logic-function-def, 46, 54
logic-predicate-decl, 49, 54
logic-predicate-def, 54
logic-type-decl, 49
logic-type-def, 52
logic-type-expr, 18
logic-type, 49
loop-allocation, 57
loop-annot, 36
loop-assigns, 36
loop-behavior, 36
loop-clause, 36
loop-invariant, 36
loop-variant, 36
match-cases, 52
match-case, 52
named-behavior-stmt, 42
named-behavior, 28
one-label, 55
parameters, 46
parameter, 46
pat, 52
poly-id, 46, 52
postx-expression, 70
predicate-def, 46
pred, 17, 28, 33, 55
reads-clause, 54
record-type, 52
rel-op, 17
requires-clause, 28
returns-clause, 62
simple-clause-stmt, 42
simple-clause, 28
statement-contract, 42
statements-ghost, 70
statement, 35, 36, 42, 70
struct-declaration, 70
sum-type, 52
terminates-clause, 28
term, 16, 28, 50, 52, 55, 62
tset, 33
two-labels, 55
type-expr, 18, 46, 52
type-invariant, 65
type-var-binders, 46
type-var, 46
unary-op, 16
variable-ident, 18
\gt_double, 23
\gt_oat , 23
Here,
40, 62
hybrid
function, 51
predicate, 51
if , 70
inductive ,
47
inductive denitions, 47
inductive predicates, 47
\initialized , 73
integer , 18, 20
\inter , 33, 34
102
INDEX
\old ,
invariant, 38
data, 64
polymorphism, 49
global, 64
loop, 36
Post,
strong, 64
post-state, 81
40, 62
type, 64
Pre,
weak, 64
pre-state, 81
65
40, 62
predicate, 16
predicate , 46,
\product , 50
49, 54
pure expression, 81
l-value, 33
\lambda, 50
\le_double, 23
\le_oat , 23
left-value, 81
lemma, 46
\let , 16, 17,
real_of_double, 23
real_of_float, 23
recursion, 50
52
library, 55
location, 33, 61
logic ,
reads , 54, 72
real , 18, 20
46, 49, 54
logic specication, 47
loop
allocation, 60
\register , 57
requires , 28, 29
\result , 28, 29, 62
returns , 62
\round_double, 23
\round_oat , 23
behavior, 37
\separated , 55,
set type, 61
sizeof , 16, 22
deallocation, 60
specication, 47
annotation, 35
assigns, 36
\specied ,
invariant, 36
variant, 38
loop ,
36, 57
LoopCurrent, 40
LoopEntry, 40
\lt_double , 23
\lt_oat , 23
lvalue, 81
\match, 52
\max, 50
\min, 50
model, 67
\oset ,
Old,
55, 56
40, 62
73
\static , 57
strong , 65
\subset , 33
\sum, 50
term, 16
terminates ,
28, 45
termination, 38, 43
\true ,
16, 17, 20
type
concrete, 51
polymorphic, 49
module, 54
\ne_double, 23
\ne_oat , 23
\nothing , 28
\null , 55, 56
\numof, 50
57
record, 51, 52
sum, 51, 52
type ,
49, 52, 65
type invariant, 64
\unallocated , 57
\union, 33, 34
\valid ,
103
55, 56
INDEX
\valid_read , 55, 56
variant , 36, 38, 43
volatile , 72
weak,
while ,
\with,
65
36
16
writes,
72
104