[ConfigImpact] Ignore unknown library calls with no cost model

Summary:
Looking at the recent silent analysis results, it seems that we report many direct unknown library calls (often cheap)... However, if these were called inside some other callee we wouldn't report them because their costs would be assumed to be constant by the cost analysis.

This is a bit awkward. We should either report all unknown calls or suppress them altogether.

Since we have too many reports per day and not a good way to determine whether an unknown library call is cheap/expensive, let's take option 2.

Then, we would be only relying on two things to determine whether to report/not:
- instantiated cost's degree > 1
- explicitly known to be expensive (i.e. modeled in ConfigImpact, like string append)

Reviewed By: skcho

Differential Revision: D27909003

fbshipit-source-id: 0391d226d
master
Ezgi Çiçek 4 years ago committed by Facebook GitHub Bot
parent 4920cce2f3
commit aae741419c

@ -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 )

@ -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

@ -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

Loading…
Cancel
Save