From 74497ea7df6514758add7834b959e89c5ac16e98 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Wed, 6 May 2020 11:23:42 -0700 Subject: [PATCH] make ClassLoads an `interprocedural` Summary: Making checkers/ its own dune library. Reviewed By: ngorogiannis Differential Revision: D21407066 fbshipit-source-id: 80744bcd4 --- infer/src/backend/registerCheckers.ml | 4 +- infer/src/checkers/classLoads.ml | 78 +++++++++++++-------------- infer/src/checkers/classLoads.mli | 3 +- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/infer/src/backend/registerCheckers.ml b/infer/src/backend/registerCheckers.ml index 2e081b665..784c794a8 100644 --- a/infer/src/backend/registerCheckers.ml +++ b/infer/src/backend/registerCheckers.ml @@ -79,7 +79,9 @@ let all_checkers = ; callbacks= [(intraprocedural SelfInBlock.checker, Language.Clang)] } ; { name= "Class loading analysis" ; active= Config.is_checker_enabled ClassLoads - ; callbacks= [(Procedure ClassLoads.analyze_procedure, Language.Java)] } + ; callbacks= + [(interprocedural Payloads.Fields.class_loads ClassLoads.analyze_procedure, Language.Java)] + } ; { name= "purity" ; active= Config.(is_checker_enabled Purity || is_checker_enabled LoopHoisting) ; callbacks= diff --git a/infer/src/checkers/classLoads.ml b/infer/src/checkers/classLoads.ml index 57aea79f9..f393e6ad9 100644 --- a/infer/src/checkers/classLoads.ml +++ b/infer/src/checkers/classLoads.ml @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. *) + open! IStd module L = Logging @@ -16,19 +17,14 @@ module L = Logging - catch / throw with exception classes *) -module Payload = SummaryPayload.Make (struct - type t = ClassLoadsDomain.summary - - let field = Payloads.Fields.class_loads -end) - -let do_call summary callee loc init = - Payload.read ~caller_summary:summary ~callee_pname:callee - |> Option.fold ~init ~f:(ClassLoadsDomain.integrate_summary callee loc) +let do_call {InterproceduralAnalysis.analyze_dependency} callee loc init = + analyze_dependency callee + |> Option.fold ~init ~f:(fun acc (_, summary) -> + ClassLoadsDomain.integrate_summary callee loc acc summary ) (** fully load a class given the typename *) -let rec load_class summary tenv loc astate class_name = +let rec load_class ({InterproceduralAnalysis.tenv} as analysis_data) loc astate class_name = (* don't bother if class is already loaded *) if ClassLoadsDomain.mem_typename class_name astate then astate else @@ -38,86 +34,87 @@ let rec load_class summary tenv loc astate class_name = let astate2 = let class_initializer = 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 summary class_initializer loc astate1 + do_call analysis_data class_initializer loc astate1 in (* finally, recursively load all superclasses *) Tenv.lookup tenv class_name |> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Struct.supers) - |> List.fold ~init:astate2 ~f:(load_class summary tenv loc) + |> List.fold ~init:astate2 ~f:(load_class analysis_data loc) -let load_type summary tenv loc (typ : Typ.t) astate = +let load_type analysis_data loc (typ : Typ.t) astate = match typ with | {desc= Tstruct name} | {desc= Tptr ({desc= Tstruct name}, _)} -> - load_class summary tenv loc astate name + load_class analysis_data loc astate name | _ -> astate -let rec load_array summary tenv loc (typ : Typ.t) astate = +let rec load_array analysis_data loc (typ : Typ.t) astate = match typ with | {desc= Tarray {elt}} -> - load_array summary tenv loc elt astate + load_array analysis_data loc elt astate | _ -> - load_type summary tenv loc typ astate + load_type analysis_data loc typ astate -let rec add_loads_of_exp summary tenv loc (exp : Exp.t) astate = +let rec add_loads_of_exp analysis_data loc (exp : Exp.t) astate = match exp with | Const (Cclass class_ident) -> (* [X.class] expressions *) let class_str = Ident.name_to_string class_ident |> JavaClassName.from_string in let class_name = Typ.JavaClass class_str in - load_class summary tenv loc astate class_name + load_class analysis_data loc astate class_name | Sizeof {typ= {desc= Tarray {elt}}} -> (* anewarray / multinewarray *) - load_array summary tenv loc elt astate + load_array analysis_data loc elt astate | Cast (_, e) | UnOp (_, e, _) | Exn e -> (* NB Cast is only used for primitive types *) - add_loads_of_exp summary tenv loc e astate + add_loads_of_exp analysis_data loc e astate | BinOp (_, e1, e2) -> - add_loads_of_exp summary tenv loc e1 astate |> add_loads_of_exp summary tenv loc e2 + add_loads_of_exp analysis_data loc e1 astate |> add_loads_of_exp analysis_data loc e2 | Lfield (e, _, typ') -> (* getfield / getstatic / putfield / putstatic *) - load_type summary tenv loc typ' astate |> add_loads_of_exp summary tenv loc e + load_type analysis_data loc typ' astate |> add_loads_of_exp analysis_data loc e | Var _ | Const _ | Closure _ | Sizeof _ | Lindex _ | Lvar _ -> astate -let exec_call summary tenv callee args loc astate = +let exec_call analysis_data callee args loc astate = match args with | [_; (Exp.Sizeof {typ}, _)] when Procname.equal callee BuiltinDecl.__instanceof -> (* this matches downcasts/instanceof and exception handlers *) - load_type summary tenv loc typ astate + load_type analysis_data loc typ astate | _ -> (* invokeinterface / invokespecial / invokestatic / invokevirtual / new *) - List.fold args ~init:astate ~f:(fun acc (exp, _) -> add_loads_of_exp summary tenv loc exp acc) - |> do_call summary callee loc + List.fold args ~init:astate ~f:(fun acc (exp, _) -> add_loads_of_exp analysis_data loc exp acc) + |> do_call analysis_data callee loc -let exec_instr summary tenv astate _ (instr : Sil.instr) = +let exec_instr analysis_data astate _ (instr : Sil.instr) = match instr with | Call (_, Const (Cfun callee), args, loc, _) -> - exec_call summary tenv callee args loc astate + exec_call analysis_data callee args loc astate | Load {e= 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 summary tenv loc exp astate + add_loads_of_exp analysis_data loc exp astate | Store {e1; e2; loc} -> - add_loads_of_exp summary tenv loc e1 astate |> add_loads_of_exp summary tenv loc e2 + add_loads_of_exp analysis_data loc e1 astate |> add_loads_of_exp analysis_data loc e2 | _ -> astate -let report_loads summary astate = +let report_loads {InterproceduralAnalysis.proc_desc; err_log} astate = let report_load ({ClassLoadsDomain.Event.loc; elem} as event) = if String.is_prefix ~prefix:"java." elem then () else let ltr = ClassLoadsDomain.Event.make_loc_trace event in let msg = Format.asprintf "Class %s loaded" elem in - SummaryReporting.log_warning summary ~loc ~ltr IssueType.class_load msg + let attrs = Procdesc.get_attributes proc_desc in + Reporting.log_warning attrs err_log ~loc ~ltr IssueType.class_load msg in - let pname = Summary.get_proc_name summary in + let pname = Procdesc.get_proc_name proc_desc in Procname.get_class_name pname |> Option.iter ~f:(fun clazz -> let method_strname = Procname.get_method pname in @@ -126,19 +123,16 @@ let report_loads summary astate = ClassLoadsDomain.iter report_load astate ) -let analyze_procedure {Callbacks.exe_env; summary} = - let proc_desc = Summary.get_proc_desc summary in +let analyze_procedure ({InterproceduralAnalysis.proc_desc} as analysis_data) = let proc_name = Procdesc.get_proc_name proc_desc in - let tenv = Exe_env.get_tenv exe_env proc_name in L.debug Analysis Verbose "CL: ANALYZING %a@." Procname.pp proc_name ; let loc = Procdesc.get_loc proc_desc in (* load the method's class *) let init = Procname.get_class_type_name proc_name - |> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class summary tenv loc) + |> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class analysis_data loc) in - 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 + let post = Procdesc.fold_instrs proc_desc ~init ~f:(exec_instr analysis_data) in + report_loads analysis_data post ; L.debug Analysis Verbose "CL: FINISHED ANALYZING %a@." Procname.pp proc_name ; - result + Some post diff --git a/infer/src/checkers/classLoads.mli b/infer/src/checkers/classLoads.mli index 1c41ed020..009287594 100644 --- a/infer/src/checkers/classLoads.mli +++ b/infer/src/checkers/classLoads.mli @@ -7,4 +7,5 @@ open! IStd -val analyze_procedure : Callbacks.proc_callback_t +val analyze_procedure : + ClassLoadsDomain.summary InterproceduralAnalysis.t -> ClassLoadsDomain.summary option