1
(**************************************************************************)
3
(* This file is part of Frama-C. *)
5
(* Copyright (C) 2007-2008 *)
6
(* CEA (Commissariat � l'�nergie Atomique) *)
8
(* you can redistribute it and/or modify it under the terms of the GNU *)
9
(* Lesser General Public License as published by the Free Software *)
10
(* Foundation, version 2.1. *)
12
(* It is distributed in the hope that it will be useful, *)
13
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
14
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
15
(* GNU Lesser General Public License for more details. *)
17
(* See the GNU Lesser General Public License version 2.1 *)
18
(* for more details (enclosed in the file licenses/LGPLv2.1). *)
20
(**************************************************************************)
31
(* Computation of over-approximed operational inputs:
32
An acurate computation of these inputs needs the computation of
33
under-approximed outputs.
34
Computation principle for the treatement of a basic statement:
35
* I_new+ = I_old+ \/+ (Rd+(stmt) /+ O_old-)
36
* O_new- = O_old- \/- Wr-(stmt)
40
{ over_inputs : Zone.t ;
41
under_outputs : Zone.t }
43
(* Initial value for the computation *)
45
{ (* initial value for the computation of over_inputs *)
46
over_inputs = Zone.bottom;
47
under_outputs = Zone.bottom;
52
over_inputs = Zone.bottom ;
53
under_outputs = Zone.top
58
{ over_inputs = Zone.top ;
59
under_outputs = Zone.bottom }
62
let call_stack : kernel_function Stack.t =
64
(* Stack of function being processed *)
66
let find_deps_no_transitivity = !From.find_deps_no_transitivity
67
(* The value of the expression [expr], just before executing the statement [instr],
68
is a function of the values of the returned zones. *)
70
module Computer (REACH:sig
71
val stmt_can_reach : stmt -> stmt -> bool
73
let name = "InOut context"
77
let current_stmt = ref Kglobal
79
let stmt_can_reach = REACH.stmt_can_reach
81
let under_inputs_termination_no_depend = ref Zone.bottom
85
module StmtStartData =
86
Dataflow.StmtStartData(struct type t = compute_t let size = 107 end)
88
let display_one fmt k v =
89
Format.fprintf fmt "Statement: %d@\n"
91
InOutContext.pretty fmt v
94
Format.fprintf fmt "@[Over-approximated operational inputs: %a@]@\n@[Under-approximated operational outputs: %a@]"
95
Zone.pretty x.over_inputs
96
Zone.pretty x.under_outputs
99
Format.fprintf fmt "=========INOUT CONTEXT START=======@\n";
103
Format.fprintf fmt "=========INOUT CONTEXT END=======@\n"
108
let computeFirstPredecessor (s: stmt) data =
112
(* update [over_inputs] using the [exp] condition:
113
I+ = I+ \/+ (D+(exp) /+ O-)
115
let inputs = find_deps_no_transitivity (Kstmt s) exp in
118
Zone.join data.over_inputs
119
(Zone.diff inputs data.under_outputs)}
122
let combinePredecessors
124
~old:{under_outputs = old_outputs;
125
over_inputs = old_inputs}
127
let {under_outputs = new_outputs;
128
over_inputs = new_inputs} = computeFirstPredecessor s new_
130
let result_inputs = Zone.join old_inputs new_inputs in
131
(* over-approximation :
132
I+ = I_old+ \/+ (I_new+ \/+ (D+(exp) /+ Onew-)
134
let result_outputs = Zone.meet old_outputs new_outputs in
135
(* under-approximation :
136
O- = O_old- /\- O_new-
138
(*display Format.std_formatter stmtStartData;*)
139
if Zone.is_included result_inputs old_inputs
140
(* test for an over-approximation *)
141
&& Zone.is_included old_outputs result_outputs
142
(* test for an under-approximation *)
144
((*Format.printf "STABLE RESULT:[Under-outputs=%a][Over-inputs=%a]@\nOLD:[Under-outputs=%a][Over-inputs=%a]@\n"
145
Zone.pretty result_outputs
146
Zone.pretty result_inputs
147
Zone.pretty old_outputs
148
Zone.pretty old_inputs
152
((*Format.printf "LATER RESULT:[Under-outputs=%a][Over-inputs=%a]@\nOLD:[Under-outputs=%a][Over-inputs=%a]@\n"
153
Zone.pretty result_outputs
154
Zone.pretty result_inputs
155
Zone.pretty old_outputs
156
Zone.pretty old_inputs
158
Some {under_outputs = result_outputs; over_inputs = result_inputs})
160
let resolv_func_vinfo ?deps kinstr funcexp =
161
!Value.expr_to_kernel_function ?deps kinstr funcexp
163
let doInstr _stmt (i: instr) (_d: t) =
164
let kinstr = !current_stmt
166
let add_with_additional_var k j st =
167
let deps, looking_for =
168
(* The modified tsets are [looking_for], those address are
169
function of [deps]. *)
170
!Value.lval_to_loc_with_deps
171
~with_alarms:CilE.warn_none_mode
177
Zone.join st.over_inputs (Zone.diff deps st.under_outputs) in
179
if Location_Bits.cardinal_zero_or_one looking_for.loc
181
(* There is only one modified zone. So, this is an exact output.
182
Add it into the under-approximed outputs. *)
183
Zone.link st.under_outputs (Locations.valid_enumerate_bits looking_for)
184
else (* Impossible to add these outputs into the under-approximed outputs. *)
187
(* Format.printf "doInstr:@\n <-new_inputs: %a@\n <-new_outputs: %a@\n ->old_inputs: %a@\n ->old_outputs: %a@\n ->additional_var: %a@\n ->read_loc: %a@\n ->writen_loc: %a@\n ->cardinal_zero_or_one: %s@\n"
188
Zone.pretty new_inputs
189
Zone.pretty new_outputs
190
Zone.pretty st.over_inputs
191
Zone.pretty st.under_outputs
194
Location_Bits.pretty looking_for.loc
195
(if Location_Bits.cardinal_zero_or_one looking_for.loc then "true" else "false");
197
{ over_inputs = new_inputs;
198
under_outputs = new_outputs }
201
| Set (lv, exp, _) ->
205
let exp_inputs_deps =
206
find_deps_no_transitivity kinstr exp
208
(* Format.printf "ADD INPUTS (line %d): %a\n"
209
location.Cil_types.line Zone.pretty exp_inputs_deps; *)
210
add_with_additional_var
214
| Call (lvaloption,funcexp,argl,_) ->
217
let funcexp_inputs, called_vinfos =
218
(* [funcexp_inputs]: inputs for the evaluation of [funcexp],
219
[called_vinfos]: list of called functions *)
221
~with_alarms:CilE.warn_none_mode
226
let acc_funcexp_inputs =
227
(* inputs used by [funcexp] and inputs for the evaluation of [funcexp] *)
228
Zone.join funcexp_inputs state.over_inputs
230
let acc_funcexp_arg_inputs =
231
(* inputs used by [funcexp], inputs for the evaluation of [funcexp] and its [argl] *)
234
let arg_inputs = find_deps_no_transitivity kinstr arg
235
in Zone.join inputs arg_inputs)
239
match called_vinfos with
240
| [] -> { over_inputs = acc_funcexp_arg_inputs ;
241
under_outputs = state.under_outputs }
243
let do_on kernel_function =
244
let { over_inputs_if_termination = called_inputs;
245
under_outputs_if_termination = called_outputs ;
247
Inout_type.over_inputs = called_input_termination_no_depend} = !Db.InOutContext.get_external kernel_function
250
let _ = under_inputs_termination_no_depend := Zone.join
251
!under_inputs_termination_no_depend
252
(Zone.diff called_input_termination_no_depend state.under_outputs);
253
in { over_inputs = (* the real inputs of the call to those of the curent state *)
254
Zone.diff called_inputs state.under_outputs;
255
under_outputs = called_outputs }
257
let acc = do_on h (* First call *)
258
in let done_on = List.fold_left (* Combine other calls *)
259
(fun acc_memory called_vinfo ->
260
let done_on = do_on called_vinfo
261
in {over_inputs = Zone.join done_on.over_inputs acc_memory.over_inputs; (* over-approximation *)
262
under_outputs = Zone.meet done_on.under_outputs acc_memory.under_outputs (* under-approximation intersec*)
266
in (* state just after the call, but before the result asssigment *)
267
{ over_inputs = Zone.join acc_funcexp_arg_inputs done_on.over_inputs ;
268
under_outputs = Zone.link state.under_outputs done_on.under_outputs (* under-approximed union *) }
270
(* Treatement for the eventual assignement of the call result *)
271
(match lvaloption with
274
add_with_additional_var
276
Zone.bottom (* Inputs are already got using [!InOutContext.get_external kernel_function]. *)
280
| _ -> Dataflow.Default
282
let doStmt (s: stmt) (_d: t) =
283
current_stmt := Kstmt s;
286
let filterStmt (s:stmt) =
287
let state = Value.noassert_get_state (Kstmt s) in
288
Value.is_reachable state
290
let clear_for_function f =
291
StmtStartData.clear ();
292
StmtStartData.iter (StmtStartData.add stmtStartData) f
294
let doGuard s _e _t =
295
current_stmt := Kstmt s;
300
let get_using_prototype kf =
301
let state = Value.get_initial_state kf in
302
let behaviors = !Value.valid_behaviors kf state in
303
let assigns = Ast_info.merge_assigns behaviors in
304
let over_inputs_if_termination =
305
!Value.assigns_to_zone_inputs_state state assigns
307
{ Inout_type.under_outputs_if_termination =
308
(* car les sorties s�re ne sont pas sp�cifi�es ! *)
310
over_inputs_if_termination =
311
(* [over_inputs_if_termination] = [Zone.top] ou [over_inputs_if_termination] ?
312
La valeur [over_inputs_if_termination] est l�g�rement incorrect car les
313
le d�tail de l'implementation n'est pas pr�cis� dans la sp�cification.
314
La meilleure implementation peut se contenter [over_inputs_if_termination]
315
comme entr�es op�rationelles. *)
316
over_inputs_if_termination;
318
(* [over_inputs] = [Zone.top] ou [over_inputs_if_termination] ?
319
La valeur [over_inputs_if_termination] est l�g�rement incorrect car les
320
fonctions feuilles ne sont pas specifi�es en cas de non terminaison. *)
321
over_inputs_if_termination
324
let compute_internal_using_prototype kf =
326
| Definition _ -> assert false
327
| Declaration _ -> get_using_prototype kf
329
let compute_internal_using_cfg kf =
330
let compute_for_definition kf f =
332
let module Computer =
333
Computer(struct let stmt_can_reach = Stmts_graph.stmt_can_reach kf end)
335
let module Compute = Dataflow.ForwardsDataFlow(Computer)
338
(fun g -> if kf == g then begin
341
"ignoring recursive call detected in function %s during [inout context] computation."
342
(Kernel_function.get_name kf));
346
Stack.push kf call_stack;
347
let res_if_termination = (* result if termination *)
348
match f.sbody.bstmts with
351
let ret_id = Kernel_function.find_return kf in
352
(* Format.printf "Return is %d@\n\n" ret_id; *)
353
(* We start with only the start block *)
354
Computer.StmtStartData.add
356
(Computer.computeFirstPredecessor
359
Compute.compute [start];
360
let _poped = Stack.pop call_stack in
361
(*Format.printf "[inout] poped %s\n@\n" (get_name _poped);
363
(fun g -> Format.printf "[inout] stack with %s\n@\n" (get_name g))
367
Computer.StmtStartData.find ret_id.sid
372
{ Inout_type.over_inputs_if_termination = res_if_termination.over_inputs ;
373
under_outputs_if_termination = res_if_termination.under_outputs ;
374
over_inputs = let acc = Computer.under_inputs_termination_no_depend
375
in Computer.StmtStartData.iter (fun _sid data -> acc := Zone.join data.over_inputs !acc) ; !acc }
378
{ Inout_type.over_inputs_if_termination = empty.over_inputs ;
379
under_outputs_if_termination = empty.under_outputs ;
380
over_inputs = empty.over_inputs
386
"compute_using_cfg cannot be called on leaf functions"
387
| Definition (f, _) ->
388
compute_for_definition kf f
394
let name = "internal_inouts"
395
let dependencies = [ Value.self ]
403
"[inout context] computing for function %a%s"
404
Kernel_function.pretty_name kf
407
(fun kf -> s := !s^" <-"^
408
(fprintf_to_string "%a" Kernel_function.pretty_name kf))
414
compute_internal_using_cfg kf
416
compute_internal_using_prototype kf
418
Cil.log "[inout context] done for function %a"
419
Kernel_function.pretty_name kf;
422
let get_external_using_prototype = get_using_prototype
424
let externalize fundec =
426
| Definition (fundec,_) ->
428
(fun v -> not (Base.is_formal_or_local v fundec))
429
| Declaration (_,vd,_,_) ->
431
(fun v -> not (Base.is_formal_of_prototype v vd))
436
let name = "external_inouts"
437
let dependencies = [ Internals.self ]
443
let internals = get_internal kf in
444
let filter = externalize kf.fundec in
446
{ Inout_type.over_inputs_if_termination = filter internals.Inout_type.over_inputs_if_termination;
447
under_outputs_if_termination = filter internals.Inout_type.under_outputs_if_termination;
448
over_inputs = filter internals.Inout_type.over_inputs })
450
let compute_external kf = ignore (get_external kf)
452
let pretty_internal fmt kf =
453
Format.fprintf fmt "@[InOut (internal) for function %a:@\n%a@]@\n"
454
Kernel_function.pretty_name kf
455
InOutContext.pretty (get_internal kf)
457
let pretty_external fmt kf =
458
Format.fprintf fmt "@[InOut for function %a:@\n%a@]@\n"
459
Kernel_function.pretty_name kf
460
InOutContext.pretty (get_external kf)
463
(* Derefs.statement := statement; *)
464
InOutContext.self_internal := Internals.self;
465
InOutContext.self_external := Externals.self;
466
InOutContext.get_internal := get_internal;
467
InOutContext.get_external := get_external;
468
InOutContext.compute := compute_external;
469
InOutContext.display := pretty_internal
473
Arg.Unit Cmdline.ForceInout.on,
474
": force operational inout display; this gives the operational inputs, an over-approximation of the set of locations whose initial value is used; and the sure outputs, an under-approximation of the set of writen tsets "
478
compile-command: "LC_ALL=C make -C ../.."