Source file utils.ml
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
open Cil_types
open Ast_const
let print_std_includes fmt globs =
if not (Kernel.PrintLibc.get ()) then begin
let acc = function
| AStr s -> Datatype.String.Set.add s acc
| _ -> Kernel.warning "Unexpected attribute parameter for fc_stdlib"; acc
in
let add_file acc g =
let attrs = Cil_datatype.Global.attr g in
List.fold_left extract_file acc (Cil.findAttribute "fc_stdlib" attrs)
in
let includes = List.fold_left add_file Datatype.String.Set.empty globs in
let print_one_include s = Format.fprintf fmt "#include \"%s\"@." s in
Datatype.String.Set.iter print_one_include includes
end
module Printer = Printer_builder.Make (struct
class printer () = object (self)
inherit Printer.extensible_printer ()
method! file fmt file =
Format.fprintf fmt "@[/* Generated by Frama-C LTest */\n\n";
print_std_includes fmt file.globals;
Format.fprintf fmt "\n#ifndef pc_label\n#define pc_label(...) do{}while(0)\n\
#endif@\n\
#ifndef pc_label_bindings\n#define pc_label_bindings(...) do{}while(0)\n\
#endif@\n\n";
if Options.Annotators.mem "RCC" then begin
Format.fprintf fmt "\
#define MAX_MUTATION %d\n\
unsigned int cpt_mutation = 0;\n\n\
/*%@ assigns cpt_mutation, \\result;\n\
\ behavior can_mutate:\n\
\ assumes cpt_mutation < MAX_MUTATION;\n\
\ ensures \\result <==> cpt_mutation == \\at(cpt_mutation, Pre) + 1;\n\
\ ensures !\\result <==> cpt_mutation == \\at(cpt_mutation, Pre);\n\n\
\ behavior cant_mutate:\n\
\ assumes cpt_mutation >= MAX_MUTATION;\n\
\ ensures !\\result;\n\
\ ensures cpt_mutation == \\at(cpt_mutation, Pre);\n\n\
\ complete behaviors;\n\
\ disjoint behaviors;\n\
*/\n\
int mutated(void);\n" (Options.MaxMutation.get ());
end;
Cil.iterGlobals file (fun g -> self#global fmt g);
Format.fprintf fmt "@]@."
end
end)
(** Extracts global variables from an AST *)
let file =
let module S = Cil_datatype.Varinfo.Set in
let f acc global =
match global with
| GVar (vi,_,_) -> if Cil.isFunctionType vi.vtype then acc else S.add vi acc
| GVarDecl (vi,_) -> if Cil.isFunctionType vi.vtype then acc else S.add vi acc
| _ -> acc
in
let globals = Cil.foldGlobals file f S.empty in
S.elements globals
let print_file_path origine_loc = (Filepath.Normalized.to_pretty_string ((fst origine_loc).Filepath.pos_path))
let mk_call ?(loc=Cil_datatype.Location.unknown) ?result fvinfo args =
let vinfo_exp = Exp_builder.var ~loc (Option.get fvinfo) in
Stmt_builder.mk (Instr (Call (result, vinfo_exp, args, loc)))
(** Indicates whether an instruction is a label. *)
let is_label instr =
match instr with
| Call (_, {enode=Lval (Var {vname=name}, NoOffset)}, _, _) ->
let regexp = Str.regexp_string "pc_label" in
Str.string_match regexp name 0
| _ -> false
(**
Indicates whether an expression is boolean in itself.
Used to detect boolean expression outside conditional statement
*)
let is_boolean e =
Options.debug ~level:3 "is boolean? @[%a@]@." Cil_printer.pp_exp e;
match e.enode with
| BinOp (_, _, _, TInt (IBool, _))
| UnOp (_, _, TInt (IBool, _))
| BinOp ((LAnd|LOr|Lt|Gt|Le|Ge|Eq|Ne), _, _, _)
| UnOp (LNot, _, _) -> true
| _ -> false
(**
Get atomic conditions from a boolean expression.
*)
let atomic_conditions =
let rec aux acc exp =
match exp.enode with
| BinOp ((Ne|Eq), a, b, _) ->
if Cil.isZero b && is_boolean a then
aux acc a
else if Cil.isZero a && is_boolean b then
aux acc b
else
exp :: acc
| BinOp ((LAnd | LOr), e1, e2, _) ->
aux (aux acc e1) e2
| UnOp (LNot, e, _) ->
aux acc e
| _ ->
exp :: acc
in
fun exp -> List.rev (aux [] exp)
let rev_combine : int -> 'a list -> 'a list list =
let rec comb_aux rev_startswith acc n l =
match n, l with
| 0, _ -> (List.rev rev_startswith) :: acc
| _, [] -> acc
| _, head :: tail ->
let acc = comb_aux (head :: rev_startswith) acc (n-1) tail in
comb_aux rev_startswith acc n tail
in
fun n l -> comb_aux [] [] n l
(** [combine n l] computes the combinations of [n] elements from the list [l].
Returns the combination in the order of the list [l].
For instance, [combine 2 [1;2;3]] returns [[1;2];[1;3];[2;3]].
*)
let combine n (l : 'a list) : 'a list list =
List.rev (rev_combine n l)
(**
[sign_combine pos neg l] computes all sign combinations of a list of elements [l], given two sign functions [pos] and [neg].
Preserves the original order of the list, i.e. each sublist is in the same order.
For instance, [sign_combine (fun x ->"+"^x) (fun x -> "-"^x) ["1";"2"]] returns [["+1";"+2"];["+1";"-2"];["-1";"+2"];["-1";"-2"]].
*)
let rev_sign_combine ~(pos: 'a -> 'b) ~(neg : 'a -> 'b) : 'a list -> 'b list list =
let rec aux acc revpref l =
match l with
| [] -> (List.rev revpref) :: acc
| head :: tail ->
let acc = aux acc (pos head :: revpref) tail in
aux acc (neg head :: revpref) tail
in
aux [] []
let sign_combine ~pos ~neg l =
List.rev (rev_sign_combine ~pos ~neg l)
let with_delta op value kind =
let delta = Options.LimitDelta.get () in
let op' = match op, delta with
| _, 0 -> Eq
| MinusA, _ -> Ge
| PlusA, _ -> Le
| _ -> assert false
in
if delta = 0 then
op', Exp_builder.kinteger64 kind value
else
op', Exp_builder.binop op (Exp_builder.kinteger64 kind value) (Exp_builder.integer delta)
let get_bounds kind : (binop*exp) list =
if kind = IBool then
[(Eq,Exp_builder.zero ());(Eq,Exp_builder.one ())]
else
let size = Cil.bitsSizeOfInt kind in
if Cil.isSigned kind then
[with_delta PlusA (Cil.min_signed_number size) kind;
with_delta MinusA (Cil.max_signed_number size) kind]
else
[with_delta PlusA Integer.zero kind;
with_delta MinusA (Cil.max_unsigned_number size) kind]
let is_bound _kind _i = false