From 1a221e798cb36e9f31b3eaf37cfa8930dfc39a4f Mon Sep 17 00:00:00 2001 From: Jeremy Dubreil Date: Wed, 30 Aug 2017 12:11:51 -0700 Subject: [PATCH] [infer][java] make the translation and analysis of abstract methods and native methods consistent Summary: With this, we can now get now get inter-procedural issues involving native methods. Reviewed By: sblackshear Differential Revision: D5730638 fbshipit-source-id: 3bdbdbd --- infer/src/backend/ondemand.ml | 25 ++++++---- infer/src/java/jTrans.ml | 47 ++++++++++--------- infer/tests/build_systems/buck/issues.exp | 1 + .../build_systems/genrule/module2/Class2.java | 2 +- .../java/quandary/UnknownCode.java | 2 +- .../codetoanalyze/java/quandary/issues.exp | 1 + 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/infer/src/backend/ondemand.ml b/infer/src/backend/ondemand.ml index 1d48e0f57..af204fa31 100644 --- a/infer/src/backend/ondemand.ml +++ b/infer/src/backend/ondemand.ml @@ -39,6 +39,13 @@ let is_active, add_active, remove_active = in (is_active, add_active, remove_active) +let should_create_summary proc_name proc_attributes = + match proc_name with + | Typ.Procname.Java _ + -> true + | _ + -> proc_attributes.ProcAttributes.is_defined + let should_be_analyzed proc_name proc_attributes = let already_analyzed () = match Specs.get_summary proc_name with @@ -47,12 +54,9 @@ let should_be_analyzed proc_name proc_attributes = | None -> false in - proc_attributes.ProcAttributes.is_defined - (* we have the implementation *) - && not (is_active proc_name) && (* avoid infinite loops *) - not (already_analyzed ()) - -(* avoid re-analysis of the same procedure *) + should_create_summary proc_name proc_attributes && not (is_active proc_name) + && (* avoid infinite loops *) + not (already_analyzed ()) let procedure_should_be_analyzed proc_name = match Specs.proc_resolve_attributes proc_name with @@ -135,8 +139,13 @@ let run_proc_analysis analyze_proc curr_pdesc callee_pdesc = let old_state = save_global_state () in let initial_summary = preprocess () in try - let summary = analyze_proc initial_summary callee_pdesc |> postprocess in - restore_global_state old_state ; summary + let attributes = Procdesc.get_attributes callee_pdesc in + let summary = + if attributes.ProcAttributes.is_defined then analyze_proc initial_summary callee_pdesc + else initial_summary + in + let final_summary = postprocess summary in + restore_global_state old_state ; final_summary with exn -> L.internal_error "@\nONDEMAND EXCEPTION %a %s@.@.BACK TRACE@.%s@?" Typ.Procname.pp callee_pname (Exn.to_string exn) (Printexc.get_backtrace ()) ; diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 0f415bfdd..618972f5d 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -275,6 +275,16 @@ let trans_access = function | `Protected -> PredSymb.Protected +let create_empty_cfg proc_name source_file procdesc = + let start_kind = Procdesc.Node.Start_node proc_name in + let start_node = Procdesc.create_node procdesc (Location.none source_file) start_kind [] in + let exit_kind = Procdesc.Node.Exit_node proc_name in + let exit_node = Procdesc.create_node procdesc (Location.none source_file) exit_kind [] in + Procdesc.node_set_succs_exn procdesc start_node [exit_node] [exit_node] ; + Procdesc.set_start_node procdesc start_node ; + Procdesc.set_exit_node procdesc exit_node ; + procdesc + let create_am_procdesc source_file program icfg am proc_name : Procdesc.t = let cfg = icfg.JContext.cfg in let tenv = icfg.JContext.tenv in @@ -290,7 +300,6 @@ let create_am_procdesc source_file program icfg am proc_name : Procdesc.t = ; formals ; is_abstract= true ; is_bridge_method= am.Javalib.am_bridge - ; is_defined= true ; is_model= Config.models_mode ; is_synthetic_method= am.Javalib.am_synthetic ; method_annotation @@ -299,14 +308,7 @@ let create_am_procdesc source_file program icfg am proc_name : Procdesc.t = in Cfg.create_proc_desc cfg proc_attributes in - let start_kind = Procdesc.Node.Start_node proc_name in - let start_node = Procdesc.create_node procdesc (Location.none source_file) start_kind [] in - let exit_kind = Procdesc.Node.Exit_node proc_name in - let exit_node = Procdesc.create_node procdesc (Location.none source_file) exit_kind [] in - Procdesc.node_set_succs_exn procdesc start_node [exit_node] [exit_node] ; - Procdesc.set_start_node procdesc start_node ; - Procdesc.set_exit_node procdesc exit_node ; - procdesc + create_empty_cfg proc_name source_file procdesc let create_native_procdesc source_file program icfg cm proc_name = let cfg = icfg.JContext.cfg in @@ -315,19 +317,22 @@ let create_native_procdesc source_file program icfg cm proc_name = let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in let formals = formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in let method_annotation = JAnnotation.translate_method cm.Javalib.cm_annotations in - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access= trans_access cm.Javalib.cm_access - ; exceptions= List.map ~f:JBasics.cn_name cm.Javalib.cm_exceptions - ; formals - ; is_bridge_method= cm.Javalib.cm_bridge - ; is_model= Config.models_mode - ; is_synthetic_method= cm.Javalib.cm_synthetic - ; method_annotation - ; ret_type= JTransType.return_type program tenv ms - ; loc= Location.none source_file } + let procdesc = + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access= trans_access cm.Javalib.cm_access + ; exceptions= List.map ~f:JBasics.cn_name cm.Javalib.cm_exceptions + ; formals + ; is_bridge_method= cm.Javalib.cm_bridge + ; is_model= Config.models_mode + ; is_synthetic_method= cm.Javalib.cm_synthetic + ; method_annotation + ; ret_type= JTransType.return_type program tenv ms + ; loc= Location.none source_file } + in + Cfg.create_proc_desc cfg proc_attributes in - Cfg.create_proc_desc cfg proc_attributes + create_empty_cfg proc_name source_file procdesc (** Creates a procedure description. *) let create_cm_procdesc source_file program linereader icfg cm proc_name = diff --git a/infer/tests/build_systems/buck/issues.exp b/infer/tests/build_systems/buck/issues.exp index 5528f3f79..f257c1d0d 100644 --- a/infer/tests/build_systems/buck/issues.exp +++ b/infer/tests/build_systems/buck/issues.exp @@ -1,4 +1,5 @@ infer/tests/build_systems/genrule/module1/Class1.java, void Class1.localNPE1(), 2, NULL_DEREFERENCE, [start of procedure localNPE1()] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetAbstractNPE(Class1), 2, NULL_DEREFERENCE, [start of procedure interTargetAbstractNPE(...),Skipping abstractMayReturnNull(): function or method not found] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetNPE(), 2, NULL_DEREFERENCE, [start of procedure interTargetNPE(),start of procedure returnsNull(),return from a call to String Class1.returnsNull()] +infer/tests/build_systems/genrule/module2/Class2.java, void Class2.interTargetNativeNPE(Class1), 2, NULL_DEREFERENCE, [start of procedure interTargetNativeNPE(...),Skipping nativeMayReturnNull(): function or method not found] infer/tests/build_systems/genrule/module2/Class2.java, void Class2.localNPE2(), 2, NULL_DEREFERENCE, [start of procedure localNPE2()] diff --git a/infer/tests/build_systems/genrule/module2/Class2.java b/infer/tests/build_systems/genrule/module2/Class2.java index 95116431f..a15c64311 100644 --- a/infer/tests/build_systems/genrule/module2/Class2.java +++ b/infer/tests/build_systems/genrule/module2/Class2.java @@ -28,7 +28,7 @@ public class Class2 { obj.toString(); } - void FN_interTargetNativeNPE(Class1 class1) { + void interTargetNativeNPE(Class1 class1) { Object obj = class1.nativeMayReturnNull(); obj.toString(); } diff --git a/infer/tests/codetoanalyze/java/quandary/UnknownCode.java b/infer/tests/codetoanalyze/java/quandary/UnknownCode.java index e48f9e8f6..8fbfcc2ab 100644 --- a/infer/tests/codetoanalyze/java/quandary/UnknownCode.java +++ b/infer/tests/codetoanalyze/java/quandary/UnknownCode.java @@ -73,7 +73,7 @@ public abstract class UnknownCode { propagateFootprint((String) InferTaint.inferSecretSource()); } - static void FN_propagateViaInterfaceCodeBad(Interface i) { + static void propagateViaInterfaceCodeBad(Interface i) { Object source = InferTaint.inferSecretSource(); Object launderedSource = i.interfaceMethod(source); InferTaint.inferSensitiveSink(launderedSource); diff --git a/infer/tests/codetoanalyze/java/quandary/issues.exp b/infer/tests/codetoanalyze/java/quandary/issues.exp index 602acb8f4..2fba42304 100644 --- a/infer/tests/codetoanalyze/java/quandary/issues.exp +++ b/infer/tests/codetoanalyze/java/quandary/issues.exp @@ -220,6 +220,7 @@ codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.callPropagateFoot codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.callUnknownSetterBad(Intent), 4, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateEmptyBad(), 6, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateEmptyBad(), 7, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)] +codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateViaInterfaceCodeBad(UnknownCode$Interface), 3, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateViaUnknownAbstractCodeBad(), 3, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateViaUnknownConstructorBad(), 4, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateViaUnknownNativeCodeBad(), 3, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object)]