From fdb1640e123b6ba313b115276ca8d0ab723d2f53 Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Fri, 28 Aug 2020 02:41:41 -0700 Subject: [PATCH] [closures preanalysis] [3/n] Adding models to dispatch functions and remove code for previous specialization and dispatch models Summary: This diff finishes the migration from the specialization of methods that take blocks as arguments. Here we delete all the old code and change the way we model dispatch functions so that the tests pass. - Remove the code for specializing the methods in biabduction. - Remove the call flags `cf_with_block_parameters` that was only used in this algorithm. - Removes models for dispatch functions. - Adds models for dispatch functions as program transformation only in biabduction. To be added in other checkers in the future. Reviewed By: ngorogiannis Differential Revision: D23345342 fbshipit-source-id: b5e8542ce --- infer/models/objc/src/Dispatch.m | 32 ---- infer/models/objc/src/Dispatch_once.m | 20 -- infer/src/IR/CallFlags.ml | 14 +- infer/src/IR/CallFlags.mli | 3 +- infer/src/IR/Ident.ml | 7 - infer/src/IR/Ident.mli | 4 - infer/src/IR/Instrs.ml | 2 - infer/src/IR/Instrs.mli | 2 - infer/src/IR/Procname.ml | 4 - infer/src/IR/Procname.mli | 3 - infer/src/IR/Sil.ml | 15 -- infer/src/IR/Sil.mli | 4 - infer/src/IR/SpecializeProcdesc.ml | 174 ------------------ infer/src/IR/SpecializeProcdesc.mli | 8 - infer/src/biabduction/ObjCDispatchModels.ml | 18 ++ infer/src/biabduction/ObjCDispatchModels.mli | 10 + infer/src/biabduction/SymExec.ml | 131 +++++++------ infer/src/biabduction/SymExecBlocks.ml | 101 ---------- infer/src/biabduction/SymExecBlocks.mli | 20 -- .../src/clang/CCallSpecializedWithClosures.ml | 10 +- infer/src/clang/cTrans.ml | 3 +- .../objc_getters_setters/issues.exp | 4 +- .../codetoanalyze/objc/biabduction/issues.exp | 22 +-- .../objc/frontend/block/retain_cycle.m.dot | 2 +- ...specialized_method_with_block_params.m.dot | 4 +- .../codetoanalyze/objc/performance/NSArray.m | 4 + .../codetoanalyze/objc/performance/block.m | 2 +- .../objc/performance/cost-issues.exp | 7 +- .../tests/codetoanalyze/objc/pulse/issues.exp | 2 +- .../shared/block/Blocks_as_parameters.m.dot | 2 +- .../objc/shared/block/block-it.m.dot | 2 +- .../objc/shared/block/dispatch.m.dot | 4 +- .../objc/shared/block/dispatch_examples.m.dot | 12 +- .../objc/shared/block/dispatch_in_macro.m.dot | 2 +- .../objcpp/biabduction/issues.exp | 5 +- 35 files changed, 144 insertions(+), 515 deletions(-) delete mode 100644 infer/models/objc/src/Dispatch.m delete mode 100644 infer/models/objc/src/Dispatch_once.m create mode 100644 infer/src/biabduction/ObjCDispatchModels.ml create mode 100644 infer/src/biabduction/ObjCDispatchModels.mli delete mode 100644 infer/src/biabduction/SymExecBlocks.ml delete mode 100644 infer/src/biabduction/SymExecBlocks.mli diff --git a/infer/models/objc/src/Dispatch.m b/infer/models/objc/src/Dispatch.m deleted file mode 100644 index 3fa930033..000000000 --- a/infer/models/objc/src/Dispatch.m +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -#import - -void dispatch_async(dispatch_queue_t queue, dispatch_block_t block) { block(); } - -void dispatch_after(dispatch_time_t when, - dispatch_queue_t queue, - dispatch_block_t block) { - block(); -} - -void dispatch_group_async(dispatch_group_t group, - - dispatch_queue_t queue, - dispatch_block_t block) { - block(); -} - -void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block) { - block(); -} - -void dispatch_group_notify(dispatch_group_t group, - dispatch_queue_t queue, - dispatch_block_t block) { - block(); -} diff --git a/infer/models/objc/src/Dispatch_once.m b/infer/models/objc/src/Dispatch_once.m deleted file mode 100644 index 86a67c4d0..000000000 --- a/infer/models/objc/src/Dispatch_once.m +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* We model dispatch_once in a separate file rather than Dispatch.m because this -code doesn't compile together with Foundation. */ - -#import - -typedef void (^dispatch_block_t)(void); - -typedef long dispatch_once_t; - -static void _dispatch_once(dispatch_once_t* predicate, - __nonnull dispatch_block_t block) { - block(); -} diff --git a/infer/src/IR/CallFlags.ml b/infer/src/IR/CallFlags.ml index dc27fe2da..8a475c1dc 100644 --- a/infer/src/IR/CallFlags.ml +++ b/infer/src/IR/CallFlags.ml @@ -17,22 +17,17 @@ type t = ; cf_injected_destructor: bool ; cf_interface: bool ; cf_is_objc_block: bool - ; cf_virtual: bool - ; cf_with_block_parameters: bool } + ; cf_virtual: bool } [@@deriving compare] let pp f - ({ cf_assign_last_arg - ; cf_injected_destructor - ; cf_interface - ; cf_is_objc_block - ; cf_with_block_parameters - ; cf_virtual }[@warning "+9"]) = + ({cf_assign_last_arg; cf_injected_destructor; cf_interface; cf_is_objc_block; cf_virtual}[@warning + "+9"]) + = if cf_assign_last_arg then F.pp_print_string f " assign_last" ; if cf_injected_destructor then F.pp_print_string f " injected" ; if cf_interface then F.pp_print_string f " interface" ; if cf_is_objc_block then F.pp_print_string f " objc_block" ; - if cf_with_block_parameters then F.pp_print_string f " block_params" ; if cf_virtual then F.pp_print_string f " virtual" ; () @@ -42,5 +37,4 @@ let default = ; cf_injected_destructor= false ; cf_interface= false ; cf_is_objc_block= false - ; cf_with_block_parameters= false ; cf_virtual= false } diff --git a/infer/src/IR/CallFlags.mli b/infer/src/IR/CallFlags.mli index 57ad7a5d3..03c00afce 100644 --- a/infer/src/IR/CallFlags.mli +++ b/infer/src/IR/CallFlags.mli @@ -18,8 +18,7 @@ type t = (** true if this is an implicit C++ destructor call injected by the clang frontend *) ; cf_interface: bool ; cf_is_objc_block: bool - ; cf_virtual: bool - ; cf_with_block_parameters: bool } + ; cf_virtual: bool } [@@deriving compare] val pp : F.formatter -> t -> unit diff --git a/infer/src/IR/Ident.ml b/infer/src/IR/Ident.ml index 8e631bf4f..d8a807b82 100644 --- a/infer/src/IR/Ident.ml +++ b/infer/src/IR/Ident.ml @@ -178,13 +178,6 @@ let create_normal name stamp = create_with_stamp KNormal name stamp (** Create a fresh identifier with default name for the given kind. *) let create_fresh kind = NameGenerator.create_fresh_ident kind (standard_name kind) -let create_fresh_specialized_with_blocks kind = - let fid = create_fresh kind in - (* The stamps are per-procedure unique, add a big enough number to effectively create - a namespace for vars in objc blocks *) - {fid with stamp= fid.stamp + 10000} - - let create_none () = create_fresh KNone (** Generate a footprint identifier with the given name and stamp *) diff --git a/infer/src/IR/Ident.mli b/infer/src/IR/Ident.mli index 571d094dc..71b48103d 100644 --- a/infer/src/IR/Ident.mli +++ b/infer/src/IR/Ident.mli @@ -97,10 +97,6 @@ val update_name_generator : t list -> unit val create_fresh : kind -> t (** Create a fresh identifier with default name for the given kind. *) -val create_fresh_specialized_with_blocks : kind -> t -(** Create a fresh identifier with default name for the given kind, with a non-clashing id for objc - block specialization *) - val create_path : string -> t (** Generate a normal identifier whose name encodes a path given as a string. *) diff --git a/infer/src/IR/Instrs.ml b/infer/src/IR/Instrs.ml index 8b3d07ea1..d2a1fafa6 100644 --- a/infer/src/IR/Instrs.ml +++ b/infer/src/IR/Instrs.ml @@ -80,8 +80,6 @@ let append_list t list = let of_list l = NotReversed (Array.of_list l) -let of_rev_list l = NotReversed (Array.of_list_rev l) - let filter_map t ~f = let instrs = get_underlying_not_reversed t in NotReversed (Array.filter_map instrs ~f) diff --git a/infer/src/IR/Instrs.mli b/infer/src/IR/Instrs.mli index 2bc8eaba1..d06830261 100644 --- a/infer/src/IR/Instrs.mli +++ b/infer/src/IR/Instrs.mli @@ -27,8 +27,6 @@ val append_list : not_reversed t -> Sil.instr list -> not_reversed t val of_list : Sil.instr list -> not_reversed t -val of_rev_list : Sil.instr list -> not_reversed t - val filter_map : not_reversed t -> f:(Sil.instr -> Sil.instr option) -> not_reversed t val map : not_reversed t -> f:(Sil.instr -> Sil.instr) -> not_reversed t diff --git a/infer/src/IR/Procname.ml b/infer/src/IR/Procname.ml index 5bf9f880d..f8766ff19 100644 --- a/infer/src/IR/Procname.ml +++ b/infer/src/IR/Procname.ml @@ -404,10 +404,6 @@ let as_java_exn ~explanation t = (* TODO: deprecate this unfortunately named function and use is_clang instead *) let is_c_method = function ObjC_Cpp _ -> true | _ -> false -let is_c_function = function C _ -> true | _ -> false - -let is_clang = function ObjC_Cpp name -> ObjC_Cpp.is_objc_method name | name -> is_c_function name - let is_java_lift f = function Java java_pname -> f java_pname | _ -> false let is_java_access_method = is_java_lift Java.is_access_method diff --git a/infer/src/IR/Procname.mli b/infer/src/IR/Procname.mli index b98a2cb31..f14accdc8 100644 --- a/infer/src/IR/Procname.mli +++ b/infer/src/IR/Procname.mli @@ -283,9 +283,6 @@ val is_objc_dealloc : t -> bool val is_c_method : t -> bool (** Return true this is an Objective-C/C++ method name. *) -val is_clang : t -> bool -(** Return true if this is a C, C++, or Objective-C procedure name *) - val is_constructor : t -> bool (** Check if this is a constructor. *) diff --git a/infer/src/IR/Sil.ml b/infer/src/IR/Sil.ml index 490829987..f848a36ad 100644 --- a/infer/src/IR/Sil.ml +++ b/infer/src/IR/Sil.ml @@ -190,20 +190,5 @@ let pp_instr ~print_types pe0 f instr = pp_instr_metadata pe0 f metadata ) -let add_with_block_parameters_flag instr = - match instr with - | Call (ret_id_typ, Exp.Const (Const.Cfun pname), arg_ts, loc, cf) -> - if - List.exists ~f:(fun (exp, _) -> Exp.is_objc_block_closure exp) arg_ts - && Procname.is_clang pname - (* to be extended to other methods *) - then - let cf' = {cf with cf_with_block_parameters= true} in - Call (ret_id_typ, Exp.Const (Const.Cfun pname), arg_ts, loc, cf') - else instr - | _ -> - instr - - (** Dump an instruction. *) let d_instr (i : instr) = L.d_pp_with_pe ~color:Pp.Green (pp_instr ~print_types:true) i diff --git a/infer/src/IR/Sil.mli b/infer/src/IR/Sil.mli index 0b851c825..dcabb35b8 100644 --- a/infer/src/IR/Sil.mli +++ b/infer/src/IR/Sil.mli @@ -78,10 +78,6 @@ val skip_instr : instr val instr_is_auxiliary : instr -> bool (** Check if an instruction is auxiliary, or if it comes from source instructions. *) -val add_with_block_parameters_flag : instr -> instr -(** Adds a with_blocks_parameters flag to a method call, when the arguments contain an Objective-C - block, and the method is an Objective-C method (to be extended to other methods) *) - val location_of_instr : instr -> Location.t (** Get the location of the instruction *) diff --git a/infer/src/IR/SpecializeProcdesc.ml b/infer/src/IR/SpecializeProcdesc.ml index 5ff38db44..fdaeb93d9 100644 --- a/infer/src/IR/SpecializeProcdesc.ml +++ b/infer/src/IR/SpecializeProcdesc.ml @@ -188,177 +188,3 @@ let with_formals_types ?(has_clang_model = false) callee_pdesc resolved_pname ar if not (Procname.is_java resolved_pname) then Attributes.store ~proc_desc:(Some resolved_proc_desc) resolved_attributes ; resolved_proc_desc - - -let with_block_args_instrs resolved_pdesc substitutions = - let resolved_pname = Procdesc.get_proc_name resolved_pdesc in - let convert_pvar pvar = Pvar.mk (Pvar.get_name pvar) resolved_pname in - let convert_exp exp = - match exp with - | Exp.Lvar origin_pvar -> - let new_pvar = convert_pvar origin_pvar in - Exp.Lvar new_pvar - | Exp.Lfield (Exp.Lvar origin_pvar, fname, typ) -> - let new_pvar = convert_pvar origin_pvar in - Exp.Lfield (Exp.Lvar new_pvar, fname, typ) - | _ -> - exp - in - let convert_instr (instrs, id_map) instr = - let get_block_name_and_load_captured_vars_instrs block_var loc = - let block_name, extra_formals = Mangled.Map.find block_var substitutions in - let dead_vars, id_exp_typs, load_instrs = - List.map extra_formals ~f:(fun (var, typ) -> - let id = Ident.create_fresh_specialized_with_blocks Ident.knormal in - let pvar = Pvar.mk var resolved_pname in - ( Var.of_id id - , (Exp.Var id, pvar, typ, Pvar.ByReference) - , Sil.Load {id; e= Exp.Lvar pvar; root_typ= typ; typ; loc} ) ) - |> List.unzip3 - in - let remove_temps_instr = Sil.Metadata (ExitScope (dead_vars, loc)) in - (block_name, id_exp_typs, load_instrs, remove_temps_instr) - in - let convert_generic_call return_ids exp origin_args loc call_flags = - let converted_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in - let call_instr = Sil.Call (return_ids, exp, converted_args, loc, call_flags) in - (call_instr :: instrs, id_map) - in - match instr with - | Sil.Load {id; e= Exp.Lvar block_param as origin_exp; root_typ; typ; loc} - when Mangled.Map.mem (Pvar.get_name block_param) substitutions -> - let id_map = Ident.Map.add id (Pvar.get_name block_param) id_map in - (Sil.Load {id; e= convert_exp origin_exp; root_typ; typ; loc} :: instrs, id_map) - | Sil.Load {id; e= origin_exp; root_typ; typ; loc} -> - (Sil.Load {id; e= convert_exp origin_exp; root_typ; typ; loc} :: instrs, id_map) - | Sil.Store {e1= assignee_exp; root_typ= origin_typ; e2= Exp.Var id; loc} - when Ident.Map.mem id id_map -> - let block_param = Ident.Map.find id id_map in - let block_name, id_exp_typs, load_instrs, remove_temps_instr = - get_block_name_and_load_captured_vars_instrs block_param loc - in - let closure = Exp.Closure {name= block_name; captured_vars= id_exp_typs} in - let instr = - Sil.Store {e1= assignee_exp; root_typ= origin_typ; typ= origin_typ; e2= closure; loc} - in - ((remove_temps_instr :: instr :: load_instrs) @ instrs, id_map) - | Sil.Store {e1= assignee_exp; root_typ= origin_typ; e2= origin_exp; loc} -> - let set_instr = - Sil.Store - { e1= convert_exp assignee_exp - ; root_typ= origin_typ - ; typ= origin_typ - ; e2= convert_exp origin_exp - ; loc } - in - (set_instr :: instrs, id_map) - | Sil.Call (return_ids, Exp.Var id, origin_args, loc, call_flags) -> ( - try - let block_name, id_exp_typs, load_instrs, remove_temps_instr = - let block_var = Ident.Map.find id id_map in - get_block_name_and_load_captured_vars_instrs block_var loc - in - let call_instr = - let id_exps = List.map ~f:(fun (id, _, typ, _) -> (id, typ)) id_exp_typs in - let converted_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in - Sil.Call - ( return_ids - , Exp.Const (Const.Cfun block_name) - , id_exps @ converted_args - , loc - , call_flags ) - in - let instrs = (remove_temps_instr :: call_instr :: load_instrs) @ instrs in - (instrs, id_map) - with Caml.Not_found -> - convert_generic_call return_ids (Exp.Var id) origin_args loc call_flags ) - | Sil.Call (return_ids, origin_call_exp, origin_args, loc, call_flags) -> - convert_generic_call return_ids origin_call_exp origin_args loc call_flags - | Sil.Prune (origin_exp, loc, is_true_branch, if_kind) -> - (Sil.Prune (convert_exp origin_exp, loc, is_true_branch, if_kind) :: instrs, id_map) - | Sil.Metadata _ -> - (* these are generated instructions that will be replaced by the preanalysis *) - (instrs, id_map) - in - let f_instr_list instrs = - let rev_instrs, _ = Instrs.fold ~f:convert_instr ~init:([], Ident.Map.empty) instrs in - Instrs.of_rev_list rev_instrs - in - f_instr_list - - -let append_no_duplicates_formals_and_annot = - Staged.unstage - (IList.append_no_duplicates ~cmp:(fun ((name1, _), _) ((name2, _), _) -> - Mangled.compare name1 name2 )) - - -let with_block_args callee_pdesc pname_with_block_args block_args = - let callee_attributes = Procdesc.get_attributes callee_pdesc in - (* Substitution from a block parameter to the block name and the new formals - that correspond to the captured variables *) - let substitutions : (Procname.t * (Mangled.t * Typ.t) list) Mangled.Map.t = - List.fold2_exn callee_attributes.formals block_args ~init:Mangled.Map.empty - ~f:(fun subts (param_name, _) block_arg_opt -> - match block_arg_opt with - | Some (cl : Exp.closure) -> - let formals_from_captured = - List.map - ~f:(fun (_, var, typ, _) -> - (* Here we create fresh names for the new formals, based on the names of the captured - variables annotated with the name of the caller method *) - (Pvar.build_formal_from_pvar var, typ) ) - cl.captured_vars - in - Mangled.Map.add param_name (cl.name, formals_from_captured) subts - | None -> - subts ) - in - (* Extend formals with fresh variables for the captured variables of the block arguments, - without duplications. *) - let new_formals_blocks_captured_vars, extended_formals_annots = - let new_formals_blocks_captured_vars_with_annots = - let formals_annots = - List.zip_exn callee_attributes.formals callee_attributes.method_annotation.params - in - List.fold formals_annots ~init:[] ~f:(fun acc ((param_name, typ), annot) -> - try - let _, captured = Mangled.Map.find param_name substitutions in - append_no_duplicates_formals_and_annot acc - (List.map captured ~f:(fun captured_var -> (captured_var, Annot.Item.empty))) - with Caml.Not_found -> - append_no_duplicates_formals_and_annot acc [((param_name, typ), annot)] ) - in - List.unzip new_formals_blocks_captured_vars_with_annots - in - let translation_unit = - let pname = Procdesc.get_proc_name callee_pdesc in - match Attributes.find_file_capturing_procedure pname with - | Some (source_file, _) -> - source_file - | None -> - Logging.die InternalError - "specialize_with_block_args ahould only be called with defined procedures, but we cannot \ - find the captured file of procname %a" - Procname.pp pname - in - let resolved_attributes = - { callee_attributes with - proc_name= pname_with_block_args - ; is_defined= true - ; formals= new_formals_blocks_captured_vars - ; method_annotation= - {return= callee_attributes.method_annotation.return; params= extended_formals_annots} - ; translation_unit } - in - let resolved_pdesc = Procdesc.from_proc_attributes resolved_attributes in - Logging.(debug Analysis Verbose) - "signature of base method %a@." Procdesc.pp_signature callee_pdesc ; - Logging.(debug Analysis Verbose) - "signature of specialized method %a@." Procdesc.pp_signature resolved_pdesc ; - let proc_desc = - convert_cfg ~callee_pdesc ~resolved_pdesc - ~f_instr_list:(with_block_args_instrs resolved_pdesc substitutions) - in - Attributes.store ~proc_desc:(Some proc_desc) resolved_attributes ; - proc_desc diff --git a/infer/src/IR/SpecializeProcdesc.mli b/infer/src/IR/SpecializeProcdesc.mli index c27ee5d24..0eda6e9b3 100644 --- a/infer/src/IR/SpecializeProcdesc.mli +++ b/infer/src/IR/SpecializeProcdesc.mli @@ -15,11 +15,3 @@ val with_formals_types : typ) where name is a parameter. The resulting procdesc is isomorphic but all the type of the parameters are replaced in the instructions according to the list. The virtual calls are also replaced to match the parameter types *) - -val with_block_args : Procdesc.t -> Procname.t -> Exp.closure option list -> Procdesc.t -(** Creates a copy of a procedure description given a list of possible closures that are passed as - arguments to the method. The resulting procdesc is isomorphic but - - - the block parameters are replaces with the closures - - the parameters of the method are extended with parameters for the captured variables in the - closures *) diff --git a/infer/src/biabduction/ObjCDispatchModels.ml b/infer/src/biabduction/ObjCDispatchModels.ml new file mode 100644 index 000000000..121daa031 --- /dev/null +++ b/infer/src/biabduction/ObjCDispatchModels.ml @@ -0,0 +1,18 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) +open! IStd + +let dispatch_models = + [ "_dispatch_once" + ; "dispatch_async" + ; "dispatch_after" + ; "dispatch_group_async" + ; "dispatch_barrier_async" + ; "dispatch_group_notify" ] + + +let is_model proc_name = List.mem dispatch_models ~equal:String.equal (Procname.to_string proc_name) diff --git a/infer/src/biabduction/ObjCDispatchModels.mli b/infer/src/biabduction/ObjCDispatchModels.mli new file mode 100644 index 000000000..82e74fbec --- /dev/null +++ b/infer/src/biabduction/ObjCDispatchModels.mli @@ -0,0 +1,10 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd + +val is_model : Procname.t -> bool diff --git a/infer/src/biabduction/SymExec.ml b/infer/src/biabduction/SymExec.ml index 65ab24138..5989f7a93 100644 --- a/infer/src/biabduction/SymExec.ml +++ b/infer/src/biabduction/SymExec.ml @@ -1065,6 +1065,11 @@ let declare_locals_and_ret tenv pdesc (prop_ : Prop.normal Prop.t) = prop' +let get_closure_opt actual_params = + List.find_map actual_params ~f:(fun (exp, _) -> + match exp with Exp.Closure c when Procname.is_objc_block c.name -> Some c | _ -> None ) + + (** Execute [instr] with a symbolic heap [prop].*) let rec sym_exec ( {InterproceduralAnalysis.proc_desc= current_pdesc; analyze_dependency; err_log; tenv} as @@ -1091,6 +1096,15 @@ let rec sym_exec let proc_exp' = Prop.exp_normalize_prop tenv prop_ proc_exp in let par' = List.map ~f:(fun (id_exp, _, typ, _) -> (id_exp, typ)) c.captured_vars in Sil.Call (ret, proc_exp', par' @ par, loc, call_flags) + | Exp.Const (Const.Cfun callee_pname) when ObjCDispatchModels.is_model callee_pname -> ( + match get_closure_opt par with + | Some c -> + (* We assume that for these modelled functions, the block passed as parameter doesn't + have arguments, so we only pass the captured variables. *) + let args = List.map ~f:(fun (id_exp, _, typ, _) -> (id_exp, typ)) c.captured_vars in + Sil.Call (ret, Exp.Const (Const.Cfun c.name), args, loc, call_flags) + | None -> + Sil.Call (ret, exp', par, loc, call_flags) ) | _ -> Sil.Call (ret, exp', par, loc, call_flags) in @@ -1189,80 +1203,61 @@ let rec sym_exec exec_skip_call ~reason ret_annots proc_attrs.ProcAttributes.ret_type ) in List.fold ~f:(fun acc pname -> exec_one_pname pname @ acc) ~init:[] resolved_pnames - | _ -> ( + | _ -> (* Generic fun call with known name *) let prop_r, n_actual_params = normalize_params analysis_data prop_ actual_params in - (* method with block parameters *) - let with_block_parameters_summary_opt = - if call_flags.CallFlags.cf_with_block_parameters then - SymExecBlocks.resolve_method_with_block_args_and_analyze analysis_data callee_pname - actual_params - else None + let resolve_and_analyze_result = + resolve_and_analyze_clang analysis_data prop_r n_actual_params callee_pname call_flags in - match with_block_parameters_summary_opt with - | Some (resolved_summary, extended_actual_params) -> - let prop_r, n_extended_actual_params = - normalize_params analysis_data prop_r extended_actual_params - in - Logging.d_strln "Calling method specialized with blocks... " ; - proc_call resolved_summary - (call_args prop_r callee_pname n_extended_actual_params ret_id_typ loc) - | None -> - (* Generic fun call with known name *) - let resolve_and_analyze_result = - resolve_and_analyze_clang analysis_data prop_r n_actual_params callee_pname - call_flags - in - let resolved_pname = resolve_and_analyze_result.resolved_pname in - let resolved_pdesc_opt = resolve_and_analyze_result.resolved_procdesc_opt in - let resolved_summary_opt = resolve_and_analyze_result.resolved_summary_opt in - Logging.d_printfln "Original callee %s" (Procname.to_unique_id callee_pname) ; - Logging.d_printfln "Resolved callee %s" (Procname.to_unique_id resolved_pname) ; - let sentinel_result = - if Language.curr_language_is Clang then - check_variadic_sentinel_if_present - (call_args prop_r resolved_pname actual_params ret_id_typ loc) - else [(prop_r, path)] - in - let do_call (prop, path) = - let callee_desc = - match (resolved_summary_opt, resolved_pdesc_opt) with - | Some summary, _ -> - `Summary summary - | None, Some pdesc -> - `ProcDesc pdesc - | None, None -> - `ProcName resolved_pname + let resolved_pname = resolve_and_analyze_result.resolved_pname in + let resolved_pdesc_opt = resolve_and_analyze_result.resolved_procdesc_opt in + let resolved_summary_opt = resolve_and_analyze_result.resolved_summary_opt in + Logging.d_printfln "Original callee %s" (Procname.to_unique_id callee_pname) ; + Logging.d_printfln "Resolved callee %s" (Procname.to_unique_id resolved_pname) ; + let sentinel_result = + if Language.curr_language_is Clang then + check_variadic_sentinel_if_present + (call_args prop_r resolved_pname actual_params ret_id_typ loc) + else [(prop_r, path)] + in + let do_call (prop, path) = + let callee_desc = + match (resolved_summary_opt, resolved_pdesc_opt) with + | Some summary, _ -> + `Summary summary + | None, Some pdesc -> + `ProcDesc pdesc + | None, None -> + `ProcName resolved_pname + in + match reason_to_skip ~callee_desc with + | Some reason -> ( + let ret_annots = + match resolved_summary_opt with + | Some (proc_desc, _) -> + (Procdesc.get_attributes proc_desc).ProcAttributes.method_annotation.return + | None -> + load_ret_annots resolved_pname in - match reason_to_skip ~callee_desc with - | Some reason -> ( - let ret_annots = - match resolved_summary_opt with - | Some (proc_desc, _) -> - (Procdesc.get_attributes proc_desc).ProcAttributes.method_annotation - .return - | None -> - load_ret_annots resolved_pname + match resolved_pdesc_opt with + | Some resolved_pdesc -> + let attrs = Procdesc.get_attributes resolved_pdesc in + let ret_type = attrs.ProcAttributes.ret_type in + let is_objc_instance_method = + ClangMethodKind.equal attrs.ProcAttributes.clang_method_kind + ClangMethodKind.OBJC_INSTANCE in - match resolved_pdesc_opt with - | Some resolved_pdesc -> - let attrs = Procdesc.get_attributes resolved_pdesc in - let ret_type = attrs.ProcAttributes.ret_type in - let is_objc_instance_method = - ClangMethodKind.equal attrs.ProcAttributes.clang_method_kind - ClangMethodKind.OBJC_INSTANCE - in - skip_call ~is_objc_instance_method ~reason prop path resolved_pname - ret_annots loc ret_id_typ ret_type n_actual_params - | None -> - skip_call ~reason prop path resolved_pname ret_annots loc ret_id_typ - (snd ret_id_typ) n_actual_params ) + skip_call ~is_objc_instance_method ~reason prop path resolved_pname ret_annots + loc ret_id_typ ret_type n_actual_params | None -> - proc_call - (Option.value_exn resolved_summary_opt) - (call_args prop resolved_pname n_actual_params ret_id_typ loc) - in - List.concat_map ~f:do_call sentinel_result ) ) ) + skip_call ~reason prop path resolved_pname ret_annots loc ret_id_typ + (snd ret_id_typ) n_actual_params ) + | None -> + proc_call + (Option.value_exn resolved_summary_opt) + (call_args prop resolved_pname n_actual_params ret_id_typ loc) + in + List.concat_map ~f:do_call sentinel_result ) ) | Sil.Call (ret_id_typ, fun_exp, actual_params, loc, call_flags) -> (* Call via function pointer *) let prop_r, n_actual_params = normalize_params analysis_data prop_ actual_params in diff --git a/infer/src/biabduction/SymExecBlocks.ml b/infer/src/biabduction/SymExecBlocks.ml deleted file mode 100644 index 28db1989a..000000000 --- a/infer/src/biabduction/SymExecBlocks.ml +++ /dev/null @@ -1,101 +0,0 @@ -(* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - *) - -open! IStd - -(* Given two lists of tuples (exp1, var1, typ1) and (exp2, var2, typ2) append the lists avoiding - duplicates, where if the variables exist we check their equality, otherwise we check the equality - of the expressions. This is to avoid adding the same captured variable twice. *) -let append_no_duplicates_vars = - let cmp (exp1, var1_opt, _) (exp2, var2_opt, _) = - match (var1_opt, var2_opt) with - | Some var1, Some var2 -> - Pvar.compare var1 var2 - | None, None -> - Exp.compare exp1 exp2 - | Some _, None -> - 1 - | None, Some _ -> - -1 - in - Staged.unstage (IList.append_no_duplicates ~cmp) - - -(* Given a list of actual parameters for a function, replaces the closures with the -captured variables, avoiding adding the same captured variable twice. *) -let get_extended_args_for_method_with_block_analysis act_params = - let ext_actuals = List.map ~f:(fun (exp, typ) -> (exp, None, typ)) act_params in - let args_and_captured = - List.fold ext_actuals ~init:[] ~f:(fun all_args act_param -> - match act_param with - | Exp.Closure cl, _, _ -> - let captured = - List.map ~f:(fun (exp, var, typ, _) -> (exp, Some var, typ)) cl.captured_vars - in - append_no_duplicates_vars all_args captured - | _ -> - List.append all_args [act_param] ) - in - List.map ~f:(fun (exp, _, typ) -> (exp, typ)) args_and_captured - - -let resolve_method_with_block_args_and_analyze - {InterproceduralAnalysis.analyze_dependency; analyze_pdesc_dependency} pname act_params = - let pdesc_opt = - match analyze_dependency pname with - | Some (proc_desc, _) -> - Some proc_desc - | None -> - AnalysisCallbacks.get_proc_desc pname - in - match pdesc_opt with - | Some pdesc - when Procdesc.is_defined pdesc - && Int.equal (List.length (Procdesc.get_formals pdesc)) (List.length act_params) - (* only specialize defined methods, and when formals and actuals have the same length *) - -> ( - (* a list with the same length of the actual params of the function, - containing either a Closure or None. *) - let block_args = - List.map act_params ~f:(function - | Exp.Closure cl, _ when Procname.is_objc_block cl.name -> - Some cl - | _ -> - None ) - in - (* name for the specialized method instantiated with block arguments *) - let pname_with_block_args = - let block_name_args = - List.filter_map block_args ~f:(function - | Some (cl : Exp.closure) -> - Some (Procname.block_name_of_procname cl.name) - | None -> - None ) - in - Procname.with_block_parameters pname block_name_args - in - (* new procdesc cloned from the original one, where the block parameters have been - replaced by the block arguments. The formals have also been expanded with the captured variables *) - let specialized_pdesc = - SpecializeProcdesc.with_block_args pdesc pname_with_block_args block_args - in - Logging.(debug Analysis Verbose) "Instructions of specialized method:@." ; - Procdesc.iter_instrs - (fun _ instr -> - Logging.(debug Analysis Verbose) "%a@." (Sil.pp_instr ~print_types:false Pp.text) instr ) - specialized_pdesc ; - Logging.(debug Analysis Verbose) "End of instructions@." ; - match analyze_pdesc_dependency specialized_pdesc with - | Some summary -> - (* Since the closures in the formals were replaced by the captured variables, - we do the same with the actual arguments *) - let extended_args = get_extended_args_for_method_with_block_analysis act_params in - Some ((specialized_pdesc, summary), extended_args) - | None -> - None ) - | _ -> - None diff --git a/infer/src/biabduction/SymExecBlocks.mli b/infer/src/biabduction/SymExecBlocks.mli deleted file mode 100644 index 0d5bae2cb..000000000 --- a/infer/src/biabduction/SymExecBlocks.mli +++ /dev/null @@ -1,20 +0,0 @@ -(* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - *) - -open! IStd - -val resolve_method_with_block_args_and_analyze : - BiabductionSummary.t InterproceduralAnalysis.t - -> Procname.t - -> (Exp.t * Typ.t) list - -> ((Procdesc.t * BiabductionSummary.t) * (Exp.t * Typ.t) list) option -(** [resolve_method_with_block_args_and_analyze caller_pdesc pname args] create a copy of the method - pname if it is defined and it's called with the correct number of arguments, and some arguments - are block closures. The copy is created by adding extra formals for each captured variable, and - by swapping the calls to the block arguments to the calls to the concrete blocks. The new - procedure is analyzed and the possibly computed summary is returned together with the list of - arguments where the closures where swapped by their captured variables. *) diff --git a/infer/src/clang/CCallSpecializedWithClosures.ml b/infer/src/clang/CCallSpecializedWithClosures.ml index 1125aa79f..87b0123ce 100644 --- a/infer/src/clang/CCallSpecializedWithClosures.ml +++ b/infer/src/clang/CCallSpecializedWithClosures.ml @@ -124,6 +124,11 @@ let is_initializer proc_desc = Procname.is_constructor proc_name +let is_dispatch_model proc_desc = + let proc_name = Procdesc.get_proc_name proc_desc in + ObjCDispatchModels.is_model proc_name + + let replace_with_specialize_methods cfg _node instr = match instr with | Sil.Call (ret, Exp.Const (Const.Cfun callee_pname), actual_params, loc, flags) @@ -133,7 +138,10 @@ let replace_with_specialize_methods cfg _node instr = parameter and then run the block. It doesn't work well when the block is instead stored in a field. This case will be left as future work, and we won't specialize common cases where this happens such as setters or initializers. *) - | Some proc_desc when (not (is_objc_setter proc_desc)) && not (is_initializer proc_desc) -> ( + | Some proc_desc + when (not (is_objc_setter proc_desc)) + && (not (is_initializer proc_desc)) + && not (is_dispatch_model proc_desc) -> ( let callee_attributes = Procdesc.get_attributes proc_desc in match formals_actuals_map callee_attributes.formals callee_attributes.method_annotation.params diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 5a78d2f6f..cec877708 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -291,9 +291,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let call_instr = Sil.Call (ret_id', function_sil, params @ forwarded_params, sil_loc, call_flags) in - let call_instr' = Sil.add_with_block_parameters_flag call_instr in mk_trans_result ret_exps - {empty_control with instrs= forwarded_init_instrs @ [call_instr']; initd_exps} + {empty_control with instrs= forwarded_init_instrs @ [call_instr]; initd_exps} (** Given a captured var, return the instruction to assign it to a temp *) diff --git a/infer/tests/build_systems/objc_getters_setters/issues.exp b/infer/tests/build_systems/objc_getters_setters/issues.exp index ee4bf2a4d..ef90c69a6 100644 --- a/infer/tests/build_systems/objc_getters_setters/issues.exp +++ b/infer/tests/build_systems/objc_getters_setters/issues.exp @@ -1,5 +1,5 @@ -build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_c_function_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_c_function_with_block_parameters_sets_fields_correctly,start of procedure calling_c_function_with_block_parameters,start of procedure c_function(),start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_3,start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_4,return from a call to c_function_objc_blockB.calling_c_function_with_block_parameters_3_objc_blockB.calling_c_function_with_block_parameters_4,return from a call to B.calling_c_function_with_block_parameters,Taking true branch] -build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_method_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_method_with_block_parameters_sets_fields_correctly,start of procedure calling_method_with_block_parameters,start of procedure foo:and:and_also:and:,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_1,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_2,return from a call to A.foo:and:and_also:and:_objc_blockB.calling_method_with_block_parameters_1_objc_blockB.calling_method_with_block_parameters_2,return from a call to B.calling_method_with_block_parameters,Taking true branch] +build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_c_function_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_c_function_with_block_parameters_sets_fields_correctly,start of procedure calling_c_function_with_block_parameters,start of procedure c_function(),start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_3,start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_4,return from a call to c_function,return from a call to B.calling_c_function_with_block_parameters,Taking true branch] +build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_method_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_method_with_block_parameters_sets_fields_correctly,start of procedure calling_method_with_block_parameters,start of procedure foo:and:and_also:and:,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_1,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_2,return from a call to A.foo:and:and_also:and:,return from a call to B.calling_method_with_block_parameters,Taking true branch] build_systems/codetoanalyze/objc_getters_setters/B.m, B.npe_no_bad_footprint_in_getter:, 3, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure npe_no_bad_footprint_in_getter:,start of procedure metadata,return from a call to A.metadata] build_systems/codetoanalyze/objc_getters_setters/B.m, B.npe_no_bad_footprint_in_setter:andMetadata:, 3, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure npe_no_bad_footprint_in_setter:andMetadata:,start of procedure setMetadata:,return from a call to A.setMetadata:] build_systems/codetoanalyze/objc_getters_setters/B.m, B.npe_no_precondition_not_met:, 4, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure npe_no_precondition_not_met:,start of procedure infer_field_get_spec:,start of procedure withMetadata:,return from a call to A.withMetadata:,return from a call to B.infer_field_get_spec:,start of procedure getX,return from a call to A.getX,Taking true branch] diff --git a/infer/tests/codetoanalyze/objc/biabduction/issues.exp b/infer/tests/codetoanalyze/objc/biabduction/issues.exp index 6cd590944..f92183704 100644 --- a/infer/tests/codetoanalyze/objc/biabduction/issues.exp +++ b/infer/tests/codetoanalyze/objc/biabduction/issues.exp @@ -3,8 +3,8 @@ codetoanalyze/objc/biabduction/field_superclass/field.c, field_superclass_main, codetoanalyze/objc/biabduction/global_const/global_const.m, SimpleRoot.doSomethingBadWithDict:andString:, 3, NULL_DEREFERENCE, B2, ERROR, [start of procedure doSomethingBadWithDict:andString:,Message stringByAppendingString: with receiver nil returns nil.] codetoanalyze/objc/biabduction/global_const/global_const.m, SimpleRoot.doSomethingOkWithDict:andString:, 3, NULL_DEREFERENCE, B2, ERROR, [start of procedure doSomethingOkWithDict:andString:,Message stringByAppendingString: with receiver nil returns nil.] codetoanalyze/objc/biabduction/initialization/compound_literal.c, init_with_compound_literal, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure init_with_compound_literal()] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure foo,start of procedure setHandler:,return from a call to RetainCSV.setHandler:_objc_blockRetainCSV.foo_1] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure foo,start of procedure setHandler:,return from a call to RetainCSV.setHandler:_objc_blockRetainCSV.foo_1] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure foo,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_3,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_2,start of procedure setHandler:,return from a call to RetainCSV.setHandler:] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure foo,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_3,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_2,start of procedure setHandler:,return from a call to RetainCSV.setHandler:] codetoanalyze/objc/biabduction/npe/null_returned_by_method.m, NullReturnedByMethodA.test1, 1, NULL_DEREFERENCE, B5, ERROR, [start of procedure test1,start of procedure test,return from a call to NullReturnedByMethodA.test] codetoanalyze/objc/biabduction/procdescs/main.c, ProcdescMain, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure ProcdescMain(),Skipping plusX:andY:: method has no implementation] codetoanalyze/objc/biabduction/procdescs/main.c, call_nslog, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure call_nslog(),Skipping NSLog(): method has no implementation] @@ -23,18 +23,18 @@ codetoanalyze/objc/shared/block/block.m, main1, 30, DIVIDE_BY_ZERO, no_bucket, E codetoanalyze/objc/shared/block/block_no_args.m, Block_no_args.m, 10, NULL_DEREFERENCE, B1, ERROR, [start of procedure m,start of procedure block,return from a call to objc_blockBlock_no_args.m_1,Taking true branch] codetoanalyze/objc/shared/category_procdesc/main.c, CategoryProcdescMain, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure CategoryProcdescMain(),Skipping performDaysWork: method has no implementation] codetoanalyze/objc/shared/field_superclass/SuperExample.m, ASuper.init, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure init] -codetoanalyze/objc/biabduction/blocks_in_heap/BlockInHeap.m, block_in_heap_executed_after_bi_abduction_ok_test, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure block_in_heap_executed_after_bi_abduction_ok_test(),start of procedure block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle(),start of procedure assign_block_to_ivar,start of procedure setHandler:,return from a call to BlockInHeap.setHandler:_objc_blockBlockInHeap.assign_block_to_ivar_1,return from a call to BlockInHeap.assign_block_to_ivar,start of procedure handler,return from a call to BlockInHeap.handler,start of procedure block,return from a call to objc_blockBlockInHeap.assign_block_to_ivar_1,return from a call to block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle,Taking true branch] +codetoanalyze/objc/biabduction/blocks_in_heap/BlockInHeap.m, block_in_heap_executed_after_bi_abduction_ok_test, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure block_in_heap_executed_after_bi_abduction_ok_test(),start of procedure block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle(),start of procedure assign_block_to_ivar,start of procedure setHandler:,return from a call to BlockInHeap.setHandler:,return from a call to BlockInHeap.assign_block_to_ivar,start of procedure handler,return from a call to BlockInHeap.handler,start of procedure block,return from a call to objc_blockBlockInHeap.assign_block_to_ivar_1,return from a call to block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle,Taking true branch] codetoanalyze/objc/biabduction/field_superclass/SubtypingExample.m, Employee.initWithName:andAge:andEducation:, 6, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure initWithName:andAge:andEducation:,start of procedure initWithName:andAge:,return from a call to Person.initWithName:andAge:,Taking true branch] codetoanalyze/objc/biabduction/field_superclass/SubtypingExample.m, subtyping_test, 0, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure subtyping_test(),start of procedure testFields(),start of procedure setEmployeeEducation:,return from a call to Employee.setEmployeeEducation:,start of procedure setAge:,return from a call to Person.setAge:,start of procedure setEmployeeEducation:,return from a call to Employee.setEmployeeEducation:,start of procedure getAge,return from a call to Person.getAge,return from a call to testFields] codetoanalyze/objc/biabduction/initialization/struct_initlistexpr.c, field_set_correctly, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure field_set_correctly()] codetoanalyze/objc/biabduction/initialization/struct_initlistexpr.c, implicit_expr_set_correctly, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure implicit_expr_set_correctly()] codetoanalyze/objc/biabduction/initialization/struct_initlistexpr.c, point_coords_set_correctly, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure point_coords_set_correctly()] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:_objc_blockFBSomeDataManager.fetchNewData_1] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:_objc_blockFBSomeDataManager.fetchNewData_1] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:_objc_blockLinkResolver.test_bad_1] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:_objc_blockLinkResolver.test_bad_1] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:_objc_blockRCBlock.retain_self_in_block_1] -codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:_objc_blockRCBlock.retain_self_in_block_1] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:] +codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:] codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, objc_blockretain_a_in_block_cycle_3, 1, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure block,start of procedure setChild:,return from a call to RCBlockAA.setChild:] codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, objc_blockretain_a_in_block_cycle_3, 1, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure block,start of procedure setChild:,return from a call to RCBlockAA.setChild:] codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, retain_a_in_block_cycle, 4, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure retain_a_in_block_cycle(),start of procedure setB:,return from a call to RCBlockAA.setB:,start of procedure setA:,return from a call to RCBlock.setA:] @@ -99,7 +99,7 @@ codetoanalyze/objc/biabduction/npe/dynamic_dispatch.m, objc_blockDynamicDispatch codetoanalyze/objc/biabduction/npe/ivar_blocks.m, MyClass.ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe] codetoanalyze/objc/biabduction/npe/skip_method_with_nil_object.m, SkipMethodNilA.testBug:, 6, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure testBug:,Message get_a with receiver nil returns nil.,Message skip_method with receiver nil returns nil.,Taking false branch] codetoanalyze/objc/biabduction/property/main.c, property_main, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation] -codetoanalyze/objc/biabduction/resource_leaks/Dispatch_sources.m, ProcessContentsOfFile, 35, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure ProcessContentsOfFile(),Taking false branch,Skipping dispatch_get_global_queue(): method has no implementation,Skipping dispatch_source_create(): method has no implementation,Taking false branch,Skipping dispatch_source_set_event_handler(): method has no implementation,Skipping dispatch_source_set_cancel_handler(): method has no implementation] +codetoanalyze/objc/biabduction/resource_leaks/Dispatch_sources.m, ProcessContentsOfFile, 35, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure ProcessContentsOfFile(),Taking false branch,Skipping dispatch_get_global_queue(): method has no implementation,Skipping dispatch_source_create(): method has no implementation,Taking false branch] codetoanalyze/objc/biabduction/resource_leaks/Dispatch_sources.m, objc_blockProcessContentsOfFile_2, 6, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure block,Skipping dispatch_source_get_data(): method has no implementation,Taking true branch,Skipping MyProcessFileData(): method has no implementation] codetoanalyze/objc/biabduction/resource_leaks/ResourceLeakExample.m, NSFileHandle.fileHandleForLoggingAtPath:mode:, 9, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure fileHandleForLoggingAtPath:mode:,Taking true branch,Skipping fileSystemRepresentation: method has no implementation,Taking false branch,Taking true branch,Skipping autorelease: no implementation found for method declared in Objective-C protocol] codetoanalyze/objc/shared/annotations/nonnull_annotations.m, NonnullAnnot.test1:, 2, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure test1:,Message child with receiver nil returns nil.] @@ -107,5 +107,5 @@ codetoanalyze/objc/shared/annotations/nonnull_annotations.m, NonnullAnnot.test3: codetoanalyze/objc/shared/annotations/nullable_annotations.m, User.otherUserName, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure otherUserName,Skipping otherUser: method has no implementation] codetoanalyze/objc/shared/annotations/nullable_annotations.m, npe_property_nullable, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure npe_property_nullable(),Skipping child: method has no implementation] codetoanalyze/objc/shared/annotations/nullable_annotations_fields.m, A.nullable_field, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure nullable_field,Skipping getA(): method has no implementation] -codetoanalyze/objc/shared/block/dispatch.m, DispatchA.dispatch_a_block_variable_from_macro_delivers_initialised_object, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure dispatch_a_block_variable_from_macro_delivers_initialised_object,start of procedure dispatch_a_block_variable_from_macro,return from a call to DispatchA.dispatch_a_block_variable_from_macro] +codetoanalyze/objc/shared/block/dispatch.m, DispatchA.dispatch_a_block_variable_from_macro_delivers_initialised_object, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure dispatch_a_block_variable_from_macro_delivers_initialised_object,start of procedure dispatch_a_block_variable_from_macro,Skipping _dispatch_once(): method has no implementation,return from a call to DispatchA.dispatch_a_block_variable_from_macro] codetoanalyze/objc/shared/npe/Available_expr.m, Available_expr.test_no_bug, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure test_no_bug,Taking true branch] diff --git a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot index 16f2ca51b..416119e31 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot @@ -52,7 +52,7 @@ digraph cfg { "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" [label="2: Exit A.capture \n " color=yellow style=filled] -"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*) block_params virtual [line 45, column 3]\n " shape="box"] +"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*) virtual [line 45, column 3]\n " shape="box"] "capture#A#instance.d411336575e4bf632a1828f5f5979726_3" -> "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot index 01678eb7c..c3f610c50 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot @@ -77,7 +77,7 @@ digraph cfg { "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_2" ; -"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,n$18:A*) block_params [line 39, column 3]\n " shape="box"] +"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,n$18:A*) [line 39, column 3]\n " shape="box"] "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" ; @@ -96,7 +96,7 @@ digraph cfg { "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_3" ; -"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,n$10:A*) block_params [line 26, column 3]\n " shape="box"] +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,n$10:A*) [line 26, column 3]\n " shape="box"] "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" ; diff --git a/infer/tests/codetoanalyze/objc/performance/NSArray.m b/infer/tests/codetoanalyze/objc/performance/NSArray.m index 496c95372..c4f243e2b 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSArray.m +++ b/infer/tests/codetoanalyze/objc/performance/NSArray.m @@ -118,6 +118,9 @@ id nsarray_first_object_constant(NSArray* array) { return array.firstObject; } id nsarray_last_object_constant(NSArray* array) { return array.lastObject; } // find element +// To be uncommented when we find a solution to avoiding absolute paths +// from the standard library in tests. +/* NSInteger nsarray_binary_search_log_FN(NSArray* sorted_array) { NSNumber* target = @5; return [sorted_array indexOfObject:target @@ -127,6 +130,7 @@ NSInteger nsarray_binary_search_log_FN(NSArray* sorted_array) { return [lhs compare:rhs]; }]; } +*/ // sort array diff --git a/infer/tests/codetoanalyze/objc/performance/block.m b/infer/tests/codetoanalyze/objc/performance/block.m index 6582172b1..3771d9c65 100644 --- a/infer/tests/codetoanalyze/objc/performance/block.m +++ b/infer/tests/codetoanalyze/objc/performance/block.m @@ -33,7 +33,7 @@ void doBlockA_linear_FN(int a) { runBlockA(block); } -void doBlockA_direct_block_linear_FN(int a) { +void doBlockA_direct_block_linear(int a) { runBlockA(^{ loop_linear(a); }); diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index 973c5063a..a27247741 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -3,7 +3,6 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array codetoanalyze/objc/performance/NSArray.m, nsarray_add_object_constant, 8, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear_FN, 8, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant, 27, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_binary_search_log_FN, 10, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_contains_object_linear, 3 + array->elements.length.ub, OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.containsObject:] codetoanalyze/objc/performance/NSArray.m, nsarray_count_bounded_linear, 3 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_empty_array_constant, 8, OnUIThread:false, [] @@ -24,7 +23,6 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear, 5 + array- codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 34, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 39, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn, 9 + array->elements.length.ub × log(array->elements.length.ub), OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:,{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:] -codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 5, OnUIThread:false, [] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear1, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear2, 6 + 3 ⋅ dict->elements.length.ub + 3 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] @@ -80,13 +78,14 @@ codetoanalyze/objc/performance/araii.m, Araii.initWithBuffer, 15, OnUIThread:fa codetoanalyze/objc/performance/araii.m, Araii.setBuffer:, 4, OnUIThread:false, [] codetoanalyze/objc/performance/araii.m, memory_leak_raii_main, 18, OnUIThread:false, [] codetoanalyze/objc/performance/block.m, block_multiply_array_linear, 13 + 5 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Call to objc_blockblock_multiply_array_linear_1,Loop,{array->elements.length.ub},Call to objc_blockblock_multiply_array_linear_1,Loop] -codetoanalyze/objc/performance/block.m, doBlockA_direct_block_linear_FN, 5, OnUIThread:false, [] +codetoanalyze/objc/performance/block.m, doBlockA_direct_block_linear, 10 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to runBlockA[objc_blockdoBlockA_direct_block_linear_3],Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop,{a},Call to runBlockA[objc_blockdoBlockA_direct_block_linear_3],Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop] codetoanalyze/objc/performance/block.m, doBlockA_linear_FN, 7, OnUIThread:false, [] codetoanalyze/objc/performance/block.m, loop_linear, 3 + 3 ⋅ x + 2 ⋅ (1+max(0, x)), OnUIThread:false, [{1+max(0, x)},Loop,{x},Loop] codetoanalyze/objc/performance/block.m, objc_blockblock_multiply_array_linear_1, 8 + 5 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] -codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_direct_block_linear_FN_3, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop] +codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_direct_block_linear_3, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop] codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_linear_FN_2, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop] codetoanalyze/objc/performance/block.m, runBlockA, 3, OnUIThread:false, [] +codetoanalyze/objc/performance/block.m, runBlockA[objc_blockdoBlockA_direct_block_linear_3], 8 + 3 ⋅ a[doBlockA_direct_block_linear()] + 2 ⋅ (1+max(0, a[doBlockA_direct_block_linear()])), OnUIThread:false, [{1+max(0, a[doBlockA_direct_block_linear()])},Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop,{a[doBlockA_direct_block_linear()]},Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop] codetoanalyze/objc/performance/break.m, break_constant_FP, 8 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Call to break_loop,Loop,{p},Call to break_loop,Loop] codetoanalyze/objc/performance/break.m, break_loop, 5 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Loop,{p},Loop] codetoanalyze/objc/performance/break.m, break_loop_with_t, 7 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Loop,{p},Loop] diff --git a/infer/tests/codetoanalyze/objc/pulse/issues.exp b/infer/tests/codetoanalyze/objc/pulse/issues.exp index 1351117a4..d8317af99 100644 --- a/infer/tests/codetoanalyze/objc/pulse/issues.exp +++ b/infer/tests/codetoanalyze/objc/pulse/issues.exp @@ -8,7 +8,7 @@ codetoanalyze/objc/pulse/MemoryLeaks.m, call_bridge_interproc_leak_ok_FP, 2, MEM codetoanalyze/objc/pulse/MemoryLeaks.m, call_cfrelease_interproc_leak_ok_FP, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `CFLocaleCreate` (modelled),allocation part of the trace ends here,memory becomes unreachable here] codetoanalyze/objc/pulse/MemoryLeaksInBlocks.m, block_captured_var_leak_bad, 6, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `malloc_no_fail` (modelled),allocation part of the trace ends here,memory becomes unreachable here] codetoanalyze/objc/pulse/NPEBlocks.m, Singleton.dispatch_once_no_npe_good_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here] -codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,when calling `objc_blockcaptured_npe_bad_2` here,parameter `x` of objc_blockcaptured_npe_bad_2,invalid access occurs here] +codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,when calling `objc_blockcaptured_npe_bad_3` here,parameter `x` of objc_blockcaptured_npe_bad_3,invalid access occurs here] codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_ok_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here] codetoanalyze/objc/pulse/use_after_free.m, PulseTest.use_after_free_simple_in_objc_method_bad:, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,invalid access occurs here] codetoanalyze/objc/pulse/use_after_free.m, use_after_free_simple_bad, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of use_after_free_simple_bad,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of use_after_free_simple_bad,invalid access occurs here] diff --git a/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot b/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot index 1b885bbd1..6a44c6d59 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot @@ -33,7 +33,7 @@ digraph cfg { "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_2" ; -"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ) block_params [line 23, column 3]\n " shape="box"] +"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ) [line 23, column 3]\n " shape="box"] "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot b/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot index a4b7e7ec3..68f4d5733 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot @@ -63,7 +63,7 @@ digraph cfg { "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" [label="2: Exit MyBlock.array \n " color=yellow style=filled] -"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*) block_params virtual [line 19, column 3]\n " shape="box"] +"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*) virtual [line 19, column 3]\n " shape="box"] "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" -> "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot b/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot index 6ba52ce77..06f122bb4 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/dispatch.m.dot @@ -110,7 +110,7 @@ digraph cfg { "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_3" -> "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_2" ; -"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" [label="4: Call _fun__dispatch_once \n n$7=*&a:DispatchA* [line 37, column 24]\n n$9=_fun__dispatch_once[objc_blockDispatchA.block_attribute_2](&#GB$DispatchA.block_attribute.once:long*,n$7:DispatchA*) block_params [line 37, column 3]\n " shape="box"] +"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" [label="4: Call _fun__dispatch_once \n n$7=*&a:DispatchA* [line 37, column 24]\n n$9=_fun__dispatch_once(&#GB$DispatchA.block_attribute.once:long*,(_fun_objc_blockDispatchA.block_attribute_2,([by ref]n$7 &a:DispatchA*)):_fn_(*)) [line 37, column 3]\n " shape="box"] "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" -> "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_3" ; @@ -190,7 +190,7 @@ digraph cfg { "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_3" -> "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_2" ; -"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" [label="4: Call _fun__dispatch_once \n n$4=_fun__dispatch_once[objc_blockDispatchA.sharedInstance_1](&#GB$DispatchA.sharedInstance.once:long*) block_params [line 28, column 3]\n " shape="box"] +"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" [label="4: Call _fun__dispatch_once \n n$4=_fun__dispatch_once(&#GB$DispatchA.sharedInstance.once:long*,(_fun_objc_blockDispatchA.sharedInstance_1):_fn_(*)) [line 28, column 3]\n " shape="box"] "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" -> "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot b/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot index 497c3143e..30e3c5ac3 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/dispatch_examples.m.dot @@ -101,7 +101,7 @@ digraph cfg { "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_3" -> "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_2" ; -"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" [label="4: Call _fun_dispatch_after \n n$16=_fun_dispatch_time(0:unsigned long long,((unsigned long long)2 * 1000000000):long long) [line 46, column 18]\n n$17=_fun_dispatch_get_main_queue() [line 47, column 18]\n n$21=_fun_dispatch_after[objc_blockDispatchEx.dispatch_after_example_3](n$16:unsigned long long,n$17:NSObject*) block_params [line 46, column 3]\n " shape="box"] +"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" [label="4: Call _fun_dispatch_after \n n$16=_fun_dispatch_time(0:unsigned long long,((unsigned long long)2 * 1000000000):long long) [line 46, column 18]\n n$17=_fun_dispatch_get_main_queue() [line 47, column 18]\n n$21=_fun_dispatch_after(n$16:unsigned long long,n$17:NSObject*,(_fun_objc_blockDispatchEx.dispatch_after_example_3):_fn_(*)) [line 46, column 3]\n " shape="box"] "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" -> "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_3" ; @@ -120,7 +120,7 @@ digraph cfg { "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_3" -> "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_2" ; -"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" [label="4: Call _fun_dispatch_async \n n$9=_fun_dispatch_get_global_queue(0:long,(unsigned long)0:unsigned long) [line 36, column 18]\n n$13=_fun_dispatch_async[objc_blockDispatchEx.dispatch_async_example_2](n$9:NSObject*) block_params [line 36, column 3]\n " shape="box"] +"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" [label="4: Call _fun_dispatch_async \n n$9=_fun_dispatch_get_global_queue(0:long,(unsigned long)0:unsigned long) [line 36, column 18]\n n$13=_fun_dispatch_async(n$9:NSObject*,(_fun_objc_blockDispatchEx.dispatch_async_example_2):_fn_(*)) [line 36, column 3]\n " shape="box"] "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" -> "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_3" ; @@ -139,7 +139,7 @@ digraph cfg { "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_3" -> "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_2" ; -"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" [label="4: Call _fun_dispatch_barrier_async \n n$38=_fun_dispatch_get_main_queue() [line 75, column 26]\n n$42=_fun_dispatch_barrier_async[objc_blockDispatchEx.dispatch_barrier_example_6](n$38:NSObject*) block_params [line 75, column 3]\n " shape="box"] +"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" [label="4: Call _fun_dispatch_barrier_async \n n$38=_fun_dispatch_get_main_queue() [line 75, column 26]\n n$42=_fun_dispatch_barrier_async(n$38:NSObject*,(_fun_objc_blockDispatchEx.dispatch_barrier_example_6):_fn_(*)) [line 75, column 3]\n " shape="box"] "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" -> "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_3" ; @@ -158,7 +158,7 @@ digraph cfg { "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_3" -> "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_2" ; -"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" [label="4: Call _fun_dispatch_group_async \n n$24=_fun_dispatch_get_main_queue() [line 57, column 30]\n n$28=_fun_dispatch_group_async[objc_blockDispatchEx.dispatch_group_example_4](n$24:NSObject*,null:NSObject*) block_params [line 57, column 3]\n " shape="box"] +"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" [label="4: Call _fun_dispatch_group_async \n n$24=_fun_dispatch_get_main_queue() [line 57, column 30]\n n$28=_fun_dispatch_group_async(null:NSObject*,n$24:NSObject*,(_fun_objc_blockDispatchEx.dispatch_group_example_4):_fn_(*)) [line 57, column 3]\n " shape="box"] "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" -> "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_3" ; @@ -177,7 +177,7 @@ digraph cfg { "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_3" -> "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_2" ; -"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" [label="4: Call _fun_dispatch_group_async \n n$31=_fun_dispatch_get_main_queue() [line 66, column 30]\n n$35=_fun_dispatch_group_async[objc_blockDispatchEx.dispatch_group_notify_example_5](n$31:NSObject*,null:NSObject*) block_params [line 66, column 3]\n " shape="box"] +"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" [label="4: Call _fun_dispatch_group_async \n n$31=_fun_dispatch_get_main_queue() [line 66, column 30]\n n$35=_fun_dispatch_group_async(null:NSObject*,n$31:NSObject*,(_fun_objc_blockDispatchEx.dispatch_group_notify_example_5):_fn_(*)) [line 66, column 3]\n " shape="box"] "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" -> "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_3" ; @@ -196,7 +196,7 @@ digraph cfg { "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_3" -> "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_2" ; -"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" [label="4: Call _fun__dispatch_once \n n$6=_fun__dispatch_once[objc_blockDispatchEx.dispatch_once_example_1](&#GB$DispatchEx.dispatch_once_example.onceToken:long*) block_params [line 27, column 3]\n " shape="box"] +"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" [label="4: Call _fun__dispatch_once \n n$6=_fun__dispatch_once(&#GB$DispatchEx.dispatch_once_example.onceToken:long*,(_fun_objc_blockDispatchEx.dispatch_once_example_1):_fn_(*)) [line 27, column 3]\n " shape="box"] "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" -> "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot b/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot index e655ae81d..00ba26638 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/dispatch_in_macro.m.dot @@ -11,7 +11,7 @@ digraph cfg { "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_3" -> "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_5" ; -"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" [label="4: Call _fun__dispatch_once \n n$3=_fun__dispatch_once[objc_blockDispatchInMacroTest_1](&#GB$DispatchInMacroTest.once_token:long*) block_params [line 21, column 10]\n " shape="box"] +"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" [label="4: Call _fun__dispatch_once \n n$3=_fun__dispatch_once(&#GB$DispatchInMacroTest.once_token:long*,(_fun_objc_blockDispatchInMacroTest_1):_fn_(*)) [line 21, column 10]\n " shape="box"] "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" -> "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_3" ; diff --git a/infer/tests/codetoanalyze/objcpp/biabduction/issues.exp b/infer/tests/codetoanalyze/objcpp/biabduction/issues.exp index f0dfb1783..359f8b131 100644 --- a/infer/tests/codetoanalyze/objcpp/biabduction/issues.exp +++ b/infer/tests/codetoanalyze/objcpp/biabduction/issues.exp @@ -1,6 +1,5 @@ -codetoanalyze/objcpp/biabduction/BlockLfield.mm, A.mOk, 1, PRECONDITION_NOT_FOUND, no_bucket, ERROR, [start of procedure mOk] codetoanalyze/objcpp/biabduction/BlockLfield.mm, CFunWithBlockOk, 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure CFunWithBlockOk()] -codetoanalyze/objcpp/biabduction/BlockLfield.mm, CFunWithBlockOk_objc_blockA.mOk_1, 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure CFunWithBlockOk()] -codetoanalyze/objcpp/biabduction/c_functions.mm, main, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure main(),start of procedure autoUpdating,return from a call to Functions.autoUpdating,start of procedure autoUpdating2,Skipping dispatch_once2(): method has no implementation,return from a call to Functions.autoUpdating2,start of procedure block,return from a call to Functions.block,start of procedure block,return from a call to objc_blockobjc_blockFunctions.autoUpdating_1_2,Message block with receiver nil returns nil.] +codetoanalyze/objcpp/biabduction/BlockLfield.mm, CFunWithBlockOk[objc_blockA.mOk_1], 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure CFunWithBlockOk()] +codetoanalyze/objcpp/biabduction/c_functions.mm, main, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure main(),start of procedure autoUpdating,start of procedure block,start of procedure setBlock:,return from a call to Functions.setBlock:,return from a call to objc_blockFunctions.autoUpdating_1,return from a call to Functions.autoUpdating,start of procedure autoUpdating2,return from a call to Functions.autoUpdating2,start of procedure block,return from a call to Functions.block,start of procedure block,return from a call to objc_blockobjc_blockFunctions.autoUpdating_1_2,Message block with receiver nil returns nil.] codetoanalyze/objcpp/biabduction/retain_cycles/RetainCycleWithStruct.mm, Animation.tracer, 2, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure tracer,start of procedure _State,return from a call to _State::_State,start of procedure initWithAnimation:,Taking true branch,return from a call to Tracer.initWithAnimation:] codetoanalyze/objcpp/biabduction/retain_cycles/RetainCycleWithStruct.mm, Animation.tracer, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure tracer,start of procedure _State,return from a call to _State::_State,start of procedure initWithAnimation:,Taking true branch,return from a call to Tracer.initWithAnimation:]