From d9535f42d591d63885f4fc7f6d77283ccaf8da44 Mon Sep 17 00:00:00 2001 From: Phoebe Nichols Date: Tue, 9 Jul 2019 05:57:37 -0700 Subject: [PATCH] Introduce method SummaryPayload.read_toplevel_procedure Summary: Cluster checkers call `SummaryPayload.read` but set the `caller_summary` to correspond to the same summary as gives the `callee_pname` This change introduces a new method `read_toplevel_procedure` that does not require a `caller_summary`, to be used by the cluster checkers Reviewed By: ngorogiannis Differential Revision: D16131660 fbshipit-source-id: 12caa1000 --- infer/src/absint/SummaryPayload.ml | 28 ++++++---- infer/src/absint/SummaryPayload.mli | 8 ++- infer/src/backend/callbacks.ml | 8 +-- infer/src/backend/callbacks.mli | 2 +- infer/src/checkers/Litho.ml | 6 +- infer/src/checkers/Siof.ml | 39 +++++++------ infer/src/checkers/annotationReachability.ml | 11 ++-- infer/src/checkers/classLoads.ml | 59 ++++++++++---------- infer/src/checkers/purity.ml | 8 +-- infer/src/checkers/uninit.ml | 22 ++++---- infer/src/concurrency/RacerD.ml | 11 ++-- infer/src/concurrency/starvation.ml | 19 ++++--- infer/src/pulse/PulseOperations.ml | 2 +- infer/src/quandary/TaintAnalysis.ml | 4 +- 14 files changed, 121 insertions(+), 106 deletions(-) diff --git a/infer/src/absint/SummaryPayload.ml b/infer/src/absint/SummaryPayload.ml index 886ee9493..ebe408aa9 100644 --- a/infer/src/absint/SummaryPayload.ml +++ b/infer/src/absint/SummaryPayload.ml @@ -20,9 +20,12 @@ module type S = sig val of_summary : Summary.t -> t option - val read_full : Procdesc.t -> Typ.Procname.t -> (Procdesc.t * t) option + val read_full : + caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> (Procdesc.t * t) option - val read : Procdesc.t -> Typ.Procname.t -> t option + val read : caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> t option + + val read_toplevel_procedure : Typ.Procname.t -> t option end module Make (P : Payload) : S with type t = P.t = struct @@ -38,16 +41,21 @@ module Make (P : Payload) : S with type t = P.t = struct let of_summary (summary : Summary.t) = of_payloads summary.payloads - let read_full caller_pdesc callee_pname = + let read_all ?caller_summary ~callee_pname = let open Option.Monad_infix in - Ondemand.analyze_proc_name ~caller_pdesc callee_pname + Ondemand.analyze_proc_name + ?caller_pdesc:(Option.map ~f:Summary.get_proc_desc caller_summary) + callee_pname >>= fun summary -> - of_summary summary - >>| fun payload -> - (* we could return the proc_desc if some client needed this but this would complicate the return - type so for now let's not do that *) - (Summary.get_proc_desc summary, payload) + of_summary summary >>| fun payload -> (Summary.get_proc_desc summary, payload) + + + let read_full ~caller_summary ~callee_pname = read_all ~caller_summary ~callee_pname + + let read ~caller_summary ~callee_pname = + read_all ~caller_summary ~callee_pname |> Option.map ~f:snd - let read caller_pdesc callee_pname = read_full caller_pdesc callee_pname |> Option.map ~f:snd + let read_toplevel_procedure callee_pname = + read_all ?caller_summary:None ~callee_pname |> Option.map ~f:snd end diff --git a/infer/src/absint/SummaryPayload.mli b/infer/src/absint/SummaryPayload.mli index 53e674af7..10427ce78 100644 --- a/infer/src/absint/SummaryPayload.mli +++ b/infer/src/absint/SummaryPayload.mli @@ -22,13 +22,15 @@ module type S = sig val of_summary : Summary.t -> t option (** Read the corresponding part of the payload from the procedure summary *) - val read_full : Procdesc.t -> Typ.Procname.t -> (Procdesc.t * t) option - [@@warning "-32"] + val read_full : + caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> (Procdesc.t * t) option (** Return the proc desc and payload for the given procedure. Runs the analysis on-demand if necessary. *) - val read : Procdesc.t -> Typ.Procname.t -> t option + val read : caller_summary:Summary.t -> callee_pname:Typ.Procname.t -> t option (** Return the payload for the given procedure. Runs the analysis on-demand if necessary. *) + + val read_toplevel_procedure : Typ.Procname.t -> t option end module Make (P : Payload) : S with type t = P.t diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index dde6b8519..0617c89c6 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -19,7 +19,7 @@ type proc_callback_args = type proc_callback_t = proc_callback_args -> Summary.t type cluster_callback_args = - {procedures: (Tenv.t * Procdesc.t) list; source_file: SourceFile.t; exe_env: Exe_env.t} + {procedures: (Tenv.t * Summary.t) list; source_file: SourceFile.t; exe_env: Exe_env.t} type cluster_callback_t = cluster_callback_args -> unit @@ -46,7 +46,7 @@ let get_procedure_definition exe_env proc_name = Procdesc.load proc_name |> Option.map ~f:(fun proc_desc -> let tenv = Exe_env.get_tenv exe_env proc_name in - (tenv, proc_desc) ) + (tenv, Summary.reset proc_desc) ) (** Invoke all registered procedure callbacks on the given procedure. *) @@ -91,8 +91,8 @@ let iterate_cluster_callbacks all_procs exe_env source_file = let environment = {procedures; source_file; exe_env} in let language_matches language = match procedures with - | (_, pdesc) :: _ -> - Language.equal language (Typ.Procname.get_language (Procdesc.get_proc_name pdesc)) + | (_, summary) :: _ -> + Language.equal language (Typ.Procname.get_language (Summary.get_proc_name summary)) | _ -> true in diff --git a/infer/src/backend/callbacks.mli b/infer/src/backend/callbacks.mli index 8b4254d3e..713a1defe 100644 --- a/infer/src/backend/callbacks.mli +++ b/infer/src/backend/callbacks.mli @@ -24,7 +24,7 @@ type proc_callback_args = type proc_callback_t = proc_callback_args -> Summary.t type cluster_callback_args = - {procedures: (Tenv.t * Procdesc.t) list; source_file: SourceFile.t; exe_env: Exe_env.t} + {procedures: (Tenv.t * Summary.t) list; source_file: SourceFile.t; exe_env: Exe_env.t} type cluster_callback_t = cluster_callback_args -> unit diff --git a/infer/src/checkers/Litho.ml b/infer/src/checkers/Litho.ml index 69f1e8047..899c2e63d 100644 --- a/infer/src/checkers/Litho.ml +++ b/infer/src/checkers/Litho.ml @@ -216,7 +216,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct , _ , _ ) -> let domain_summary = - Payload.read (Summary.get_proc_desc proc_data.summary) callee_procname + Payload.read ~caller_summary:proc_data.summary ~callee_pname:callee_procname in let receiver = Domain.LocalAccessPath.make @@ -247,7 +247,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct (* treat it like a normal call *) apply_callee_summary domain_summary caller_pname return_base actuals astate | Call (ret_id_typ, Direct callee_procname, actuals, _, _) -> - let summary = Payload.read (Summary.get_proc_desc proc_data.summary) callee_procname in + let summary = + Payload.read ~caller_summary:proc_data.summary ~callee_pname:callee_procname + in apply_callee_summary summary caller_pname ret_id_typ actuals astate | Assign (lhs_ae, HilExp.AccessExpression rhs_ae, _) -> ( (* creating an alias for the rhs binding; assume all reads will now occur through the diff --git a/infer/src/checkers/Siof.ml b/infer/src/checkers/Siof.ml index 5a39ccb87..ed3152c3e 100644 --- a/infer/src/checkers/Siof.ml +++ b/infer/src/checkers/Siof.ml @@ -69,9 +69,12 @@ module TransferFunctions (CFG : ProcCfg.S) = struct type extras = ProcData.no_extras - let is_compile_time_constructed pdesc pv = + let is_compile_time_constructed summary pv = let init_pname = Pvar.get_initializer_pname pv in - match Option.bind init_pname ~f:(Payload.read pdesc) with + match + Option.bind init_pname ~f:(fun callee_pname -> + Payload.read ~caller_summary:summary ~callee_pname ) + with | Some (Bottom, _) -> (* we analyzed the initializer for this global and found that it doesn't require any runtime initialization so cannot participate in SIOF *) @@ -94,13 +97,13 @@ module TransferFunctions (CFG : ProcCfg.S) = struct Staged.unstage (filter_global_accesses (Domain.VarNames.of_list always_initialized)) - let get_globals pdesc e = + let get_globals summary e = let is_dangerous_global pv = Pvar.is_global pv && (not (Pvar.is_static_local pv)) && (not (Pvar.is_pod pv)) && (not (Pvar.is_compile_constant pv)) - && (not (is_compile_time_constructed pdesc pv)) + && (not (is_compile_time_constructed summary pv)) && is_not_always_initialized pv in Exp.program_vars e @@ -127,20 +130,19 @@ module TransferFunctions (CFG : ProcCfg.S) = struct (NonBottom trace_with_non_init_globals, snd astate) - let add_actuals_globals astate0 pdesc call_loc actuals = + let add_actuals_globals astate0 summary call_loc actuals = List.fold_left actuals ~init:astate0 ~f:(fun astate (e, _) -> - get_globals pdesc e |> add_globals astate call_loc ) + get_globals summary e |> add_globals astate call_loc ) let at_least_nonbottom = Domain.join (NonBottom SiofTrace.bottom, Domain.VarNames.empty) let exec_instr astate {ProcData.summary} _ (instr : Sil.instr) = - let pdesc = Summary.get_proc_desc summary in match instr with | Store (Lvar global, Typ.{desc= Tptr _}, Lvar _, loc) when (Option.equal Typ.Procname.equal) (Pvar.get_initializer_pname global) - (Some (Procdesc.get_proc_name pdesc)) -> + (Some (Summary.get_proc_name summary)) -> (* if we are just taking the reference of another global then we are not really accessing it. This is a dumb heuristic as something also might take that result and then dereference it, thus requiring the target object to be initialized. Solving this would @@ -152,7 +154,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | Load (_, exp, _, loc) (* dereference -> add all the dangerous variables *) | Store (_, _, exp, loc) (* except in the case above, consider all reads as dangerous *) | Prune (exp, loc, _, _) -> - get_globals pdesc exp |> add_globals astate loc + get_globals summary exp |> add_globals astate loc | Call (_, Const (Cfun callee_pname), _, _, _) when is_whitelisted callee_pname -> at_least_nonbottom astate | Call (_, Const (Cfun callee_pname), _, _, _) when is_modelled callee_pname -> @@ -169,10 +171,10 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | Call (_, Const (Cfun (ObjC_Cpp cpp_pname as callee_pname)), _ :: actuals_without_self, loc, _) when Typ.Procname.is_constructor callee_pname && Typ.Procname.ObjC_Cpp.is_constexpr cpp_pname -> - add_actuals_globals astate pdesc loc actuals_without_self + add_actuals_globals astate summary loc actuals_without_self | Call (_, Const (Cfun callee_pname), actuals, loc, _) -> let callee_astate = - match Payload.read pdesc callee_pname with + match Payload.read ~caller_summary:summary ~callee_pname with | Some (NonBottom trace, initialized_by_callee) -> let already_initialized = snd astate in let dangerous_accesses = @@ -193,12 +195,12 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | None -> (Bottom, Domain.VarNames.empty) in - add_actuals_globals astate pdesc loc actuals + add_actuals_globals astate summary loc actuals |> Domain.join callee_astate |> (* make sure it's not Bottom: we made a function call so this needs initialization *) at_least_nonbottom | Call (_, _, actuals, loc, _) -> - add_actuals_globals astate pdesc loc actuals + add_actuals_globals astate summary loc actuals |> (* make sure it's not Bottom: we made a function call so this needs initialization *) at_least_nonbottom | Metadata _ -> @@ -218,9 +220,9 @@ let is_foreign current_tu v = true -let report_siof summary trace pdesc gname loc = +let report_siof summary trace gname loc = let trace_of_pname pname = - match Payload.read pdesc pname with + match Payload.read ~caller_summary:summary ~callee_pname:pname with | Some (NonBottom summary, _) -> summary | _ -> @@ -244,7 +246,8 @@ let report_siof summary trace pdesc gname loc = else List.iter ~f:report_one_path reportable_paths -let siof_check pdesc gname (summary : Summary.t) = +let siof_check gname (summary : Summary.t) = + let pdesc = Summary.get_proc_desc summary in match summary.payloads.siof with | Some (NonBottom post, _) -> let attrs = Procdesc.get_attributes pdesc in @@ -260,7 +263,7 @@ let siof_check pdesc gname (summary : Summary.t) = if not (SiofTrace.Sinks.is_empty foreign_sinks) then report_siof summary (SiofTrace.update_sinks post foreign_sinks) - pdesc gname attrs.ProcAttributes.loc + gname attrs.ProcAttributes.loc | Some (Bottom, _) | None -> () @@ -310,7 +313,7 @@ let checker {Callbacks.tenv; summary; get_procs_in_file} : Summary.t = in ( match Typ.Procname.get_global_name_of_initializer pname with | Some gname -> - siof_check proc_desc gname updated_summary + siof_check gname updated_summary | None -> () ) ; updated_summary diff --git a/infer/src/checkers/annotationReachability.ml b/infer/src/checkers/annotationReachability.ml index 4720b9f55..0e7cc131f 100644 --- a/infer/src/checkers/annotationReachability.ml +++ b/infer/src/checkers/annotationReachability.ml @@ -567,15 +567,15 @@ module TransferFunctions (CFG : ProcCfg.S) = struct specs - let merge_callee_map call_site pdesc callee_pname tenv specs astate = - match Payload.read pdesc callee_pname with + let merge_callee_map call_site summary callee_pname tenv specs astate = + match Payload.read ~caller_summary:summary ~callee_pname with | None -> astate | Some callee_call_map -> let add_call_site annot sink calls astate = if AnnotReachabilityDomain.CallSites.is_empty calls then astate else - let pname = Procdesc.get_proc_name pdesc in + let pname = Summary.get_proc_name summary in List.fold ~f:(fun astate (spec : AnnotationSpec.t) -> if spec.sanitizer_predicate tenv pname then astate @@ -592,11 +592,10 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | Sil.Call ((id, _), Const (Cfun callee_pname), _, _, _) when is_unlikely callee_pname -> Domain.add_tracking_var (Var.of_id id) astate | Sil.Call (_, Const (Cfun callee_pname), _, call_loc, _) -> - let pdesc = Summary.get_proc_desc summary in - let caller_pname = Procdesc.get_proc_name pdesc in + let caller_pname = Summary.get_proc_name summary in let call_site = CallSite.make callee_pname call_loc in check_call tenv callee_pname caller_pname call_site astate extras - |> merge_callee_map call_site pdesc callee_pname tenv extras + |> merge_callee_map call_site summary callee_pname tenv extras | Sil.Load (id, exp, _, _) when is_tracking_exp astate exp -> Domain.add_tracking_var (Var.of_id id) astate | Sil.Store (Exp.Lvar pvar, _, exp, _) when is_tracking_exp astate exp -> diff --git a/infer/src/checkers/classLoads.ml b/infer/src/checkers/classLoads.ml index 86882cff1..6ea07dc58 100644 --- a/infer/src/checkers/classLoads.ml +++ b/infer/src/checkers/classLoads.ml @@ -22,12 +22,13 @@ module Payload = SummaryPayload.Make (struct let field = Payloads.Fields.class_loads end) -let do_call pdesc callee loc init = - Payload.read pdesc callee |> Option.fold ~init ~f:(ClassLoadsDomain.integrate_summary callee loc) +let do_call summary callee loc init = + Payload.read ~caller_summary:summary ~callee_pname:callee + |> Option.fold ~init ~f:(ClassLoadsDomain.integrate_summary callee loc) (** fully load a class given the typename *) -let rec load_class proc_desc tenv loc astate class_name = +let rec load_class summary tenv loc astate class_name = (* don't bother if class is already loaded *) if ClassLoadsDomain.mem_typename class_name astate then astate else @@ -37,78 +38,78 @@ let rec load_class proc_desc tenv loc astate class_name = let astate2 = let class_initializer = Typ.Procname.(Java (Java.get_class_initializer class_name)) in (* NB may recurse if we are in class init but the shortcircuiting above makes it a no-op *) - do_call proc_desc class_initializer loc astate1 + do_call summary class_initializer loc astate1 in (* finally, recursively load all superclasses *) Tenv.lookup tenv class_name |> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Typ.Struct.supers) - |> List.fold ~init:astate2 ~f:(load_class proc_desc tenv loc) + |> List.fold ~init:astate2 ~f:(load_class summary tenv loc) -let load_type proc_desc tenv loc (typ : Typ.t) astate = +let load_type summary tenv loc (typ : Typ.t) astate = match typ with | {desc= Tstruct name} | {desc= Tptr ({desc= Tstruct name}, _)} -> - load_class proc_desc tenv loc astate name + load_class summary tenv loc astate name | _ -> astate -let rec load_array proc_desc tenv loc (typ : Typ.t) astate = +let rec load_array summary tenv loc (typ : Typ.t) astate = match typ with | {desc= Tarray {elt}} -> - load_array proc_desc tenv loc elt astate + load_array summary tenv loc elt astate | _ -> - load_type proc_desc tenv loc typ astate + load_type summary tenv loc typ astate -let rec add_loads_of_exp proc_desc tenv loc (exp : Exp.t) astate = +let rec add_loads_of_exp summary tenv loc (exp : Exp.t) astate = match exp with | Const (Cclass class_ident) -> (* [X.class] expressions *) let class_str = Ident.name_to_string class_ident |> Mangled.from_string in let class_name = Typ.JavaClass class_str in - load_class proc_desc tenv loc astate class_name + load_class summary tenv loc astate class_name | Sizeof {typ= {desc= Tarray {elt}}} -> (* anewarray / multinewarray *) - load_array proc_desc tenv loc elt astate + load_array summary tenv loc elt astate | Cast (_, e) | UnOp (_, e, _) | Exn e -> (* NB Cast is only used for primitive types *) - add_loads_of_exp proc_desc tenv loc e astate + add_loads_of_exp summary tenv loc e astate | BinOp (_, e1, e2) -> - add_loads_of_exp proc_desc tenv loc e1 astate |> add_loads_of_exp proc_desc tenv loc e2 + add_loads_of_exp summary tenv loc e1 astate |> add_loads_of_exp summary tenv loc e2 | Lfield (e, _, typ') -> (* getfield / getstatic / putfield / putstatic *) - load_type proc_desc tenv loc typ' astate |> add_loads_of_exp proc_desc tenv loc e + load_type summary tenv loc typ' astate |> add_loads_of_exp summary tenv loc e | Var _ | Const _ | Closure _ | Sizeof _ | Lindex _ | Lvar _ -> astate -let exec_call pdesc tenv callee args loc astate = +let exec_call summary tenv callee args loc astate = match args with | [_; (Exp.Sizeof {typ}, _)] when Typ.Procname.equal callee BuiltinDecl.__instanceof -> (* this matches downcasts/instanceof and exception handlers *) - load_type pdesc tenv loc typ astate + load_type summary tenv loc typ astate | _ -> (* invokeinterface / invokespecial / invokestatic / invokevirtual / new *) - List.fold args ~init:astate ~f:(fun acc (exp, _) -> add_loads_of_exp pdesc tenv loc exp acc) - |> do_call pdesc callee loc + List.fold args ~init:astate ~f:(fun acc (exp, _) -> add_loads_of_exp summary tenv loc exp acc) + |> do_call summary callee loc -let exec_instr pdesc tenv astate _ (instr : Sil.instr) = +let exec_instr summary tenv astate _ (instr : Sil.instr) = match instr with | Call (_, Const (Cfun callee), args, loc, _) -> - exec_call pdesc tenv callee args loc astate + exec_call summary tenv callee args loc astate | Load (_, exp, _, loc) | Prune (exp, loc, _, _) -> (* NB the java frontend seems to always translate complex guards into a sequence of instructions plus a prune on logical vars only. So the below is only for completeness. *) - add_loads_of_exp pdesc tenv loc exp astate + add_loads_of_exp summary tenv loc exp astate | Store (e1, _, e2, loc) -> - add_loads_of_exp pdesc tenv loc e1 astate |> add_loads_of_exp pdesc tenv loc e2 + add_loads_of_exp summary tenv loc e1 astate |> add_loads_of_exp summary tenv loc e2 | _ -> astate -let report_loads proc_desc summary astate = +let report_loads summary astate = let report_load ({ClassLoadsDomain.Event.loc; elem} as event) = if String.is_prefix ~prefix:"java." elem then () else @@ -116,7 +117,7 @@ let report_loads proc_desc summary astate = let msg = Format.asprintf "Class %s loaded" elem in Reporting.log_warning summary ~loc ~ltr IssueType.class_load msg in - let pname = Procdesc.get_proc_name proc_desc in + let pname = Summary.get_proc_name summary in Typ.Procname.get_class_name pname |> Option.iter ~f:(fun clazz -> let method_strname = Typ.Procname.get_method pname in @@ -133,10 +134,10 @@ let analyze_procedure {Callbacks.tenv; summary} = (* load the method's class *) let init = Typ.Procname.get_class_type_name proc_name - |> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class proc_desc tenv loc) + |> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class summary tenv loc) in - let post = Procdesc.fold_instrs proc_desc ~init ~f:(exec_instr proc_desc tenv) in - report_loads proc_desc summary post ; + let post = Procdesc.fold_instrs proc_desc ~init ~f:(exec_instr summary tenv) in + report_loads summary post ; let result = Payload.update_summary post summary in L.debug Analysis Verbose "CL: FINISHED ANALYZING %a@." Typ.Procname.pp proc_name ; result diff --git a/infer/src/checkers/purity.ml b/infer/src/checkers/purity.ml index 1b38ab346..9ff2ad815 100644 --- a/infer/src/checkers/purity.ml +++ b/infer/src/checkers/purity.ml @@ -197,7 +197,8 @@ let should_report pdesc = true -let report_errors pdesc astate summary = +let report_errors astate summary = + let pdesc = Summary.get_proc_desc summary in let proc_name = Procdesc.get_proc_name pdesc in match astate with | Some astate -> @@ -224,13 +225,12 @@ let compute_summary summary tenv get_callee_summary inferbo_invariant_map = let checker {Callbacks.tenv; summary; integer_type_widths} : Summary.t = - let proc_desc = Summary.get_proc_desc summary in let inferbo_invariant_map = BufferOverrunAnalysis.cached_compute_invariant_map summary tenv integer_type_widths in - let get_callee_summary = Payload.read proc_desc in + let get_callee_summary callee_pname = Payload.read ~caller_summary:summary ~callee_pname in let astate = compute_summary summary tenv get_callee_summary inferbo_invariant_map in - report_errors proc_desc astate summary ; + report_errors astate summary ; match astate with | Some astate -> debug "Purity summary :%a \n" PurityDomain.pp astate ; diff --git a/infer/src/checkers/uninit.ml b/infer/src/checkers/uninit.ml index 21bacff73..98cb3aca8 100644 --- a/infer/src/checkers/uninit.ml +++ b/infer/src/checkers/uninit.ml @@ -99,14 +99,13 @@ module TransferFunctions (CFG : ProcCfg.S) = struct || is_array_element_passed_by_ref callee_formals t access_expr idx - let report_on_function_params pdesc tenv maybe_uninit_vars actuals loc summary callee_formals_opt - = + let report_on_function_params tenv maybe_uninit_vars actuals loc summary callee_formals_opt = List.iteri actuals ~f:(fun idx e -> match HilExp.ignore_cast e with | HilExp.AccessExpression access_expr -> let _, t = HilExp.AccessExpression.get_base access_expr in if - should_report_var pdesc tenv maybe_uninit_vars access_expr + should_report_var (Summary.get_proc_desc summary) tenv maybe_uninit_vars access_expr && (not (Typ.is_pointer t)) && not (Option.exists callee_formals_opt ~f:(fun callee_formals -> @@ -153,8 +152,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct else None - let remove_initialized_params pdesc call maybe_uninit_vars idx access_expr remove_fields = - match Payload.read pdesc call with + let remove_initialized_params summary call maybe_uninit_vars idx access_expr remove_fields = + match Payload.read ~caller_summary:summary ~callee_pname:call with | Some {pre= init_formals; post= _} -> ( match init_nth_actual_param call idx init_formals with | Some var_formal -> @@ -171,8 +170,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct (* true if a function initializes at least a param or a field of a struct param *) - let function_initializes_some_formal_params pdesc call = - match Payload.read pdesc call with + let function_initializes_some_formal_params summary call = + match Payload.read ~caller_summary:summary ~callee_pname:call with | Some {pre= initialized_formal_params; post= _} -> not (D.is_empty initialized_formal_params) | _ -> @@ -234,7 +233,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct (* if it's a default constructor, we use the following heuristic: we assume that it initializes correctly all fields when there is an implementation of the constructor that initilizes at least one field. If there is no explicit implementation we cannot assume fields are initialized *) - if function_initializes_some_formal_params pdesc call then + if function_initializes_some_formal_params summary call then let maybe_uninit_vars = (* in HIL/SIL the default constructor has only one param: the struct *) MaybeUninitVars.remove_all_fields tenv base astate.maybe_uninit_vars @@ -269,7 +268,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct ~f:(is_fld_or_array_elem_passed_by_ref t access_expr idx) -> ( match pname_opt with | Some pname when Config.uninit_interproc -> - remove_initialized_params pdesc pname acc idx access_expr_to_remove false + remove_initialized_params summary pname acc idx access_expr_to_remove false | _ -> MaybeUninitVars.remove access_expr_to_remove acc ) | base when Option.exists pname_opt ~f:Typ.Procname.is_constructor -> @@ -278,7 +277,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | _, {Typ.desc= Tptr _} -> ( match pname_opt with | Some pname when Config.uninit_interproc -> - remove_initialized_params pdesc pname acc idx access_expr_to_remove true + remove_initialized_params summary pname acc idx access_expr_to_remove true | _ -> MaybeUninitVars.remove_everything_under tenv access_expr_to_remove acc ) | _ -> @@ -292,8 +291,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct in ( match call with | Direct _ -> - report_on_function_params pdesc tenv maybe_uninit_vars actuals loc summary - callee_formals_opt + report_on_function_params tenv maybe_uninit_vars actuals loc summary callee_formals_opt | Indirect _ -> () ) ; {astate with maybe_uninit_vars} diff --git a/infer/src/concurrency/RacerD.ml b/infer/src/concurrency/RacerD.ml index bb0f0af7d..3708f05ef 100644 --- a/infer/src/concurrency/RacerD.ml +++ b/infer/src/concurrency/RacerD.ml @@ -322,7 +322,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct astate | NoEffect -> ( let rebased_summary_opt = - Payload.read pdesc callee_pname + Payload.read ~caller_summary:summary ~callee_pname |> Option.map ~f:(fun summary -> let rebased_accesses = Ondemand.get_proc_desc callee_pname @@ -1170,15 +1170,16 @@ let make_results_table file_env = (fun snapshot acc -> ReportMap.add {threads; snapshot; tenv; procdesc} acc) accesses acc in - List.fold file_env ~init:ReportMap.empty ~f:(fun acc (tenv, proc_desc) -> - Procdesc.get_proc_name proc_desc |> Payload.read proc_desc - |> Option.fold ~init:acc ~f:(aggregate_post tenv proc_desc) ) + List.fold file_env ~init:ReportMap.empty ~f:(fun acc (tenv, summary) -> + Payload.read_toplevel_procedure (Summary.get_proc_name summary) + |> Option.fold ~init:acc ~f:(aggregate_post tenv (Summary.get_proc_desc summary)) ) (* aggregate all of the procedures in the file env by their declaring class. this lets us analyze each class individually *) let aggregate_by_class file_env = - List.fold file_env ~init:String.Map.empty ~f:(fun acc ((tenv, pdesc) as proc) -> + List.fold file_env ~init:String.Map.empty ~f:(fun acc ((tenv, summary) as proc) -> + let pdesc = Summary.get_proc_desc summary in if should_report_on_proc tenv pdesc then Procdesc.get_proc_name pdesc |> Typ.Procname.get_class_name |> Option.fold ~init:acc ~f:(fun acc classname -> diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index ef907fee5..a02357bc0 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -81,7 +81,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct in let do_unlock locks astate = List.filter_map ~f:get_lock_path locks |> Domain.release astate in let do_call callee loc astate = - Payload.read (Summary.get_proc_desc summary) callee + Payload.read ~caller_summary:summary ~callee_pname:callee |> Option.value_map ~default:astate ~f:(Domain.integrate_summary tenv astate callee loc) in match instr with @@ -327,7 +327,7 @@ let should_report pdesc = false -let fold_reportable_summaries (tenv, current_pdesc) clazz ~init ~f = +let fold_reportable_summaries (tenv, current_summary) clazz ~init ~f = let methods = Tenv.lookup tenv clazz |> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Typ.Struct.methods) @@ -336,7 +336,7 @@ let fold_reportable_summaries (tenv, current_pdesc) clazz ~init ~f = Ondemand.get_proc_desc mthd |> Option.value_map ~default:acc ~f:(fun other_pdesc -> if should_report other_pdesc then - Payload.read current_pdesc mthd + Payload.read ~caller_summary:current_summary ~callee_pname:mthd |> Option.map ~f:(fun payload -> (mthd, payload)) |> Option.fold ~init:acc ~f else acc ) @@ -353,8 +353,8 @@ let fold_reportable_summaries (tenv, current_pdesc) clazz ~init ~f = once, as opposed to twice with all other deadlock pairs. *) let report_deadlocks env {StarvationDomain.order; ui} report_map' = let open StarvationDomain in - let _, current_pdesc = env in - let current_pname = Procdesc.get_proc_name current_pdesc in + let _, current_summary = env in + let current_pname = Summary.get_proc_name current_summary in let report_endpoint_elem current_elem endpoint_pname elem report_map = if not @@ -409,8 +409,8 @@ let report_deadlocks env {StarvationDomain.order; ui} report_map' = let report_starvation env {StarvationDomain.events; ui} report_map' = let open StarvationDomain in - let _, current_pdesc = env in - let current_pname = Procdesc.get_proc_name current_pdesc in + let _, current_summary = env in + let current_pname = Summary.get_proc_name current_summary in let report_remote_block ui_explain event current_lock endpoint_pname endpoint_elem report_map = let lock = endpoint_elem.Order.elem.first in match endpoint_elem.Order.elem.eventually.elem with @@ -489,9 +489,10 @@ let report_starvation env {StarvationDomain.events; ui} report_map' = let reporting {Callbacks.procedures; source_file} = - let report_procedure issue_log ((tenv, proc_desc) as env) = + let report_procedure issue_log ((tenv, summary) as env) = + let proc_desc = Summary.get_proc_desc summary in if should_report proc_desc then - Payload.read proc_desc (Procdesc.get_proc_name proc_desc) + Payload.read_toplevel_procedure (Procdesc.get_proc_name proc_desc) |> Option.value_map ~default:issue_log ~f:(fun summary -> report_deadlocks env summary ReportMap.empty |> report_starvation env summary diff --git a/infer/src/pulse/PulseOperations.ml b/infer/src/pulse/PulseOperations.ml index d5856a95c..e0b6a366c 100644 --- a/infer/src/pulse/PulseOperations.ml +++ b/infer/src/pulse/PulseOperations.ml @@ -305,7 +305,7 @@ let remove_vars vars astate = let call ~caller_summary call_loc callee_pname ~ret ~actuals astate = - match PulsePayload.read_full caller_summary.Summary.proc_desc callee_pname with + match PulsePayload.read_full ~caller_summary ~callee_pname with | Some (callee_proc_desc, preposts) -> let formals = Procdesc.get_formals callee_proc_desc diff --git a/infer/src/quandary/TaintAnalysis.ml b/infer/src/quandary/TaintAnalysis.ml index 6c7d05d13..100820fd8 100644 --- a/infer/src/quandary/TaintAnalysis.ml +++ b/infer/src/quandary/TaintAnalysis.ml @@ -128,7 +128,7 @@ module Make (TaintSpecification : TaintSpec.S) = struct (* read_summary will trigger ondemand analysis of the current proc. we don't want that. *) TaintDomain.bottom else - match Payload.read (Summary.get_proc_desc proc_data.summary) pname with + match Payload.read ~caller_summary:proc_data.summary ~callee_pname:pname with | Some summary -> TaintSpecification.of_summary_access_tree summary | None -> @@ -655,7 +655,7 @@ module Make (TaintSpecification : TaintSpec.S) = struct add_actual_source source index actuals astate_with_sink proc_data ) in let astate_with_summary = - match Payload.read (Summary.get_proc_desc proc_data.summary) callee_pname with + match Payload.read ~caller_summary:proc_data.summary ~callee_pname with | None -> handle_unknown_call callee_pname astate_with_direct_sources | Some summary -> (