diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index 3eb98b3d7..7e18da855 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -89,32 +89,31 @@ let iterate_procedure_callbacks exe_env caller_pname = Specs.add_summary proc_name summary; summary in + let initial_summary = reset_summary caller_pname in match get_procedure_definition exe_env caller_pname with - | None -> () - | Some (idenv, tenv, proc_name, proc_desc, _) -> - ignore - (List.fold - ~init:(reset_summary proc_name) - ~f:(fun summary (language_opt, proc_callback) -> - let language_matches = match language_opt with - | Some language -> Config.equal_language language procedure_language - | None -> true in - if language_matches then - let init_time = Unix.gettimeofday () in - proc_callback - { - get_proc_desc; - get_procs_in_file; - idenv; - tenv; - summary; - proc_desc; - } - |> update_time (Unix.gettimeofday () -. init_time) - else - summary) - !procedure_callbacks); - Specs.store_summary (Specs.get_summary_unsafe "iterate_procedure_callbacks" proc_name) + | None -> initial_summary + | Some (idenv, tenv, _, proc_desc, _) -> + List.fold + ~init:initial_summary + ~f:(fun summary (language_opt, proc_callback) -> + let language_matches = match language_opt with + | Some language -> Config.equal_language language procedure_language + | None -> true in + if language_matches then + let init_time = Unix.gettimeofday () in + proc_callback + { + get_proc_desc; + get_procs_in_file; + idenv; + tenv; + summary; + proc_desc; + } + |> update_time (Unix.gettimeofday () -. init_time) + else + summary) + !procedure_callbacks (** Invoke all registered cluster callbacks on a cluster of procedures. *) @@ -154,10 +153,26 @@ let iterate_callbacks call_graph exe_env = (* Make sure summaries exists. *) List.iter ~f:(fun p -> ignore (reset_summary p)) procs_to_analyze; - (* Invoke procedure callbacks. *) - List.iter - ~f:(iterate_procedure_callbacks exe_env) - procs_to_analyze; + let analyze_ondemand _ proc_desc = + let proc_name = Procdesc.get_proc_name proc_desc in + iterate_procedure_callbacks exe_env proc_name in + + let callbacks = { + Ondemand.analyze_ondemand; + get_proc_desc = Exe_env.get_proc_desc exe_env + } in + + (* Create and register on-demand analysis callback *) + let analyze_proc_name pname = + match Ondemand.get_proc_desc pname with + | None -> + failwithf "Could not find proc desc for %a" Typ.Procname.pp pname + | Some pdesc -> + ignore (Ondemand.analyze_proc_desc ~propagate_exceptions:true pdesc pdesc) in + Ondemand.set_callbacks callbacks; + + (* Invoke procedure callbacks using on-demand anlaysis schedulling *) + List.iter ~f:analyze_proc_name procs_to_analyze; let originally_defined_procs = Cg.get_defined_nodes call_graph in @@ -185,6 +200,9 @@ let iterate_callbacks call_graph exe_env = ~f:(iterate_cluster_callbacks originally_defined_procs exe_env) (cluster procs_to_analyze); + (* Unregister callbacks *) + Ondemand.unset_callbacks (); + (* Store all the summaries to disk *) List.iter ~f:(fun pname -> diff --git a/infer/src/checkers/AbstractInterpreter.ml b/infer/src/checkers/AbstractInterpreter.ml index f79915728..c76fc8cd2 100644 --- a/infer/src/checkers/AbstractInterpreter.ml +++ b/infer/src/checkers/AbstractInterpreter.ml @@ -159,35 +159,14 @@ end module Interprocedural (Summ : Summary.S) = struct let compute_and_store_post - ~compute_post ~make_extras { Callbacks.get_proc_desc; proc_desc; tenv; } = - let proc_name = Procdesc.get_proc_name proc_desc in - let analyze_ondemand_ _ pdesc = - match compute_post (ProcData.make pdesc tenv (make_extras pdesc)) with - | Some post -> - Summ.write_summary (Procdesc.get_proc_name pdesc) post; - Some post - | None -> - None in - let analyze_ondemand source pdesc = - ignore (analyze_ondemand_ source pdesc); - Specs.get_summary_unsafe - "Inferprocedural.compute_and_store_post" - (Procdesc.get_proc_name pdesc) in - let callbacks = - { - Ondemand.analyze_ondemand; - get_proc_desc; - } in - if Ondemand.procedure_should_be_analyzed proc_name - then - begin - Ondemand.set_callbacks callbacks; - let post_opt = analyze_ondemand_ SourceFile.empty proc_desc in - Ondemand.unset_callbacks (); - post_opt - end - else - Summ.read_summary proc_desc proc_name + ~compute_post ~make_extras { Callbacks.proc_desc; tenv; } = + match compute_post (ProcData.make proc_desc tenv (make_extras proc_desc)) with + | Some post -> + Summ.write_summary (Procdesc.get_proc_name proc_desc) post; + Some post + | None -> + None + end module MakeWithScheduler (C : ProcCfg.S) (S : Scheduler.Make) (T : TransferFunctions.Make) = diff --git a/infer/src/checkers/annotationReachability.ml b/infer/src/checkers/annotationReachability.ml index 22baa18fa..d1420f74e 100644 --- a/infer/src/checkers/annotationReachability.ml +++ b/infer/src/checkers/annotationReachability.ml @@ -153,8 +153,8 @@ let method_has_annot annot tenv pname = let method_overrides_annot annot tenv pname = method_overrides (method_has_annot annot) tenv pname -let lookup_annotation_calls annot pname : CallSite.t list = - match Specs.get_summary pname with +let lookup_annotation_calls caller_pdesc annot pname : CallSite.t list = + match Ondemand.analyze_proc_name ~propagate_exceptions:false caller_pdesc pname with | Some { Specs.payload = { Specs.calls = Some call_map; }; } -> begin try @@ -381,7 +381,7 @@ module Interprocedural = struct report_annotation_stack src_annot.class_name snk_annot.class_name in report_call_stack (method_has_annot snk_annot tenv) - (lookup_annotation_calls snk_annot) + (lookup_annotation_calls proc_desc snk_annot) f_report (CallSite.make proc_name loc) calls in diff --git a/infer/src/checkers/summary.ml b/infer/src/checkers/summary.ml index e3a053d35..bb1b7c8e2 100644 --- a/infer/src/checkers/summary.ml +++ b/infer/src/checkers/summary.ml @@ -39,7 +39,7 @@ module Make (H : Helper) = struct match Specs.get_summary pname with | Some global_summary -> let payload = H.update_payload summary global_summary.Specs.payload in - Specs.store_summary { global_summary with payload; } + Specs.add_summary pname { global_summary with payload; } | None -> failwithf "Summary for %a should exist, but does not!@." Typ.Procname.pp pname diff --git a/infer/src/eradicate/eradicate.ml b/infer/src/eradicate/eradicate.ml index c678c6a1a..5095b5ed1 100644 --- a/infer/src/eradicate/eradicate.ml +++ b/infer/src/eradicate/eradicate.ml @@ -405,39 +405,14 @@ module Main = Build(EmptyExtension) (** Eradicate checker for Java @Nullable annotations. *) -let callback_eradicate - ({ Callbacks.get_proc_desc; summary } as callback_args) = +let callback_eradicate = let checks = { TypeCheck.eradicate = true; check_extension = false; check_ret_type = []; } in - let callbacks = - let analyze_ondemand _ pdesc = - let idenv_pname = Idenv.create pdesc in - let proc_name = Procdesc.get_proc_name pdesc in - let summary = Specs.get_summary_unsafe "Eradicate.analyze_ondemand" proc_name in - Main.callback checks - { callback_args with - Callbacks.idenv = idenv_pname; - summary; - proc_desc = pdesc; } in - { - Ondemand.analyze_ondemand; - get_proc_desc; - } in - - if Ondemand.procedure_should_be_analyzed (Specs.get_proc_name summary) - then - begin - Ondemand.set_callbacks callbacks; - let final_summary = Main.callback checks callback_args in - Ondemand.unset_callbacks (); - final_summary - end - else - summary + Main.callback checks (** Call the given check_return_type at the end of every procedure. *) let callback_check_return_type check_return_type callback_args = diff --git a/infer/tests/codetoanalyze/java/checkers/issues.exp b/infer/tests/codetoanalyze/java/checkers/issues.exp index 1b1e3f809..d6121a19f 100644 --- a/infer/tests/codetoanalyze/java/checkers/issues.exp +++ b/infer/tests/codetoanalyze/java/checkers/issues.exp @@ -23,7 +23,7 @@ codetoanalyze/java/checkers/ExpensiveInheritanceExample.java, void ExpensiveInhe codetoanalyze/java/checkers/ExpensiveInheritanceExample.java, void ExpensiveInheritanceExample.reportsAssumingObjectOfTypeA(), 2, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveInheritanceExample.java, void ExpensiveInheritanceExample.reportsBecauseFooIsExpensiveInA(A), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveInterfaceExample.java, void ExpensiveInterfaceExample$ImplementsInterface.m1(), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] -codetoanalyze/java/checkers/ExpensiveSubtypingExample.java, void ExpensiveSubtypingExample.m3(), 0, CHECKERS_EXPENSIVE_OVERRIDES_UNANNOTATED, [return from a call to void ExpensiveSubtypingExample.m4()] +codetoanalyze/java/checkers/ExpensiveSubtypingExample.java, void ExpensiveSubtypingExample.m3(), 0, CHECKERS_EXPENSIVE_OVERRIDES_UNANNOTATED, [] codetoanalyze/java/checkers/FragmentRetainsViewExample.java, void FragmentRetainsViewExample.onDestroyView(), 0, CHECKERS_FRAGMENT_RETAINS_VIEW, [return from a call to void FragmentRetainsViewExample.onDestroyView()] codetoanalyze/java/checkers/FragmentRetainsViewExample.java, void FragmentRetainsViewExample.onDestroyView(), 0, CHECKERS_FRAGMENT_RETAINS_VIEW, [return from a call to void FragmentRetainsViewExample.onDestroyView()] codetoanalyze/java/checkers/FragmentRetainsViewExample.java, void FragmentRetainsViewExample.onDestroyView(), 0, CHECKERS_FRAGMENT_RETAINS_VIEW, [return from a call to void FragmentRetainsViewExample.onDestroyView()] diff --git a/infer/tests/codetoanalyze/java/quandary/Recursion.java b/infer/tests/codetoanalyze/java/quandary/Recursion.java index 1ac9b5612..6c92c72b6 100644 --- a/infer/tests/codetoanalyze/java/quandary/Recursion.java +++ b/infer/tests/codetoanalyze/java/quandary/Recursion.java @@ -36,10 +36,11 @@ public class Recursion { safeRecursionCallSink(5, InferTaint.inferSecretSource()); } - public static void recursionBad(int i, Object param) { + // TODO (#16595757): Requires support for recursion in Ondemand + public static void FN_recursionBad(int i, Object param) { if (i == 0) return; InferTaint.inferSensitiveSink(param); - recursionBad(i - 1, InferTaint.inferSecretSource()); + FN_recursionBad(i - 1, InferTaint.inferSecretSource()); } } diff --git a/infer/tests/codetoanalyze/java/quandary/issues.exp b/infer/tests/codetoanalyze/java/quandary/issues.exp index 4d657e376..b97d9b89d 100644 --- a/infer/tests/codetoanalyze/java/quandary/issues.exp +++ b/infer/tests/codetoanalyze/java/quandary/issues.exp @@ -154,7 +154,6 @@ codetoanalyze/java/quandary/LoggingPrivateData.java, void LoggingPrivateData.log codetoanalyze/java/quandary/LoggingPrivateData.java, void LoggingPrivateData.logAllSourcesBad(Location,TelephonyManager), 39, QUANDARY_TAINT_ERROR, [return from float Location.getSpeed(),call to int Log.wtf(String,String)] codetoanalyze/java/quandary/LoggingPrivateData.java, void LoggingPrivateData.logAllSourcesBad(Location,TelephonyManager), 39, QUANDARY_TAINT_ERROR, [return from double Location.getLongitude(),call to int Log.wtf(String,String)] codetoanalyze/java/quandary/Recursion.java, void Recursion.callSinkThenDivergeBad(), 1, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void Recursion.callSinkThenDiverge(Object),call to void InferTaint.inferSensitiveSink(Object)] -codetoanalyze/java/quandary/Recursion.java, void Recursion.recursionBad(int,Object), 3, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void Recursion.recursionBad(int,Object)] codetoanalyze/java/quandary/Recursion.java, void Recursion.safeRecursionCallSinkBad(), 1, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void Recursion.safeRecursionCallSink(int,Object),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Strings.java, void Strings.viaFormatterBad(), 3, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Strings.java, void Strings.viaFormatterIgnoreReturnBad(), 4, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] diff --git a/infer/tests/codetoanalyze/java/threadsafety/issues.exp b/infer/tests/codetoanalyze/java/threadsafety/issues.exp index 31f7a333c..7bd98a4dc 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/issues.exp +++ b/infer/tests/codetoanalyze/java/threadsafety/issues.exp @@ -69,6 +69,6 @@ codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.c codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.callVisibleForTestingBad(), 1, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.visibleForTestingNotPublicOk(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.deeperTraceBad(), 1, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.callAssignInPrivateMethod(),call to void ThreadSafeExample.assignInPrivateMethodOk(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.oddBad(), 1, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.evenOk(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] -codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.recursiveBad(), 2, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.recursiveBad(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] +codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.recursiveBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.tsBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void YesThreadSafeExtendsNotThreadSafeExample.subsubmethodBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.YesThreadSafeExtendsNotThreadSafeExample.subsubfield]