let doInstr _stmt (i: instr) (_d: t) =
let kinstr = !current_stmt
in
let add_with_additional_var k j st =
let deps, looking_for =
(* The modified tsets are [looking_for], those address are
function of [deps]. *)
!Value.lval_to_loc_with_deps
~with_alarms:CilE.warn_none_mode
~deps:j
kinstr
k
in
let new_inputs =
Zone.join st.over_inputs (Zone.diff deps st.under_outputs) in
let new_outputs =
if Location_Bits.cardinal_zero_or_one looking_for.loc
then
(* There is only one modified zone. So, this is an exact output.
Add it into the under-approximed outputs. *)
Zone.link st.under_outputs (Locations.valid_enumerate_bits looking_for)
else (* Impossible to add these outputs into the under-approximed outputs. *)
st.under_outputs
in
{ over_inputs = new_inputs;
under_outputs = new_outputs }
in
match i with
| Set (lv, exp, _) ->
Dataflow.Post
(fun state ->
let exp_inputs_deps =
!From.find_deps_no_transitivity kinstr exp
in
add_with_additional_var
lv
exp_inputs_deps
state)
| Call (lvaloption,funcexp,argl,_) ->
Dataflow.Post
(fun state ->
let funcexp_inputs, called_vinfos =
(* [funcexp_inputs]: inputs for the evaluation of [funcexp],
[called_vinfos]: list of called functions *)
resolv_func_vinfo
~with_alarms:CilE.warn_none_mode
~deps:Zone.bottom
kinstr
funcexp
in
let acc_funcexp_inputs =
(* inputs used by [funcexp] and inputs for the evaluation of [funcexp] *)
Zone.join funcexp_inputs state.over_inputs
in
let acc_funcexp_arg_inputs =
(* inputs used by [funcexp], inputs for the evaluation of [funcexp] and its [argl] *)
List.fold_right
(fun arg inputs ->
let arg_inputs = !From.find_deps_no_transitivity kinstr arg
in Zone.join inputs arg_inputs)
argl
acc_funcexp_inputs
in let result =
match Kernel_function.Set.elements called_vinfos with
| [] -> { over_inputs = acc_funcexp_arg_inputs ;
under_outputs = state.under_outputs }
| h::t ->
let do_on kernel_function =
let { over_inputs_if_termination = called_inputs;
under_outputs_if_termination = called_outputs ;
Inout_type.over_inputs = called_input_termination_no_depend} = !Db.InOutContext.get_external kernel_function
in
let _ = under_inputs_termination_no_depend := Zone.join
!under_inputs_termination_no_depend
(Zone.diff called_input_termination_no_depend state.under_outputs);
in { over_inputs = (* the real inputs of the call to those of the curent state *)
Zone.diff called_inputs state.under_outputs;
under_outputs = called_outputs }
in
let acc = do_on h (* First call *)
in let done_on = List.fold_left (* Combine other calls *)
(fun acc_memory called_vinfo ->
let done_on = do_on called_vinfo
in {over_inputs = Zone.join done_on.over_inputs acc_memory.over_inputs; (* over-approximation *)
under_outputs = Zone.meet done_on.under_outputs acc_memory.under_outputs (* under-approximation intersec*)
})
acc
t
in (* state just after the call, but before the result asssigment *)
{ over_inputs = Zone.join acc_funcexp_arg_inputs done_on.over_inputs ;
under_outputs = Zone.link state.under_outputs done_on.under_outputs (* under-approximed union *) }
in let result =
(* Treatement for the eventual assignement of the call result *)
(match lvaloption with
| None -> result
| Some lv ->
add_with_additional_var
lv
Zone.bottom (* Inputs are already got using [!InOutContext.get_external kernel_function]. *)
result)
in result
)
| _ -> Dataflow.Default