[attributes] request attributes only when procdesc isn't required

Summary: Most of the time, when the procdesc of a callee is requested, all that is really required is the procedure attributes. However, requesting the procdesc may return `None` when the procedure is undefined (in Java, and soon for Clang too).  So, change all callsites to using attributes instead, where possible.

Reviewed By: jvillard

Differential Revision: D23539422

fbshipit-source-id: 3b1a52d48
master
Nikos Gorogiannis 4 years ago committed by Facebook GitHub Bot
parent d7cd987780
commit 30fcdc7d29

@ -97,6 +97,19 @@ let get_annotated_formals {method_annotation= {params}; formals} =
List.rev (zip_params (List.rev params) (List.rev formals))
let get_access attributes = attributes.access
let get_formals attributes = attributes.formals
let get_pvar_formals attributes =
let pname = attributes.proc_name in
List.map attributes.formals ~f:(fun (name, typ) -> (Pvar.mk name pname, typ))
let get_proc_name attributes = attributes.proc_name
let get_loc attributes = attributes.loc
let default translation_unit proc_name =
{ access= PredSymb.Default
; captured= []

@ -64,6 +64,20 @@ val default : SourceFile.t -> Procname.t -> t
val pp : Format.formatter -> t -> unit
val get_access : t -> PredSymb.access
(** Return the visibility attribute *)
val get_formals : t -> (Mangled.t * Typ.t) list
(** Return name and type of formal parameters *)
val get_annotated_formals : t -> ((Mangled.t * Typ.t) * Annot.Item.t) list
val get_loc : t -> Location.t
(** Return loc information for the procedure *)
val get_proc_name : t -> Procname.t
val get_pvar_formals : t -> (Pvar.t * Typ.t) list
(** Return pvar and type of formal parameters *)
module SQLite : SqliteUtils.Data with type t = t

@ -79,9 +79,8 @@ let log_issue_external procname ~issue_log ?severity_override ~loc ~ltr ?access
issue_log
let is_suppressed ?(field_name = None) tenv proc_desc kind =
let is_suppressed ?(field_name = None) tenv proc_attributes kind =
let lookup = Tenv.lookup tenv in
let proc_attributes = Procdesc.get_attributes proc_desc in
(* Errors can be suppressed with annotations. An error of kind CHECKER_ERROR_NAME can be
suppressed with the following annotations:
- @android.annotation.SuppressLint("checker-error-name")

@ -51,5 +51,6 @@ val log_issue_external :
-> IssueLog.t
(** Log an issue to the error log in [IssueLog] associated with the given procname. *)
val is_suppressed : ?field_name:Fieldname.t option -> Tenv.t -> Procdesc.t -> IssueType.t -> bool
val is_suppressed :
?field_name:Fieldname.t option -> Tenv.t -> ProcAttributes.t -> IssueType.t -> bool
(** should an issue report be suppressed due to a [@SuppressLint("issue")] annotation? *)

@ -63,6 +63,7 @@ let report exe_env work_set =
Summary.OnDisk.get procname
|> Option.fold ~init ~f:(fun acc summary ->
let pdesc = Summary.get_proc_desc summary in
let pattrs = Procdesc.get_attributes pdesc in
let tenv = Exe_env.get_tenv exe_env procname in
let acc =
Starvation.report_on_pair
@ -71,7 +72,7 @@ let report exe_env work_set =
|> Option.bind ~f:(fun summary ->
Option.map summary.Summary.payloads.starvation ~f:(fun starvation ->
(Summary.get_proc_desc summary, starvation) ) ) )
tenv pdesc pair acc
tenv pattrs pair acc
in
match pair.elem.event with
| LockAcquire lock ->
@ -80,7 +81,7 @@ let report exe_env work_set =
in
WorkHashSet.fold
(fun (other_procname, (other_pair : CriticalPair.t)) () acc ->
Starvation.report_on_parallel_composition ~should_report_starvation tenv pdesc
Starvation.report_on_parallel_composition ~should_report_starvation tenv pattrs
pair lock other_procname other_pair acc )
work_set acc
| _ ->

@ -974,10 +974,8 @@ let execute_store ?(report_deref_errors = true) ({InterproceduralAnalysis.tenv;
let is_variadic_procname callee_pname =
Option.value_map
(AnalysisCallbacks.get_proc_desc callee_pname)
~f:(fun proc_desc -> (Procdesc.get_attributes proc_desc).ProcAttributes.is_variadic)
~default:false
Option.value_map ~default:false (AnalysisCallbacks.proc_resolve_attributes callee_pname)
~f:(fun proc_attrs -> proc_attrs.ProcAttributes.is_variadic)
let resolve_and_analyze_no_dynamic_dispatch {InterproceduralAnalysis.analyze_dependency; tenv}

@ -443,7 +443,7 @@ let compute_invariant_map :
let open IOption.Let_syntax in
let get_summary proc_name = analyze_dependency proc_name >>| snd in
let get_formals callee_pname =
AnalysisCallbacks.get_proc_desc callee_pname >>| Procdesc.get_pvar_formals
AnalysisCallbacks.proc_resolve_attributes callee_pname >>| ProcAttributes.get_pvar_formals
in
let integer_type_widths = Exe_env.get_integer_type_widths exe_env proc_name in
let oenv = OndemandEnv.mk proc_desc tenv integer_type_widths in

@ -458,7 +458,7 @@ let checker ({InterproceduralAnalysis.proc_desc; tenv; exe_env; analyze_dependen
analysis_summary
in
let get_formals callee_pname =
AnalysisCallbacks.get_proc_desc callee_pname >>| Procdesc.get_pvar_formals
AnalysisCallbacks.proc_resolve_attributes callee_pname >>| ProcAttributes.get_pvar_formals
in
compute_checks get_checks_summary get_summary get_formals proc_name tenv integer_type_widths
cfg inv_map

@ -285,23 +285,21 @@ module TransferFunctions = struct
{domain with vars}
let is_objc_instance proc_desc_opt =
match proc_desc_opt with
| Some proc_desc -> (
let proc_attrs = Procdesc.get_attributes proc_desc in
match proc_attrs.ProcAttributes.clang_method_kind with
| ClangMethodKind.OBJC_INSTANCE ->
true
| _ ->
false )
let is_objc_instance attributes_opt =
match attributes_opt with
| Some proc_attrs -> (
match proc_attrs.ProcAttributes.clang_method_kind with
| ClangMethodKind.OBJC_INSTANCE ->
true
| _ ->
false )
| None ->
false
let get_annotations proc_desc_opt =
match proc_desc_opt with
| Some proc_desc ->
let proc_attrs = Procdesc.get_attributes proc_desc in
let get_annotations attributes_opt =
match attributes_opt with
| Some proc_attrs ->
Some proc_attrs.ProcAttributes.method_annotation.params
| None ->
None
@ -330,14 +328,14 @@ module TransferFunctions = struct
| _ ->
domain
in
let proc_desc_opt = AnalysisCallbacks.get_proc_desc pname in
let annotations = get_annotations proc_desc_opt in
let attributes_opt = AnalysisCallbacks.proc_resolve_attributes pname in
let annotations = get_annotations attributes_opt in
let args =
if is_objc_instance proc_desc_opt then match args with _ :: rest -> rest | [] -> []
if is_objc_instance attributes_opt then match args with _ :: rest -> rest | [] -> []
else args
in
let annotations =
if is_objc_instance proc_desc_opt then
if is_objc_instance attributes_opt then
match annotations with Some (_ :: rest) -> Some rest | _ -> annotations
else annotations
in

@ -115,8 +115,8 @@ let report_annotation_stack ({InterproceduralAnalysis.proc_desc; err_log} as ana
let report_call_stack end_of_stack lookup_next_calls report call_site sink_map =
let lookup_location pname =
Option.value_map ~f:Procdesc.get_loc ~default:Location.dummy
(AnalysisCallbacks.get_proc_desc pname)
Option.value_map ~f:ProcAttributes.get_loc ~default:Location.dummy
(AnalysisCallbacks.proc_resolve_attributes pname)
in
let rec loop fst_call_loc visited_pnames trace (callee_pname, call_loc) =
if end_of_stack callee_pname then report fst_call_loc trace callee_pname call_loc
@ -206,9 +206,9 @@ end
module CxxAnnotationSpecs = struct
let src_path_of pname =
match AnalysisCallbacks.get_proc_desc pname with
| Some proc_desc ->
let loc = Procdesc.get_loc proc_desc in
match AnalysisCallbacks.proc_resolve_attributes pname with
| Some proc_attrs ->
let loc = ProcAttributes.get_loc proc_attrs in
SourceFile.to_string loc.file
| None ->
""

@ -157,7 +157,8 @@ let check_printf_args_ok tenv (node : Procdesc.Node.t) (instr : Sil.instr) (proc
check_type_names cl (printf.format_pos + 1) pn (format_string_type_names fmt 0)
vararg_ivar_type_names
| None ->
if not (Reporting.is_suppressed tenv proc_desc IssueType.checkers_printf_args) then
let proc_attrs = Procdesc.get_attributes proc_desc in
if not (Reporting.is_suppressed tenv proc_attrs IssueType.checkers_printf_args) then
Reporting.log_issue proc_desc err_log ~loc:cl PrintfArgs
IssueType.checkers_printf_args "Format string must be string literal"
with e ->

@ -86,7 +86,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let is_array t = match t.Typ.desc with Typ.Tarray _ -> true | _ -> false
let get_formals pname =
AnalysisCallbacks.get_proc_desc pname |> Option.map ~f:Procdesc.get_formals
AnalysisCallbacks.proc_resolve_attributes pname |> Option.map ~f:ProcAttributes.get_formals
let should_report_var pdesc tenv maybe_uninit_vars access_expr =

@ -394,7 +394,8 @@ module ReportMap : sig
val empty : t
type report_add_t = Tenv.t -> Procdesc.t -> Location.t -> Errlog.loc_trace -> string -> t -> t
type report_add_t =
Tenv.t -> ProcAttributes.t -> Location.t -> Errlog.loc_trace -> string -> t -> t
val add_deadlock : report_add_t
@ -431,40 +432,41 @@ end = struct
type t = report_t list Location.Map.t
type report_add_t = Tenv.t -> Procdesc.t -> Location.t -> Errlog.loc_trace -> string -> t -> t
type report_add_t =
Tenv.t -> ProcAttributes.t -> Location.t -> Errlog.loc_trace -> string -> t -> t
let empty : t = Location.Map.empty
let add tenv pdesc loc report loc_map =
if Reporting.is_suppressed tenv pdesc (issue_type_of_problem report.problem) then loc_map
let add tenv pattrs loc report loc_map =
if Reporting.is_suppressed tenv pattrs (issue_type_of_problem report.problem) then loc_map
else
Location.Map.update loc
(function reports_opt -> Some (report :: Option.value reports_opt ~default:[]))
loc_map
let add_deadlock tenv pdesc loc ltr message (map : t) =
let pname = Procdesc.get_proc_name pdesc in
let add_deadlock tenv pattrs loc ltr message (map : t) =
let pname = ProcAttributes.get_proc_name pattrs in
let report = {problem= Deadlock (-List.length ltr); pname; ltr; message} in
add tenv pdesc loc report map
add tenv pattrs loc report map
let add_starvation sev tenv pdesc loc ltr message map =
let pname = Procdesc.get_proc_name pdesc in
let add_starvation sev tenv pattrs loc ltr message map =
let pname = ProcAttributes.get_proc_name pattrs in
let report = {pname; problem= Starvation sev; ltr; message} in
add tenv pdesc loc report map
add tenv pattrs loc report map
let add_strict_mode_violation tenv pdesc loc ltr message (map : t) =
let pname = Procdesc.get_proc_name pdesc in
let add_strict_mode_violation tenv pattrs loc ltr message (map : t) =
let pname = ProcAttributes.get_proc_name pattrs in
let report = {problem= StrictModeViolation (-List.length ltr); pname; ltr; message} in
add tenv pdesc loc report map
add tenv pattrs loc report map
let add_lockless_violation tenv pdesc loc ltr message (map : t) =
let pname = Procdesc.get_proc_name pdesc in
let add_lockless_violation tenv pattrs loc ltr message (map : t) =
let pname = ProcAttributes.get_proc_name pattrs in
let report = {problem= LocklessViolation (-List.length ltr); pname; ltr; message} in
add tenv pdesc loc report map
add tenv pattrs loc report map
let issue_log_of loc_map =
@ -563,10 +565,10 @@ let should_report_deadlock_on_current_proc current_elem endpoint_elem =
c < 0 )
let should_report pdesc =
(not (PredSymb.equal_access (Procdesc.get_access pdesc) Private))
let should_report attrs =
(not (PredSymb.equal_access (ProcAttributes.get_access attrs) Private))
&&
match Procdesc.get_proc_name pdesc with
match ProcAttributes.get_proc_name attrs with
| Procname.Java java_pname ->
(not (Procname.Java.is_autogen_method java_pname))
&& not (Procname.Java.is_class_initializer java_pname)
@ -582,9 +584,9 @@ let fold_reportable_summaries analyze_ondemand tenv clazz ~init ~f =
|> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Struct.methods)
in
let f acc mthd =
AnalysisCallbacks.get_proc_desc mthd
|> Option.value_map ~default:acc ~f:(fun other_pdesc ->
if should_report other_pdesc then
AnalysisCallbacks.proc_resolve_attributes mthd
|> Option.value_map ~default:acc ~f:(fun other_attrs ->
if should_report other_attrs then
analyze_ondemand mthd
|> Option.map ~f:(fun (_, payload) -> (mthd, payload))
|> Option.fold ~init:acc ~f
@ -603,10 +605,10 @@ let fold_reportable_summaries analyze_ondemand tenv clazz ~init ~f =
(** report warnings possible on the parallel composition of two threads/critical pairs
[should_report_starvation] means [pair] is on the UI thread and not on a constructor *)
let report_on_parallel_composition ~should_report_starvation tenv pdesc pair lock other_pname
let report_on_parallel_composition ~should_report_starvation tenv pattrs pair lock other_pname
other_pair report_map =
let open Domain in
let pname = Procdesc.get_proc_name pdesc in
let pname = ProcAttributes.get_proc_name pattrs in
let make_trace_and_loc () =
let first_trace = CriticalPair.make_trace ~header:"[Trace 1] " pname pair in
let second_trace = CriticalPair.make_trace ~header:"[Trace 2] " other_pname other_pair in
@ -626,7 +628,7 @@ let report_on_parallel_composition ~should_report_starvation tenv pdesc pair loc
pname_pp pname Lock.pp_locks lock Event.describe event
in
let ltr, loc = make_trace_and_loc () in
ReportMap.add_starvation sev tenv pdesc loc ltr error_message report_map
ReportMap.add_starvation sev tenv pattrs loc ltr error_message report_map
| MonitorWait monitor_lock
when should_report_starvation
&& Acquisitions.lock_is_held_in_other_thread tenv lock acquisitions
@ -637,7 +639,7 @@ let report_on_parallel_composition ~should_report_starvation tenv pdesc pair loc
pname_pp pname Lock.pp_locks lock Event.describe other_pair.CriticalPair.elem.event
in
let ltr, loc = make_trace_and_loc () in
ReportMap.add_starvation High tenv pdesc loc ltr error_message report_map
ReportMap.add_starvation High tenv pattrs loc ltr error_message report_map
| LockAcquire other_lock
when CriticalPair.may_deadlock tenv pair other_pair
&& should_report_deadlock_on_current_proc pair other_pair ->
@ -648,15 +650,15 @@ let report_on_parallel_composition ~should_report_starvation tenv pdesc pair loc
pname_pp pname pname_pp other_pname Lock.describe lock Lock.describe other_lock
in
let ltr, loc = make_trace_and_loc () in
ReportMap.add_deadlock tenv pdesc loc ltr error_message report_map
ReportMap.add_deadlock tenv pattrs loc ltr error_message report_map
| _ ->
report_map
else report_map
let report_on_pair ~analyze_ondemand tenv pdesc (pair : Domain.CriticalPair.t) report_map =
let report_on_pair ~analyze_ondemand tenv pattrs (pair : Domain.CriticalPair.t) report_map =
let open Domain in
let pname = Procdesc.get_proc_name pdesc in
let pname = ProcAttributes.get_proc_name pattrs in
let event = pair.elem.event in
let should_report_starvation =
CriticalPair.is_uithread pair && not (Procname.is_constructor pname)
@ -673,21 +675,21 @@ let report_on_pair ~analyze_ondemand tenv pdesc (pair : Domain.CriticalPair.t) r
Event.describe event
in
let ltr, loc = make_trace_and_loc () in
ReportMap.add_starvation sev tenv pdesc loc ltr error_message report_map
ReportMap.add_starvation sev tenv pattrs loc ltr error_message report_map
| MonitorWait _ when should_report_starvation ->
let error_message =
Format.asprintf "Method %a runs on UI thread and may block; %a." pname_pp pname
Event.describe event
in
let ltr, loc = make_trace_and_loc () in
ReportMap.add_starvation High tenv pdesc loc ltr error_message report_map
ReportMap.add_starvation High tenv pattrs loc ltr error_message report_map
| StrictModeCall _ when should_report_starvation ->
let error_message =
Format.asprintf "Method %a runs on UI thread and may violate Strict Mode; %a." pname_pp
pname Event.describe event
in
let ltr, loc = make_trace_and_loc () in
ReportMap.add_strict_mode_violation tenv pdesc loc ltr error_message report_map
ReportMap.add_strict_mode_violation tenv pattrs loc ltr error_message report_map
| LockAcquire _ when StarvationModels.is_annotated_lockless tenv pname ->
let error_message =
Format.asprintf "Method %a is annotated %s but%a." pname_pp pname
@ -696,14 +698,14 @@ let report_on_pair ~analyze_ondemand tenv pdesc (pair : Domain.CriticalPair.t) r
in
let loc = CriticalPair.get_earliest_lock_or_call_loc ~procname:pname pair in
let ltr = CriticalPair.make_trace pname pair in
ReportMap.add_lockless_violation tenv pdesc loc ltr error_message report_map
ReportMap.add_lockless_violation tenv pattrs loc ltr error_message report_map
| LockAcquire lock when Acquisitions.lock_is_held lock pair.elem.acquisitions ->
let error_message =
Format.asprintf "Potential self deadlock. %a%a twice." pname_pp pname Lock.pp_locks lock
in
let loc = CriticalPair.get_earliest_lock_or_call_loc ~procname:pname pair in
let ltr = CriticalPair.make_trace ~header:"In method " pname pair in
ReportMap.add_deadlock tenv pdesc loc ltr error_message report_map
ReportMap.add_deadlock tenv pattrs loc ltr error_message report_map
| LockAcquire lock when not Config.starvation_whole_program ->
Lock.root_class lock
|> Option.value_map ~default:report_map ~f:(fun other_class ->
@ -714,7 +716,7 @@ let report_on_pair ~analyze_ondemand tenv pdesc (pair : Domain.CriticalPair.t) r
fold_reportable_summaries analyze_ondemand tenv other_class ~init:report_map
~f:(fun acc (other_pname, {critical_pairs}) ->
CriticalPairs.fold
(report_on_parallel_composition ~should_report_starvation tenv pdesc pair lock
(report_on_parallel_composition ~should_report_starvation tenv pattrs pair lock
other_pname)
critical_pairs acc ) )
| _ ->
@ -732,8 +734,9 @@ let reporting {InterproceduralAnalysis.procedures; file_exe_env; analyze_file_de
let report_procedure report_map procname =
analyze_file_dependency procname
|> Option.value_map ~default:report_map ~f:(fun (proc_desc, summary) ->
let attributes = Procdesc.get_attributes proc_desc in
let tenv = Exe_env.get_tenv file_exe_env procname in
if should_report proc_desc then report_on_proc tenv proc_desc report_map summary
if should_report attributes then report_on_proc tenv attributes report_map summary
else report_map )
in
List.fold procedures ~init:ReportMap.empty ~f:report_procedure |> ReportMap.issue_log_of

@ -25,7 +25,7 @@ end
val report_on_pair :
analyze_ondemand:(Procname.t -> (Procdesc.t * StarvationDomain.summary) option)
-> Tenv.t
-> Procdesc.t
-> ProcAttributes.t
-> StarvationDomain.CriticalPair.t
-> ReportMap.t
-> ReportMap.t
@ -33,7 +33,7 @@ val report_on_pair :
val report_on_parallel_composition :
should_report_starvation:bool
-> Tenv.t
-> Procdesc.t
-> ProcAttributes.t
-> StarvationDomain.CriticalPair.t
-> StarvationDomain.Lock.t
-> Procname.t

@ -294,7 +294,7 @@ let checker ({InterproceduralAnalysis.proc_desc; exe_env; analyze_dependency} as
inferbo_summary
in
let get_formals callee_pname =
AnalysisCallbacks.get_proc_desc callee_pname >>| Procdesc.get_pvar_formals
AnalysisCallbacks.proc_resolve_attributes callee_pname >>| ProcAttributes.get_pvar_formals
in
let instr_cfg = InstrCFG.from_pdesc proc_desc in
let extras =

@ -9,7 +9,8 @@ open! IStd
let report_error {IntraproceduralAnalysis.proc_desc; tenv; err_log} checker kind loc
?(field_name = None) ~severity description =
let suppressed = Reporting.is_suppressed tenv proc_desc kind ~field_name in
let proc_attrs = Procdesc.get_attributes proc_desc in
let suppressed = Reporting.is_suppressed tenv proc_attrs kind ~field_name in
if suppressed then Logging.debug Analysis Medium "Reporting is suppressed!@\n"
else
let localized_description = Localise.verbatim_desc description in

@ -49,13 +49,15 @@ module PulseTransferFunctions = struct
type analysis_data = PulseSummary.t InterproceduralAnalysis.t
let get_pvar_formals pname =
AnalysisCallbacks.proc_resolve_attributes pname |> Option.map ~f:ProcAttributes.get_pvar_formals
let interprocedural_call {InterproceduralAnalysis.analyze_dependency} ret call_exp actuals
call_loc astate =
match proc_name_of_call call_exp with
| Some callee_pname when not Config.pulse_intraprocedural_only ->
let formals_opt =
AnalysisCallbacks.get_proc_desc callee_pname |> Option.map ~f:Procdesc.get_pvar_formals
in
let formals_opt = get_pvar_formals callee_pname in
let callee_data = analyze_dependency callee_pname in
PulseOperations.call ~callee_data call_loc callee_pname ~ret ~actuals ~formals_opt astate
| _ ->

Loading…
Cancel
Save