let interp_call stmt lval_to_assign funcexp argl d_value =
let call_site_loc = CurrentLoc.get () in
let with_alarms = warn_all_quiet_mode () in
let return_type_funcexp =
match unrollType (typeOf funcexp) with
TFun (t, _, _, _) -> t
| _ -> assert false
in
let bitssizeofreturntypefuncexp =
bitsSizeOf return_type_funcexp
in
let state_after_call state =
try
let functions, _ = resolv_func_vinfo ~with_alarms None state funcexp in
let is_library_function kf = not (Kernel_function.is_definition kf) in
let calling_at_least_one_library_function =
Kernel_function.Hptset.exists is_library_function functions
in
let calling_only_library_functions =
calling_at_least_one_library_function &&
(Kernel_function.Hptset.for_all is_library_function functions)
in
let compute_actual = compute_actual ~with_alarms
(calling_at_least_one_library_function,
calling_only_library_functions)
in
let actuals = List.map (compute_actual state) argl in
let treat_one_call f (acc_rt,acc_res,acc_clobbered_set as acc) =
try
let return_type = Kernel_function.get_return_type f in
if bitsSizeOf return_type <> bitssizeofreturntypefuncexp
then raise Wrong_function_type;
let return, result, clobbered_set =
!compute_call_ref f ~call_kinstr:(Kstmt stmt) state actuals
in
let caller = current_kf (), stmt in
Kf_state.add_caller f ~caller;
CurrentLoc.set call_site_loc;
(match acc_rt,return with
| None,_ -> return
| Some _, None -> acc_rt
| Some acc_rt, Some return ->
Some (snd (V_Offsetmap.join acc_rt return))),
Cvalue.Model.join acc_res result,
Location_Bits.Top_Param.join acc_clobbered_set clobbered_set
with Wrong_function_type ->
warning_once_current
"Pointed function type must match function pointer type when dereferenced: assert(Ook)";
CilE.stop_if_stop_at_first_alarm_mode ();
acc
in
let return,new_state,clobbered_set =
Kernel_function.Hptset.fold treat_one_call
functions
empty_interpretation_result
in
bases_containing_locals :=
Location_Bits.Top_Param.join !bases_containing_locals clobbered_set;
match lval_to_assign with
| None -> new_state
| Some lv ->
match return with
| Some return ->
assign_return_to_lv ~with_alarms funcexp lv return new_state
| None ->
if Cvalue.Model.is_reachable new_state
then
warning_once_current
"In function %t: called function returns void but returned value is assigned; ignoring assignment"
pretty_current_cfunction_name;
new_state
with
| Got_bottom ->
CurrentLoc.set call_site_loc;
Cvalue.Model.bottom
| Leaf ->
CurrentLoc.set call_site_loc;
(match lval_to_assign with
| None -> state
| Some lv ->
let evaled_exp = V.top_leaf_origin () in
do_assign_abstract_value ~with_alarms state lv evaled_exp)
in
State_set.fold
(fun acc state -> State_set.add (state_after_call state) acc)
State_set.empty
d_value