diff --git a/infer/lib/python/inferlib/analyze.py b/infer/lib/python/inferlib/analyze.py index 25ef18402..2a782cd4f 100644 --- a/infer/lib/python/inferlib/analyze.py +++ b/infer/lib/python/inferlib/analyze.py @@ -373,7 +373,7 @@ class Infer: infer_options += ['-allow_specs_cleanup'] if self.args.analyzer == config.ANALYZER_ERADICATE: - infer_options += ['-checkers', '-eradicate'] + infer_options += ['-eradicate'] elif self.args.analyzer == config.ANALYZER_CHECKERS: infer_options += ['-checkers'] else: diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index 12ee05775..719060de9 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -12,14 +12,16 @@ module L = Logging (** Module to register and invoke callbacks *) -type proc_callback_t = - Procname.t list -> - (Procname.t -> Cfg.Procdesc.t option) -> - Idenv.t -> - Sil.tenv -> - Procname.t -> - Cfg.Procdesc.t -> - unit +type proc_callback_args = { + get_proc_desc : Procname.t -> Cfg.Procdesc.t option; + get_procs_in_file : Procname.t -> Procname.t list; + idenv : Idenv.t; + tenv : Sil.tenv; + proc_name : Procname.t; + proc_desc : Cfg.Procdesc.t; +} + +type proc_callback_t = proc_callback_args -> unit type cluster_callback_t = Procname.t list -> @@ -55,14 +57,18 @@ let get_procedure_definition exe_env proc_name = let get_language proc_name = if Procname.is_java proc_name then Config.Java else Config.C_CPP (** Invoke all registered procedure callbacks on a set of procedures. *) -let iterate_procedure_callbacks all_procs exe_env proc_name = +let iterate_procedure_callbacks exe_env proc_name = let procedure_language = get_language proc_name in Config.curr_language := procedure_language; let cfg = Exe_env.get_cfg exe_env proc_name in - let get_procdesc proc_name = + let get_proc_desc proc_name = let cfg = try Exe_env.get_cfg exe_env proc_name with Not_found -> cfg in Cfg.Procdesc.find_from_name cfg proc_name in + let get_procs_in_file proc_name = + let cfg = try Exe_env.get_cfg exe_env proc_name with Not_found -> cfg in + IList.map Cfg.Procdesc.get_proc_name (Cfg.get_defined_procs cfg) in + let update_time proc_name elapsed = match Specs.get_summary proc_name with @@ -83,7 +89,15 @@ let iterate_procedure_callbacks all_procs exe_env proc_name = if language_matches then begin let init_time = Unix.gettimeofday () in - proc_callback all_procs get_procdesc idenv tenv proc_name proc_desc; + proc_callback + { + get_proc_desc; + get_procs_in_file; + idenv; + tenv; + proc_name; + proc_desc; + }; let elapsed = Unix.gettimeofday () -. init_time in update_time proc_name elapsed end) @@ -160,7 +174,7 @@ let iterate_callbacks store_summary call_graph exe_env = (* Invoke callbacks. *) IList.iter - (iterate_procedure_callbacks originally_defined_procs exe_env) + (iterate_procedure_callbacks exe_env) procs_to_analyze; IList.iter diff --git a/infer/src/backend/callbacks.mli b/infer/src/backend/callbacks.mli index e578bb9b6..5b9020f37 100644 --- a/infer/src/backend/callbacks.mli +++ b/infer/src/backend/callbacks.mli @@ -9,6 +9,14 @@ (** Module to register and invoke callbacks *) +type proc_callback_args = { + get_proc_desc : Procname.t -> Cfg.Procdesc.t option; + get_procs_in_file : Procname.t -> Procname.t list; + idenv : Idenv.t; + tenv : Sil.tenv; + proc_name : Procname.t; + proc_desc : Cfg.Procdesc.t; +} (** Type of a procedure callback: - List of all the procedures the callback will be called on. @@ -16,14 +24,7 @@ - Idenv to look up the definition of ids in a cfg. - Type environment. - Procedure for the callback to act on. *) -type proc_callback_t = - Procname.t list -> - (Procname.t -> Cfg.Procdesc.t option) -> - Idenv.t -> - Sil.tenv -> - Procname.t -> - Cfg.Procdesc.t -> - unit +type proc_callback_t = proc_callback_args -> unit type cluster_callback_t = Procname.t list -> diff --git a/infer/src/backend/inferanalyze.ml b/infer/src/backend/inferanalyze.ml index ddcdfecea..29e72f87c 100644 --- a/infer/src/backend/inferanalyze.ml +++ b/infer/src/backend/inferanalyze.ml @@ -250,7 +250,10 @@ let arg_desc = " execute the code query" ; "-eradicate", - Arg.Unit (fun () -> Config.eradicate := true; Config.intraprocedural := true), + Arg.Unit (fun () -> + Config.eradicate := true; + checkers := true; + Config.intraprocedural := true), None, " activate the eradicate checker for java annotations" ; diff --git a/infer/src/checkers/callbackChecker.ml b/infer/src/checkers/callbackChecker.ml index 78e465154..a957cb15e 100644 --- a/infer/src/checkers/callbackChecker.ml +++ b/infer/src/checkers/callbackChecker.ml @@ -38,8 +38,6 @@ let get_or_create_lifecycle_typs tenv = match !android_lifecycle_typs with lifecycle_typs | typs -> typs -let do_eradicate_check all_procs get_procdesc idenv tenv proc_name proc_desc = - Eradicate.callback_eradicate all_procs get_procdesc idenv tenv proc_name proc_desc let num_methods_checked = ref 0 @@ -49,21 +47,23 @@ let done_checking num_methods = (** ask Eradicate to check each of the procs in [registered_callback_procs] (and their transitive * callees) in a context where each of the fields in [fields_nullifed] is marked as @Nullable *) -let do_eradicate_check all_procs get_procdesc idenv tenv = +let do_eradicate_check ({ Callbacks.get_proc_desc } as callback_args) = (* tell Eradicate to treat each of the fields nullified in on_destroy as nullable *) FldSet.iter (fun fld -> Models.Inference.field_add_nullable_annotation fld) !fields_nullified; Procname.Set.iter (fun proc_name -> - match get_procdesc proc_name with + match get_proc_desc proc_name with | Some proc_desc -> - do_eradicate_check all_procs get_procdesc idenv tenv proc_name proc_desc + Eradicate.callback_eradicate + { callback_args with Callbacks.proc_name; proc_desc } | None -> ()) !registered_callback_procs (** if [procname] belongs to an Android lifecycle type, save the set of callbacks registered in * [procname]. in addition, if [procname] is a special "destroy" /"cleanup" method, save the set of * fields that are nullified *) -let callback_checker_main all_procs get_procdesc idenv tenv proc_name proc_desc = +let callback_checker_main + ({ Callbacks.proc_desc; proc_name; tenv } as callback_args) = let typename = Typename.TN_csu (Csu.Class Csu.Java, Mangled.from_string (Procname.java_get_class proc_name)) in @@ -99,5 +99,5 @@ let callback_checker_main all_procs get_procdesc idenv tenv proc_name proc_desc fields_nullified := FldSet.union (PatternMatch.get_fields_nullified proc_desc) !fields_nullified in if done_checking (IList.length def_methods) then - do_eradicate_check all_procs get_procdesc idenv tenv + do_eradicate_check callback_args | _ -> () diff --git a/infer/src/checkers/checkDeadCode.ml b/infer/src/checkers/checkDeadCode.ml index 968a244cc..7bfea5e30 100644 --- a/infer/src/checkers/checkDeadCode.ml +++ b/infer/src/checkers/checkDeadCode.ml @@ -88,13 +88,7 @@ let check_final_state proc_name proc_desc exit_node final_s = end (** Simple check for dead code. *) -let callback_check_dead_code - (all_procs : Procname.t list) - (get_proc_desc: Procname.t -> Cfg.Procdesc.t option) - (idenv: Idenv.t) - (tenv: Sil.tenv) - (proc_name: Procname.t) - (proc_desc : Cfg.Procdesc.t) : unit = +let callback_check_dead_code { Callbacks.proc_desc; proc_name } = let module DFDead = MakeDF(struct type t = State.t diff --git a/infer/src/checkers/checkers.ml b/infer/src/checkers/checkers.ml index 98abd2f59..e34a332e7 100644 --- a/infer/src/checkers/checkers.ml +++ b/infer/src/checkers/checkers.ml @@ -181,7 +181,7 @@ let report_calls_and_accesses callback node instr = | None -> () (** Report all field accesses and method calls of a procedure. *) -let callback_check_access all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_check_access { Callbacks.proc_desc } = Cfg.Procdesc.iter_instrs (report_calls_and_accesses "PROC") proc_desc (** Report all field accesses and method calls of a class. *) @@ -191,7 +191,7 @@ let callback_check_cluster_access all_procs get_proc_desc proc_definitions = (IList.map get_proc_desc all_procs) (** Looks for writeToParcel methods and checks whether read is in reverse *) -let callback_check_write_to_parcel all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_check_write_to_parcel { Callbacks.proc_desc; proc_name; idenv; get_proc_desc } = let verbose = ref false in let is_write_to_parcel this_expr this_type = @@ -274,7 +274,7 @@ let callback_check_write_to_parcel all_procs get_proc_desc idenv tenv proc_name Cfg.Procdesc.iter_instrs do_instr proc_desc (** Monitor calls to Preconditions.checkNotNull and detect inconsistent uses. *) -let callback_monitor_nullcheck all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_monitor_nullcheck { Callbacks.proc_desc; idenv; proc_name } = let verbose = ref false in let class_formal_names = lazy ( @@ -341,11 +341,11 @@ let callback_monitor_nullcheck all_procs get_proc_desc idenv tenv proc_name proc summary_checks_of_formals () (** Test persistent state. *) -let callback_test_state all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_test_state { Callbacks.proc_name } = ST.pname_add proc_name "somekey" "somevalue" (** Check the uses of VisibleForTesting *) -let callback_checkVisibleForTesting all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_checkVisibleForTesting { Callbacks.proc_desc } = let ma = (Specs.pdesc_resolve_attributes proc_desc).ProcAttributes.method_annotation in if Annotations.ma_contains ma [Annotations.visibleForTesting] then begin @@ -355,7 +355,7 @@ let callback_checkVisibleForTesting all_procs get_proc_desc idenv tenv proc_name end (** Check for readValue and readValueAs json deserialization *) -let callback_find_deserialization all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_find_deserialization { Callbacks.proc_desc; get_proc_desc; idenv; proc_name } = let verbose = true in let ret_const_key = "return_const" in @@ -448,7 +448,7 @@ let callback_find_deserialization all_procs get_proc_desc idenv tenv proc_name p Cfg.Procdesc.iter_instrs do_instr proc_desc (** Check field accesses. *) -let callback_check_field_access all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_check_field_access { Callbacks.proc_desc } = let rec do_exp is_read = function | Sil.Var _ -> () | Sil.UnOp (_, e, _) -> @@ -491,7 +491,7 @@ let callback_check_field_access all_procs get_proc_desc idenv tenv proc_name pro Cfg.Procdesc.iter_instrs do_instr proc_desc (** Print c method calls. *) -let callback_print_c_method_calls all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_print_c_method_calls { Callbacks.proc_desc; proc_name } = let do_instr node = function | Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), (e, t):: args, loc, cf) when Procname.is_c_method pn -> diff --git a/infer/src/checkers/codeQuery.ml b/infer/src/checkers/codeQuery.ml index 01d7839d4..060423516 100644 --- a/infer/src/checkers/codeQuery.ml +++ b/infer/src/checkers/codeQuery.ml @@ -204,7 +204,7 @@ module Match = struct end -let code_query_callback all_procs get_proc_desc idenv tenv proc_name proc_desc = +let code_query_callback { Callbacks.proc_desc; idenv; proc_name } = let do_instr node instr = let env = Match.init_env () in let _found = Match.match_query true env idenv node proc_name (Lazy.force query_ast) proc_name node instr in diff --git a/infer/src/checkers/dataflow.ml b/infer/src/checkers/dataflow.ml index ad6125c95..6571d5216 100644 --- a/infer/src/checkers/dataflow.ml +++ b/infer/src/checkers/dataflow.ml @@ -166,7 +166,7 @@ module MakeDF(St: DFStateType) : DF with type state = St.t = struct end (* MakeDF *) (** Example dataflow callback: compute the the distance from a node to the start node. *) -let callback_test_dataflow all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_test_dataflow { Callbacks.proc_desc } = let verbose = false in let module DFCount = MakeDF(struct type t = int diff --git a/infer/src/checkers/fragmentRetainsViewChecker.ml b/infer/src/checkers/fragmentRetainsViewChecker.ml index 642973142..8d43f0f44 100644 --- a/infer/src/checkers/fragmentRetainsViewChecker.ml +++ b/infer/src/checkers/fragmentRetainsViewChecker.ml @@ -26,10 +26,10 @@ let report_error fld fld_typ pname pdesc = let exn = Exceptions.Checkers (retained_view, Localise.verbatim_desc description) in Reporting.log_error pname ~loc:(Some loc) exn -let callback_fragment_retains_view all_procs get_procdesc idenv tenv pname pdesc = +let callback_fragment_retains_view { Callbacks.proc_desc; proc_name; tenv } = (* TODO: complain if onDestroyView is not defined, yet the Fragment has View fields *) (* TODO: handle fields nullified in callees in the same file *) - let is_on_destroy_view = Procname.java_get_method pname = "onDestroyView" in + let is_on_destroy_view = Procname.java_get_method proc_name = "onDestroyView" in (* this is needlessly complicated because field types are Tvars instead of Tstructs *) let fld_typ_is_view = function | Sil.Tptr (Sil.Tvar tname, _) -> @@ -45,18 +45,18 @@ let callback_fragment_retains_view all_procs get_procdesc idenv tenv pname pdesc Typename.equal fld_classname class_typename && fld_typ_is_view fld_typ in if is_on_destroy_view then begin - let class_typename = Typename.Java.from_string (Procname.java_get_class pname) in + let class_typename = Typename.Java.from_string (Procname.java_get_class proc_name) in match Sil.tenv_lookup tenv class_typename with - | Some (Sil.Tstruct { Sil.csu; struct_name = Some class_name; def_methods; instance_fields } + | Some (Sil.Tstruct { Sil.struct_name = Some _; instance_fields } as typ) when AndroidFramework.is_fragment typ tenv -> let declared_view_fields = IList.filter (is_declared_view_typ class_typename) instance_fields in - let fields_nullified = PatternMatch.get_fields_nullified pdesc in + let fields_nullified = PatternMatch.get_fields_nullified proc_desc in (* report if a field is declared by C, but not nulled out in C.onDestroyView *) IList.iter (fun (fname, typ, _) -> if not (Ident.FieldSet.mem fname fields_nullified) then - report_error fname typ pname pdesc) + report_error fname typ proc_name proc_desc) declared_view_fields | _ -> () end diff --git a/infer/src/checkers/immutableChecker.ml b/infer/src/checkers/immutableChecker.ml index 53dfb74c4..51109a309 100644 --- a/infer/src/checkers/immutableChecker.ml +++ b/infer/src/checkers/immutableChecker.ml @@ -46,5 +46,5 @@ let check_immutable_cast curr_pname curr_pdesc typ_expected typ_found_opt loc : end | None -> () -let callback_check_immutable_cast get_proc_desc idenv proc_name = - Eradicate.callback_check_return_type check_immutable_cast get_proc_desc idenv proc_name +let callback_check_immutable_cast = + Eradicate.callback_check_return_type check_immutable_cast diff --git a/infer/src/checkers/performanceCritical.ml b/infer/src/checkers/performanceCritical.ml index ece2e902d..d3efa2619 100644 --- a/infer/src/checkers/performanceCritical.ml +++ b/infer/src/checkers/performanceCritical.ml @@ -227,7 +227,7 @@ let check_one_procedure tenv pname pdesc = | _ -> () -let callback_performance_checker _ get_proc_desc _ tenv pname pdesc = +let callback_performance_checker { Callbacks.proc_desc; proc_name; get_proc_desc; tenv } = let callbacks = let analyze_ondemand pn = match get_proc_desc pn with @@ -235,10 +235,10 @@ let callback_performance_checker _ get_proc_desc _ tenv pname pdesc = | Some pd -> check_one_procedure tenv pn pd in { Ondemand.analyze_ondemand; get_proc_desc; } in if !Config.ondemand_enabled - || Ondemand.procedure_should_be_analyzed pdesc pname + || Ondemand.procedure_should_be_analyzed proc_desc proc_name then begin Ondemand.set_callbacks callbacks; - check_one_procedure tenv pname pdesc; + check_one_procedure tenv proc_name proc_desc; Ondemand.unset_callbacks () end diff --git a/infer/src/checkers/printfArgs.ml b/infer/src/checkers/printfArgs.ml index 128daf566..fc56cff0b 100644 --- a/infer/src/checkers/printfArgs.ml +++ b/infer/src/checkers/printfArgs.ml @@ -219,12 +219,6 @@ let check_printf_args_ok | None -> ()) | _ -> () -let callback_printf_args - (all_procs : Procname.t list) - (get_proc_desc: Procname.t -> Cfg.Procdesc.t option) - (idenv: Idenv.t) - (tenv: Sil.tenv) - (proc_name: Procname.t) - (proc_desc : Cfg.Procdesc.t) : unit = +let callback_printf_args { Callbacks.proc_desc; proc_name } : unit = Cfg.Procdesc.iter_instrs (fun n i -> check_printf_args_ok n i proc_name proc_desc) proc_desc diff --git a/infer/src/checkers/repeatedCallsChecker.ml b/infer/src/checkers/repeatedCallsChecker.ml index d2784eccb..8130e1067 100644 --- a/infer/src/checkers/repeatedCallsChecker.ml +++ b/infer/src/checkers/repeatedCallsChecker.ml @@ -165,11 +165,11 @@ end (* CheckRepeatedCalls *) module MainRepeatedCalls = Eradicate.Build(RepeatedCallsExtension) -let callback_check_repeated_calls all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_check_repeated_calls callback_args = let checks = { TypeCheck.eradicate = false; check_extension = checkers_repeated_calls; check_ret_type = []; } in - MainRepeatedCalls.callback checks all_procs get_proc_desc idenv tenv proc_name proc_desc + MainRepeatedCalls.callback checks callback_args diff --git a/infer/src/checkers/sqlChecker.ml b/infer/src/checkers/sqlChecker.ml index 7e4be739f..a364dba49 100644 --- a/infer/src/checkers/sqlChecker.ml +++ b/infer/src/checkers/sqlChecker.ml @@ -13,7 +13,7 @@ module L = Logging (** Find SQL statements in string concatenations *) -let callback_sql all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_sql { Callbacks.proc_desc; proc_name } = let verbose = false in (* Case insensitive SQL statement patterns *) diff --git a/infer/src/eradicate/eradicate.ml b/infer/src/eradicate/eradicate.ml index f0c67aa26..e98516389 100644 --- a/infer/src/eradicate/eradicate.ml +++ b/infer/src/eradicate/eradicate.ml @@ -31,10 +31,7 @@ type parameters = TypeState.parameters (** Type for a module that provides a main callback function *) module type CallBackT = sig - val callback : - TypeCheck.checks -> Procname.t list -> TypeCheck.get_proc_desc -> - Idenv.t -> Sil.tenv -> Procname.t -> - Cfg.Procdesc.t -> unit + val callback : TypeCheck.checks -> Callbacks.proc_callback_args -> unit end (* CallBackT *) (** Extension to the type checker. *) @@ -149,8 +146,16 @@ struct !calls_this, None let callback2 - calls_this checks all_procs get_proc_desc idenv tenv curr_pname - curr_pdesc annotated_signature linereader proc_loc : unit = + calls_this checks + { + Callbacks.proc_desc = curr_pdesc; + proc_name = curr_pname; + get_proc_desc; + idenv; + tenv; + get_procs_in_file; + } + annotated_signature linereader proc_loc : unit = let find_duplicate_nodes = State.mk_find_duplicate_nodes curr_pdesc in let find_canonical_duplicate node = @@ -251,7 +256,7 @@ struct | Some pdesc -> res := (pname, pdesc) :: !res | None -> () in - IList.iter do_proc all_procs; + IList.iter do_proc (get_procs_in_file curr_pname); IList.rev !res (** Typestates after the current procedure and all initializer procedures. *) @@ -322,7 +327,7 @@ struct update_summary curr_pname curr_pdesc final_typestate_opt (** Entry point for the eradicate-based checker infrastructure. *) - let callback checks all_procs get_proc_desc idenv tenv proc_name proc_desc = + let callback checks ({ Callbacks.proc_desc; proc_name } as callback_args) = let calls_this = ref false in let filter_special_cases () = @@ -346,8 +351,7 @@ struct annotated_signature; callback2 - calls_this checks all_procs get_proc_desc idenv tenv - proc_name proc_desc annotated_signature linereader loc + calls_this checks callback_args annotated_signature linereader loc end (* MkCallback *) @@ -383,7 +387,7 @@ module Main = Build(EmptyExtension) (** Eradicate checker for Java @Nullable annotations. *) -let callback_eradicate all_procs get_proc_desc idenv tenv proc_name proc_desc = +let callback_eradicate ({ Callbacks.get_proc_desc; idenv; proc_desc; proc_name } as callback_args) = let checks = { TypeCheck.eradicate = true; @@ -396,7 +400,11 @@ let callback_eradicate all_procs get_proc_desc idenv tenv proc_name proc_desc = | None -> () | Some pdesc -> let idenv_pname = Idenv.create_from_idenv idenv pdesc in - Main.callback checks all_procs get_proc_desc idenv_pname tenv pname pdesc in + Main.callback checks + { callback_args with + Callbacks.idenv = idenv_pname; + proc_name = pname; + proc_desc = pdesc; } in { Ondemand.analyze_ondemand; get_proc_desc; } in if not !Config.ondemand_enabled || @@ -404,17 +412,16 @@ let callback_eradicate all_procs get_proc_desc idenv tenv proc_name proc_desc = then begin Ondemand.set_callbacks callbacks; - Main.callback checks all_procs get_proc_desc idenv tenv proc_name proc_desc; + Main.callback checks callback_args; Ondemand.unset_callbacks () end (** Call the given check_return_type at the end of every procedure. *) -let callback_check_return_type check_return_type all_procs - get_proc_desc idenv tenv proc_name proc_desc = +let callback_check_return_type check_return_type callback_args = let checks = { TypeCheck.eradicate = false; check_extension = false; check_ret_type = [check_return_type]; } in - Main.callback checks all_procs get_proc_desc idenv tenv proc_name proc_desc + Main.callback checks callback_args diff --git a/infer/src/eradicate/eradicate.mli b/infer/src/eradicate/eradicate.mli index 3d9738c66..2d4c3607d 100644 --- a/infer/src/eradicate/eradicate.mli +++ b/infer/src/eradicate/eradicate.mli @@ -21,10 +21,7 @@ type parameters = (Sil.exp * Sil.typ) list (** Type for a module that provides a main callback function *) module type CallBackT = sig - val callback : - TypeCheck.checks -> Procname.t list -> TypeCheck.get_proc_desc -> - Idenv.t -> Sil.tenv -> Procname.t -> - Cfg.Procdesc.t -> unit + val callback : TypeCheck.checks -> Callbacks.proc_callback_args -> unit end (* CallBackT *)