diff --git a/infer/src/cost/ConfigImpactAnalysis.ml b/infer/src/cost/ConfigImpactAnalysis.ml index 81cd57f9c..bb89019bb 100644 --- a/infer/src/cost/ConfigImpactAnalysis.ml +++ b/infer/src/cost/ConfigImpactAnalysis.ml @@ -379,7 +379,8 @@ module Dom = struct dispatch tenv pname args - let call tenv analyze_dependency ~is_cheap_call callee args location + let call tenv analyze_dependency ~(instantiated_cost : CostInstantiate.instantiated_cost) callee + args location ({config_checks; field_checks; unchecked_callees; unchecked_callees_cond} as astate) = let join_unchecked_callees new_unchecked_callees new_unchecked_callees_cond = if FieldChecks.is_top field_checks then @@ -413,6 +414,8 @@ module Dom = struct let has_expensive_callee = Option.exists callee_summary ~f:Summary.has_known_expensive_callee in + let is_cheap_call = match instantiated_cost with Cheap -> true | _ -> false in + let is_unmodeled_call = match instantiated_cost with NoModel -> true | _ -> false in match expensiveness_model with | None when is_cheap_call && not has_expensive_callee -> (* If callee is cheap by heuristics, ignore it. *) @@ -446,8 +449,8 @@ module Dom = struct join_unchecked_callees (UncheckedCallees.replace_location_by_call location callee_summary) (UncheckedCalleesCond.replace_location_by_call location callee_summary_cond) - | None when Procname.is_objc_init callee -> - (* If callee is unknown ObjC initializer, ignore it. *) + | None when Procname.is_objc_init callee || is_unmodeled_call -> + (* If callee is unknown ObjC initializer or has no cost model, ignore it. *) astate | _ -> (* Otherwise, add callee's name. *) @@ -462,7 +465,7 @@ type analysis_data = { interproc: (BufferOverrunAnalysisSummary.t option * Summary.t option * CostDomain.summary option) InterproceduralAnalysis.t - ; get_is_cheap_call: CostInstantiate.Call.t -> bool } + ; get_instantiated_cost: CostInstantiate.Call.t -> CostInstantiate.instantiated_cost } module TransferFunctions = struct module CFG = ProcCfg.Normal @@ -514,7 +517,8 @@ module TransferFunctions = struct fun tenv pname -> dispatch tenv pname |> Option.is_some - let exec_instr astate {interproc= {tenv; analyze_dependency}; get_is_cheap_call} node idx instr = + let exec_instr astate {interproc= {tenv; analyze_dependency}; get_instantiated_cost} node idx + instr = match (instr : Sil.instr) with | Load {id; e= Lvar pvar} -> Dom.load_config id pvar astate @@ -541,8 +545,8 @@ module TransferFunctions = struct CostInstantiate.Call. {loc= location; pname= callee; node= CFG.Node.to_instr idx node; args; ret} in - let is_cheap_call = get_is_cheap_call call in - Dom.call tenv analyze_dependency ~is_cheap_call callee args location astate ) + let instantiated_cost = get_instantiated_cost call in + Dom.call tenv analyze_dependency ~instantiated_cost callee args location astate ) | Prune (e, _, _, _) -> Dom.prune e astate | _ -> @@ -564,8 +568,8 @@ let has_call_stmt proc_desc = let checker ({InterproceduralAnalysis.proc_desc} as analysis_data) = - let get_is_cheap_call = CostInstantiate.get_is_cheap_call analysis_data in - let analysis_data = {interproc= analysis_data; get_is_cheap_call} in + let get_instantiated_cost = CostInstantiate.get_instantiated_cost analysis_data in + let analysis_data = {interproc= analysis_data; get_instantiated_cost} in Option.map (Analyzer.compute_post analysis_data ~initial:Dom.init proc_desc) ~f:(fun astate -> let has_call_stmt = has_call_stmt proc_desc in Dom.to_summary ~has_call_stmt astate ) diff --git a/infer/src/cost/costInstantiate.ml b/infer/src/cost/costInstantiate.ml index 0a2372fae..66258f868 100644 --- a/infer/src/cost/costInstantiate.ml +++ b/infer/src/cost/costInstantiate.ml @@ -32,7 +32,9 @@ type cost_args = type 'a interproc_analysis = (BufferOverrunAnalysisSummary.t option * 'a * CostDomain.summary option) InterproceduralAnalysis.t -let get_symbolic_cost +type instantiated_cost = Cheap | NoModel | Symbolic of CostDomain.BasicCost.t + +let get_instantiated_cost { tenv ; integer_type_widths ; get_callee_cost_summary_and_formals @@ -44,9 +46,7 @@ let get_symbolic_cost (BufferOverrunAnalysis.extract_pre (ProcCfg.InstrNode.id node) inferbo_invariant_map) in let loc = ProcCfg.InstrNode.loc node in - let get_symbolic cost = - if CostDomain.BasicCost.is_symbolic cost then `SymbolicCost cost else `Cheap - in + let get_symbolic cost = if CostDomain.BasicCost.is_symbolic cost then Symbolic cost else Cheap in let get_summary pname = Option.map ~f:fst (get_callee_cost_summary_and_formals pname) in match get_callee_cost_summary_and_formals pname with | Some (CostDomain.{post= cost_record}, callee_formals) -> @@ -56,14 +56,14 @@ let get_symbolic_cost ~inferbo_caller_mem:inferbo_mem ~callee_pname:pname ~callee_formals ~args ~callee_cost ~loc) .cost |> get_symbolic - else `Cheap + else Cheap | None -> let fun_arg_list = List.map args ~f:(fun (exp, typ) -> ProcnameDispatcher.Call.FuncArg.{exp; typ; arg_payload= ()} ) in CostModels.Call.dispatch tenv pname fun_arg_list - |> Option.value_map ~default:`NoModel ~f:(fun model -> + |> Option.value_map ~default:NoModel ~f:(fun model -> let model_env = let node_hash = ProcCfg.InstrNode.hash node in BufferOverrunUtils.ModelEnv.mk_model_env pname ~node_hash loc tenv @@ -102,20 +102,12 @@ let prepare_call_args let get_cost_if_expensive analysis_data call = - match prepare_call_args analysis_data call |> get_symbolic_cost with - | `SymbolicCost cost -> + match prepare_call_args analysis_data call |> get_instantiated_cost with + | Symbolic cost -> Some cost - | `Cheap | `NoModel -> + | Cheap | NoModel -> None -let get_is_cheap_call analysis_data call = - match prepare_call_args analysis_data call |> get_symbolic_cost with - | `SymbolicCost _ -> - (* symbolic costs (e.g. 4n+5 or log(n) are considered expensive) *) - false - | `Cheap -> - true - | `NoModel -> - (* unmodeled calls are considered expensive *) - false +let get_instantiated_cost analysis_data call = + prepare_call_args analysis_data call |> get_instantiated_cost diff --git a/infer/src/cost/costInstantiate.mli b/infer/src/cost/costInstantiate.mli index f87ee2b9e..582a1f0df 100644 --- a/infer/src/cost/costInstantiate.mli +++ b/infer/src/cost/costInstantiate.mli @@ -22,6 +22,8 @@ end type 'a interproc_analysis = (BufferOverrunAnalysisSummary.t option * 'a * CostDomain.summary option) InterproceduralAnalysis.t +type instantiated_cost = Cheap | NoModel | Symbolic of CostDomain.BasicCost.t + val get_cost_if_expensive : 'a interproc_analysis -> Call.t -> CostDomain.BasicCost.t option -val get_is_cheap_call : 'a interproc_analysis -> Call.t -> bool +val get_instantiated_cost : 'a interproc_analysis -> Call.t -> instantiated_cost