From 87a3d693e1f24aa8851ae6bb8e52e5523d41999b Mon Sep 17 00:00:00 2001 From: Dulma Rodriguez Date: Wed, 18 Nov 2015 03:16:14 -0800 Subject: [PATCH] Adding static variables to blocks class to get retain cycles Summary: public The static and global variables used in blocks don't appear in the ast as captured. We need them however to try and find retain cycles involving those variables. This diff adds a way of collecting the static variables used in blocks and treat them like we treat other captured variables to find retain cycles. Reviewed By: ddino Differential Revision: D2663727 fb-gh-sync-id: d5b44ec --- infer/src/clang/cContext.ml | 32 +++++++-- infer/src/clang/cContext.mli | 6 +- infer/src/clang/cFrontend.ml | 2 +- infer/src/clang/cMethod_trans.ml | 6 +- infer/src/clang/cMethod_trans.mli | 2 +- infer/src/clang/cModule_type.ml | 2 +- infer/src/clang/cTrans.ml | 48 +++++--------- infer/src/clang/cVar_decl.ml | 2 +- infer/src/clang/cVar_decl.mli | 2 +- .../RetainCycleStaticVar.m | 49 ++++++++++++++ .../objc/frontend/block/block.dot | 14 ++-- .../objc/frontend/block/block_no_args.dot | 2 +- .../objc/frontend/block/dispatch.dot | 14 ++-- .../objc/frontend/block/dispatch_examples.dot | 52 +++++++-------- .../objc/frontend/block/static.dot | 20 +++--- .../objc/RetainCycleStaticVarTest.java | 65 +++++++++++++++++++ 16 files changed, 221 insertions(+), 97 deletions(-) create mode 100644 infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleStaticVar.m create mode 100644 infer/tests/endtoend/objc/RetainCycleStaticVarTest.java diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index 0bc5801fd..69af97b94 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -33,7 +33,7 @@ type t = is_callee_expression : bool; namespace: string option; (* contains the name of the namespace if we are in the scope of one*) outer_context : t option; (* in case of objc blocks, the context of the method containing the block *) - mutable blocks : Procname.t list (* List of blocks defined in this method *) + mutable blocks_static_vars : ((Sil.pvar * Sil.typ) list) Procname.Map.t; } let create_context tenv cg cfg procdesc ns curr_class is_objc_method context_opt = @@ -46,7 +46,7 @@ let create_context tenv cg cfg procdesc ns curr_class is_objc_method context_opt is_objc_method = is_objc_method; namespace = ns; outer_context = context_opt; - blocks = [] + blocks_static_vars = Procname.Map.empty } let get_cfg context = context.cfg @@ -128,11 +128,29 @@ let create_curr_class tenv class_name = | [] -> ContextCls (class_name, None, [])) | _ -> assert false -let rec add_block context block = - context.blocks <- block :: context.blocks; - match context.outer_context with - | Some outer_context -> add_block outer_context block - | None -> () +let add_block_static_var context block_name static_var_typ = + match context.outer_context, static_var_typ with + | Some outer_context, (static_var, typ) when Sil.pvar_is_global static_var -> + (let new_static_vars, duplicate = + try + let static_vars = Procname.Map.find block_name outer_context.blocks_static_vars in + if IList.mem ( + fun (var1, typ1) (var2, typ2) -> Sil.pvar_equal var1 var2 + ) static_var_typ static_vars then + static_vars, true + else + static_var_typ :: static_vars, false + with Not_found -> [static_var_typ], false in + if not duplicate then + let blocks_static_vars = + Procname.Map.add block_name new_static_vars outer_context.blocks_static_vars in + outer_context.blocks_static_vars <- blocks_static_vars) + | _ -> () + +let static_vars_for_block context block_name = + try Procname.Map.find block_name context.blocks_static_vars + with Not_found -> [] + let rec get_outer_procname context = match context.outer_context with diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index 3a5e417a5..1a61b4f9d 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -28,7 +28,7 @@ type t = is_callee_expression : bool; namespace: string option; (* contains the name of the namespace if we are in the scope of one*) outer_context : t option; (* in case of objc blocks, the context of the method containing the block *) - mutable blocks: Procname.t list; (* List of blocks defined in this method *) + mutable blocks_static_vars : ((Sil.pvar * Sil.typ) list) Procname.Map.t; } val get_procdesc : t -> Cfg.Procdesc.t @@ -58,7 +58,9 @@ val create_context : Sil.tenv -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t -> val create_curr_class : Sil.tenv -> string -> curr_class -val add_block : t -> Procname.t -> unit +val add_block_static_var : t -> Procname.t -> (Sil.pvar * Sil.typ) -> unit + +val static_vars_for_block : t -> Procname.t -> (Sil.pvar * Sil.typ) list val is_objc_instance : t -> bool diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index 50f130149..5f6560f70 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -147,7 +147,7 @@ let do_source_file source_file ast = Cg.store_to_file cg_file call_graph; Cfg.store_cfg_to_file cfg_file true cfg; (*Logging.out "Tenv %a@." Sil.pp_tenv tenv;*) - (*Printing.print_tenv tenv;*) + (* Printing.print_tenv tenv; *) (*Printing.print_procedures cfg; *) Sil.store_tenv_to_file tenv_file tenv; if !CFrontend_config.stats_mode then Cfg.check_cfg_connectedness cfg; diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index da4ebe630..056c5099c 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -252,7 +252,9 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method = let is_generated = CMethod_signature.ms_is_generated ms in let create_new_procdesc () = let formals = get_formal_parameters tenv ms in - let captured_str = IList.map (fun (s, t, _) -> (Mangled.to_string s, t)) captured in + let captured_str = IList.map ( + fun (var, t) -> (Mangled.to_string (Sil.pvar_get_name var), t) + ) captured in (* Captured variables for blocks are treated as parameters *) let formals = captured_str @formals in let source_range = CMethod_signature.ms_get_loc ms in @@ -260,7 +262,7 @@ let create_local_procdesc cfg tenv ms fbody captured is_objc_inst_method = let loc_start = CLocation.get_sil_location_from_range source_range true in let loc_exit = CLocation.get_sil_location_from_range source_range false in let ret_type = get_return_type tenv ms in - let captured' = IList.map (fun (s, t, _) -> (s, t)) captured in + let captured' = IList.map (fun (var, t) -> (Sil.pvar_get_name var, t)) captured in let procdesc = let proc_attributes = { (ProcAttributes.default proc_name Config.C_CPP) with diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index db48cfb33..d02e829f0 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -21,7 +21,7 @@ type method_call_type = | MCStatic val create_local_procdesc : Cfg.cfg -> Sil.tenv -> CMethod_signature.method_signature -> - Clang_ast_t.stmt list -> (Mangled.t * Sil.typ * bool) list -> bool -> bool + Clang_ast_t.stmt list -> (Sil.pvar * Sil.typ) list -> bool -> bool val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.typ list) option -> unit diff --git a/infer/src/clang/cModule_type.ml b/infer/src/clang/cModule_type.ml index de4ac331e..14604104b 100644 --- a/infer/src/clang/cModule_type.ml +++ b/infer/src/clang/cModule_type.ml @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. *) -type block_data = CContext.t * Clang_ast_t.type_ptr * Procname.t * (Mangled.t * Sil.typ * bool) list +type block_data = CContext.t * Clang_ast_t.type_ptr * Procname.t * (Sil.pvar * Sil.typ) list type instr_type = [ | `ClangStmt of Clang_ast_t.stmt diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index cfb75d30c..4bd8e7727 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -94,7 +94,8 @@ struct let tenv = trans_state.context.CContext.tenv in let procdesc = trans_state.context.CContext.procdesc in let procname = Cfg.Procdesc.get_proc_name procdesc in - let mk_field_from_captured_var (vname, typ, b) = + let mk_field_from_captured_var (var, typ) = + let vname = Sil.pvar_get_name var in let qual_name = Ast_utils.make_qual_name_decl block_name (Mangled.to_string vname) in let fname = General_utils.mk_class_field_name qual_name in let item_annot = Sil.item_annotation_empty in @@ -105,8 +106,8 @@ struct IList.iter (fun (fn, ft, _) -> Printing.log_out "-----> field: '%s'\n" (Ident.fieldname_to_string fn)) fields; let mblock = Mangled.from_string block_name in - let block_type = Sil.Tstruct(fields, [], Sil.Class, Some mblock, [], [], []) in - let block_name = Sil.TN_csu(Sil.Class, mblock) in + let block_type = Sil.Tstruct (fields, [], Sil.Class, Some mblock, [], [], []) in + let block_name = Sil.TN_csu (Sil.Class, mblock) in Sil.tenv_add tenv block_name block_type; let trans_res = CTrans_utils.alloc_trans trans_state loc (Ast_expressions.dummy_stmt_info ()) block_type true in let id_block = match trans_res.exps with @@ -114,23 +115,23 @@ struct | _ -> assert false in let block_var = Sil.mk_pvar mblock procname in let declare_block_local = - Sil.Declare_locals([(block_var, Sil.Tptr(block_type, Sil.Pk_pointer))], loc) in + Sil.Declare_locals ([(block_var, Sil.Tptr (block_type, Sil.Pk_pointer))], loc) in (* Adds Nullify of the temp block variable in the predecessors of the exit node. *) let pred_exit = Cfg.Node.get_preds (Cfg.Procdesc.get_exit_node procdesc) in let block_nullify_instr = if pred_exit = [] then - [Sil.Nullify(block_var, loc, true)] + [Sil.Nullify (block_var, loc, true)] else (IList.iter (fun n -> let loc = Cfg.Node.get_loc n in Cfg.Node.append_instrs_temps n [Sil.Nullify(block_var, loc, true)] []) pred_exit; []) in - let set_instr = Sil.Set(Sil.Lvar block_var, block_type, Sil.Var id_block, loc) in - let ids, captured_instrs = IList.split (IList.map (fun (vname, typ, _) -> - let id = Ident.create_fresh Ident.knormal in - id, Sil.Letderef(id, Sil.Lvar (Sil.mk_pvar vname procname), typ, loc) - ) captured_vars) in + let set_instr = Sil.Set (Sil.Lvar block_var, block_type, Sil.Var id_block, loc) in + let create_field_exp (var, typ) = + let id = Ident.create_fresh Ident.knormal in + id, Sil.Letderef (id, Sil.Lvar var, typ, loc) in + let ids, captured_instrs = IList.split (IList.map create_field_exp captured_vars) in let fields_ids = IList.combine fields ids in let set_fields = IList.map (fun ((f, t, _), id) -> - Sil.Set(Sil.Lfield(Sil.Var id_block, f, block_type), t, Sil.Var id, loc)) fields_ids in + Sil.Set (Sil.Lfield (Sil.Var id_block, f, block_type), t, Sil.Var id, loc)) fields_ids in (declare_block_local :: trans_res.instrs) @ [set_instr] @ captured_instrs @ set_fields @ block_nullify_instr, id_block :: ids @@ -336,6 +337,7 @@ struct let pln = trans_state.parent_line_number in let sil_loc = CLocation.get_sil_location stmt_info pln context in let pvar = CVar_decl.sil_var_of_decl_ref context decl_ref procname in + CContext.add_block_static_var context procname (pvar, typ); let e = Sil.Lvar pvar in let exps = if Self.is_var_self pvar (CContext.is_objc_method context) then let curr_class = CContext.get_curr_class context in @@ -1874,25 +1876,10 @@ struct let loc = (match stmt_info.Clang_ast_t.si_source_range with (l1, l2) -> CLocation.clang_to_sil_location l1 pln (Some context.CContext.procdesc)) in - (* Given a mangled name (possibly full) returns a plain mangled name *) - let ensure_plain_mangling m = - Mangled.from_string (Mangled.to_string m) in (* Given a captured var, return the instruction to assign it to a temp *) - let assign_captured_var cv = - let cvar, typ = (match cv with - | (cvar, typ, false) -> cvar, typ - | (cvar, typ, true) -> (* static case *) - let formals = Cfg.Procdesc.get_formals context.CContext.procdesc in - let cvar' = ensure_plain_mangling cvar in - (* we check if cvar' is a formal. In that case we need this plain mangled name *) - (* otherwise it's a static variable defined among the locals *) - (* and therefore we need the full mangled name *) - let cvar''= - if (IList.exists(fun (s, t) -> Mangled.from_string s = cvar') formals) then cvar' - else cvar in - (cvar'', typ)) in + let assign_captured_var (cvar, typ) = let id = Ident.create_fresh Ident.knormal in - let instr = Sil.Letderef (id, Sil.Lvar (Sil.mk_pvar cvar procname), typ, loc) in + let instr = Sil.Letderef (id, (Sil.Lvar cvar), typ, loc) in (id, instr) in match decl with | Clang_ast_t.BlockDecl (decl_info, block_decl_info) -> @@ -1908,14 +1895,15 @@ struct let ids_instrs = IList.map assign_captured_var captured_vars in let ids, instrs = IList.split ids_instrs in let block_data = (context, type_ptr, block_pname, captured_vars) in - CContext.add_block context block_pname; M.function_decl context.tenv context.cfg context.cg context.namespace decl (Some block_data); Cfg.set_procname_priority context.cfg block_pname; let captured_exps = IList.map (fun id -> Sil.Var id) ids in let tu = Sil.Ctuple ((Sil.Const (Sil.Cfun block_pname)) :: captured_exps) in let block_name = Procname.to_string block_pname in + let static_vars = CContext.static_vars_for_block context block_pname in + let captured_static_vars = captured_vars @ static_vars in let alloc_block_instr, ids_block = - allocate_block trans_state block_name captured_vars loc in + allocate_block trans_state block_name captured_static_vars loc in { empty_res_trans with ids = ids_block @ ids; instrs = alloc_block_instr @ instrs; exps = [(Sil.Const tu, typ)]} | _ -> assert false diff --git a/infer/src/clang/cVar_decl.ml b/infer/src/clang/cVar_decl.ml index 9bb33c2d5..5ad620bd3 100644 --- a/infer/src/clang/cVar_decl.ml +++ b/infer/src/clang/cVar_decl.ml @@ -104,7 +104,7 @@ let captured_vars_from_block_info context cvl = else let pvar = sil_var_of_decl_ref context dr procname in let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv type_ptr in - (Sil.pvar_get_name pvar, typ, false) :: vars + (pvar, typ) :: vars | _ -> assert false) | _ -> assert false in IList.fold_right sil_var_of_captured_var cvl [] diff --git a/infer/src/clang/cVar_decl.mli b/infer/src/clang/cVar_decl.mli index b4ad0782f..c6986644e 100644 --- a/infer/src/clang/cVar_decl.mli +++ b/infer/src/clang/cVar_decl.mli @@ -19,4 +19,4 @@ val add_var_to_locals : Cfg.Procdesc.t -> Clang_ast_t.decl -> Sil.typ -> Sil.pva val compute_autorelease_pool_vars : CContext.t -> Clang_ast_t.stmt list -> (Sil.exp * Sil.typ) list val captured_vars_from_block_info : CContext.t -> Clang_ast_t.block_captured_variable list -> - (Mangled.t * Sil.typ * bool) list + (Sil.pvar * Sil.typ) list diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleStaticVar.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleStaticVar.m new file mode 100644 index 000000000..350ad5ed4 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleStaticVar.m @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2015 - present Facebook, Inc. +* All rights reserved. +* +* This source code is licensed under the BSD style license found in the +* LICENSE file in the root directory of this source tree. An additional grant +* of patent rights can be found in the PATENTS file in the same directory. +*/ + +#import + +typedef void (^MyHandler) (NSString *name); + +@interface C : NSObject + +@property (nonatomic, strong) MyHandler handler; + +@property (nonatomic, strong) NSString *name; +@property (nonatomic,strong) C *bla1; +@property (nonatomic,strong) C *bla2; +@end + +@implementation C + +- (void) foo { + static dispatch_once_t once; + static C* sharedInstance1; + dispatch_once(&once, ^{ + sharedInstance1 = [[C alloc] init]; + }); + static C* sharedInstance2; + dispatch_once(&once, ^{ + sharedInstance2 = [[C alloc] init]; + }); + + _bla1 = sharedInstance1; + _bla2 = sharedInstance2; + sharedInstance2.handler = ^(NSString* s){ + _name = sharedInstance2.name; + }; +} + +@end + +int main() { + C *c = [[C alloc] init]; + [c foo]; + return 0; +} diff --git a/infer/tests/codetoanalyze/objc/frontend/block/block.dot b/infer/tests/codetoanalyze/objc/frontend/block/block.dot index 859a3b24f..2d26b749d 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/block.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/block.dot @@ -18,7 +18,7 @@ digraph iCFG { 21 -> 20 ; -20 [label="20: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_main1______2); [line 19]\n n$25=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_main1______2 ):unsigned long ) [line 19]\n *&__objc_anonymous_block_main1______2:class __objc_anonymous_block_main1______2 =n$25 [line 19]\n n$26=*&x:int [line 19]\n *n$25.x:int =n$26 [line 19]\n n$10=*&x:int [line 19]\n *&addblock:_fn_ (*)=(_fun___objc_anonymous_block_main1______2,n$10) [line 19]\n REMOVE_TEMPS(n$25,n$26,n$10); [line 19]\n " shape="box"] +20 [label="20: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_main1______2); [line 19]\n n$27=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_main1______2 ):unsigned long ) [line 19]\n *&__objc_anonymous_block_main1______2:class __objc_anonymous_block_main1______2 =n$27 [line 19]\n n$28=*&x:int [line 19]\n *n$27.x:int =n$28 [line 19]\n n$11=*&x:int [line 19]\n *&addblock:_fn_ (*)=(_fun___objc_anonymous_block_main1______2,n$11) [line 19]\n REMOVE_TEMPS(n$27,n$28,n$11); [line 19]\n " shape="box"] 20 -> 10 ; @@ -26,11 +26,11 @@ digraph iCFG { 19 -> 18 ; -18 [label="18: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block___objc_anonymous_block_main1______2______3); [line 25]\n n$22=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block___objc_anonymous_block_main1______2______3 ):unsigned long ) [line 25]\n *&__objc_anonymous_block___objc_anonymous_block_main1______2______3:class __objc_anonymous_block___objc_anonymous_block_main1______2______3 =n$22 [line 25]\n n$23=*&x:int [line 25]\n n$24=*&bla:int [line 25]\n *n$22.bla:int =n$23 [line 25]\n *n$22.x:int =n$24 [line 25]\n n$16=*&x:int [line 25]\n n$17=*&bla:int [line 25]\n *&addblock2:_fn_ (*)=(_fun___objc_anonymous_block___objc_anonymous_block_main1______2______3,n$16,n$17) [line 25]\n REMOVE_TEMPS(n$22,n$23,n$24,n$16,n$17); [line 25]\n " shape="box"] +18 [label="18: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block___objc_anonymous_block_main1______2______3); [line 25]\n n$23=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block___objc_anonymous_block_main1______2______3 ):unsigned long ) [line 25]\n *&__objc_anonymous_block___objc_anonymous_block_main1______2______3:class __objc_anonymous_block___objc_anonymous_block_main1______2______3 =n$23 [line 25]\n n$24=*&x:int [line 25]\n n$25=*&bla:int [line 25]\n n$26=*&#GB$main1_s:int [line 25]\n *n$23.bla:int =n$24 [line 25]\n *n$23.main1_s:int =n$25 [line 25]\n *n$23.x:int =n$26 [line 25]\n n$17=*&x:int [line 25]\n n$18=*&bla:int [line 25]\n *&addblock2:_fn_ (*)=(_fun___objc_anonymous_block___objc_anonymous_block_main1______2______3,n$17,n$18) [line 25]\n REMOVE_TEMPS(n$23,n$24,n$25,n$26,n$17,n$18); [line 25]\n " shape="box"] 18 -> 14 ; -17 [label="17: Return Stmt \n n$18=*&z:int [line 26]\n n$19=*&#GB$main1_s:int [line 26]\n n$20=*&x:int [line 26]\n n$21=*&bla:int [line 26]\n *&return:int =(((n$18 + n$19) + n$20) + n$21) [line 26]\n REMOVE_TEMPS(n$18,n$19,n$20,n$21); [line 26]\n NULLIFY(&z,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] +17 [label="17: Return Stmt \n n$19=*&z:int [line 26]\n n$20=*&#GB$main1_s:int [line 26]\n n$21=*&x:int [line 26]\n n$22=*&bla:int [line 26]\n *&return:int =(((n$19 + n$20) + n$21) + n$22) [line 26]\n REMOVE_TEMPS(n$19,n$20,n$21,n$22); [line 26]\n NULLIFY(&z,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] 17 -> 16 ; @@ -41,11 +41,11 @@ digraph iCFG { 15 -> 17 ; -14 [label="14: BinaryOperatorStmt: Assign \n n$14=*&addblock2:_fn_ (*) [line 29]\n n$15=n$14(1:int ) [line 29]\n *&add2:int =n$15 [line 29]\n REMOVE_TEMPS(n$14,n$15); [line 29]\n NULLIFY(&addblock2,false); [line 29]\n " shape="box"] +14 [label="14: BinaryOperatorStmt: Assign \n n$15=*&addblock2:_fn_ (*) [line 29]\n n$16=n$15(1:int ) [line 29]\n *&add2:int =n$16 [line 29]\n REMOVE_TEMPS(n$15,n$16); [line 29]\n NULLIFY(&addblock2,false); [line 29]\n " shape="box"] 14 -> 13 ; -13 [label="13: Return Stmt \n n$11=*&c:int [line 30]\n n$12=*&add2:int [line 30]\n n$13=*&bla:int [line 30]\n *&return:int =((n$11 + n$12) + n$13) [line 30]\n REMOVE_TEMPS(n$11,n$12,n$13); [line 30]\n NULLIFY(&__objc_anonymous_block___objc_anonymous_block_main1______2______3,true); [line 30]\n NULLIFY(&add2,false); [line 30]\n NULLIFY(&c,false); [line 30]\n APPLY_ABSTRACTION; [line 30]\n " shape="box"] +13 [label="13: Return Stmt \n n$12=*&c:int [line 30]\n n$13=*&add2:int [line 30]\n n$14=*&bla:int [line 30]\n *&return:int =((n$12 + n$13) + n$14) [line 30]\n REMOVE_TEMPS(n$12,n$13,n$14); [line 30]\n NULLIFY(&__objc_anonymous_block___objc_anonymous_block_main1______2______3,true); [line 30]\n NULLIFY(&add2,false); [line 30]\n NULLIFY(&c,false); [line 30]\n APPLY_ABSTRACTION; [line 30]\n " shape="box"] 13 -> 12 ; @@ -56,11 +56,11 @@ digraph iCFG { 11 -> 19 ; -10 [label="10: BinaryOperatorStmt: Assign \n n$8=*&addblock:_fn_ (*) [line 33]\n n$9=n$8(1:int ,2:int ) [line 33]\n *&add1:int =n$9 [line 33]\n REMOVE_TEMPS(n$8,n$9); [line 33]\n NULLIFY(&addblock,false); [line 33]\n " shape="box"] +10 [label="10: BinaryOperatorStmt: Assign \n n$9=*&addblock:_fn_ (*) [line 33]\n n$10=n$9(1:int ,2:int ) [line 33]\n *&add1:int =n$10 [line 33]\n REMOVE_TEMPS(n$9,n$10); [line 33]\n NULLIFY(&addblock,false); [line 33]\n " shape="box"] 10 -> 9 ; -9 [label="9: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_main1______1); [line 36]\n n$7=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_main1______1 ):unsigned long ) [line 36]\n *&__objc_anonymous_block_main1______1:class __objc_anonymous_block_main1______1 =n$7 [line 36]\n *&addblock:_fn_ (*)=(_fun___objc_anonymous_block_main1______1) [line 36]\n REMOVE_TEMPS(n$7); [line 36]\n " shape="box"] +9 [label="9: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_main1______1); [line 36]\n n$7=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_main1______1 ):unsigned long ) [line 36]\n *&__objc_anonymous_block_main1______1:class __objc_anonymous_block_main1______1 =n$7 [line 36]\n n$8=*&#GB$main1_s:int [line 36]\n *n$7.main1_s:int =n$8 [line 36]\n *&addblock:_fn_ (*)=(_fun___objc_anonymous_block_main1______1) [line 36]\n REMOVE_TEMPS(n$7,n$8); [line 36]\n " shape="box"] 9 -> 5 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot index a7c997894..fce6fe554 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot @@ -7,7 +7,7 @@ digraph iCFG { 15 -> 14 ; -14 [label="14: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_My_manager_m______1); [line 26]\n n$7=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_My_manager_m______1 ):unsigned long ) [line 26]\n *&__objc_anonymous_block_My_manager_m______1:class __objc_anonymous_block_My_manager_m______1 =n$7 [line 26]\n n$8=*&z:int [line 26]\n *n$7.z:int =n$8 [line 26]\n n$5=*&z:int [line 26]\n *&b:_fn_ (*)=(_fun___objc_anonymous_block_My_manager_m______1,n$5) [line 26]\n REMOVE_TEMPS(n$7,n$8,n$5); [line 26]\n " shape="box"] +14 [label="14: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_My_manager_m______1); [line 26]\n n$7=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_My_manager_m______1 ):unsigned long ) [line 26]\n *&__objc_anonymous_block_My_manager_m______1:class __objc_anonymous_block_My_manager_m______1 =n$7 [line 26]\n n$8=*&z:int [line 26]\n n$9=*&#GB$g:int [line 26]\n *n$7.g:int =n$8 [line 26]\n *n$7.z:int =n$9 [line 26]\n n$5=*&z:int [line 26]\n *&b:_fn_ (*)=(_fun___objc_anonymous_block_My_manager_m______1,n$5) [line 26]\n REMOVE_TEMPS(n$7,n$8,n$9,n$5); [line 26]\n " shape="box"] 14 -> 10 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot b/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot index fb4e00397..3ba58851d 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/dispatch.dot @@ -39,7 +39,7 @@ digraph iCFG { 23 -> 32 ; -22 [label="22: BinaryOperatorStmt: Assign \n n$15=*&self:class A * [line 14]\n n$16=*&x:int [line 14]\n *n$15._x:int =n$16 [line 14]\n REMOVE_TEMPS(n$15,n$16); [line 14]\n NULLIFY(&self,false); [line 14]\n NULLIFY(&x,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] +22 [label="22: BinaryOperatorStmt: Assign \n n$17=*&self:class A * [line 14]\n n$18=*&x:int [line 14]\n *n$17._x:int =n$18 [line 14]\n REMOVE_TEMPS(n$17,n$18); [line 14]\n NULLIFY(&self,false); [line 14]\n NULLIFY(&x,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] 22 -> 21 ; @@ -50,7 +50,7 @@ digraph iCFG { 20 -> 22 ; -19 [label="19: Return Stmt \n n$13=*&self:class A * [line 14]\n n$14=*n$13._x:int [line 14]\n *&return:int =n$14 [line 14]\n REMOVE_TEMPS(n$13,n$14); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] +19 [label="19: Return Stmt \n n$15=*&self:class A * [line 14]\n n$16=*n$15._x:int [line 14]\n *&return:int =n$16 [line 14]\n REMOVE_TEMPS(n$15,n$16); [line 14]\n NULLIFY(&self,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] 19 -> 18 ; @@ -61,7 +61,7 @@ digraph iCFG { 17 -> 19 ; -16 [label="16: BinaryOperatorStmt: Assign \n n$11=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 37]\n n$9=_fun_A_init(n$11:class A *) virtual [line 37]\n *&#GB$A_trans_sharedInstance:struct objc_object *=n$9 [line 37]\n REMOVE_TEMPS(n$9,n$11); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"] +16 [label="16: BinaryOperatorStmt: Assign \n n$12=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 37]\n n$10=_fun_A_init(n$12:class A *) virtual [line 37]\n *&#GB$A_trans_sharedInstance:struct objc_object *=n$10 [line 37]\n REMOVE_TEMPS(n$10,n$12); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"] 16 -> 15 ; @@ -72,15 +72,15 @@ digraph iCFG { 14 -> 16 ; -13 [label="13: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_A_trans______2); [line 36]\n n$12=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_trans______2 ):unsigned long ) [line 36]\n *&__objc_anonymous_block_A_trans______2:class __objc_anonymous_block_A_trans______2 =n$12 [line 36]\n *&dummy_block:_fn_ (*)=(_fun___objc_anonymous_block_A_trans______2) [line 36]\n REMOVE_TEMPS(n$12); [line 36]\n " shape="box"] +13 [label="13: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_A_trans______2); [line 36]\n n$13=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_trans______2 ):unsigned long ) [line 36]\n *&__objc_anonymous_block_A_trans______2:class __objc_anonymous_block_A_trans______2 =n$13 [line 36]\n n$14=*&#GB$A_trans_sharedInstance:struct objc_object * [line 36]\n *n$13.A_trans_sharedInstance:struct objc_object *=n$14 [line 36]\n *&dummy_block:_fn_ (*)=(_fun___objc_anonymous_block_A_trans______2) [line 36]\n REMOVE_TEMPS(n$13,n$14); [line 36]\n " shape="box"] 13 -> 12 ; -12 [label="12: Call n$8 \n n$8=*&dummy_block:_fn_ (*) [line 39]\n n$8() [line 39]\n REMOVE_TEMPS(n$8); [line 39]\n NULLIFY(&dummy_block,false); [line 39]\n " shape="box"] +12 [label="12: Call n$9 \n n$9=*&dummy_block:_fn_ (*) [line 39]\n n$9() [line 39]\n REMOVE_TEMPS(n$9); [line 39]\n NULLIFY(&dummy_block,false); [line 39]\n " shape="box"] 12 -> 11 ; -11 [label="11: Return Stmt \n n$7=*&#GB$A_trans_sharedInstance:struct objc_object * [line 40]\n *&return:struct objc_object *=n$7 [line 40]\n REMOVE_TEMPS(n$7); [line 40]\n NULLIFY(&__objc_anonymous_block_A_trans______2,true); [line 40]\n APPLY_ABSTRACTION; [line 40]\n " shape="box"] +11 [label="11: Return Stmt \n n$8=*&#GB$A_trans_sharedInstance:struct objc_object * [line 40]\n *&return:struct objc_object *=n$8 [line 40]\n REMOVE_TEMPS(n$8); [line 40]\n NULLIFY(&__objc_anonymous_block_A_trans______2,true); [line 40]\n APPLY_ABSTRACTION; [line 40]\n " shape="box"] 11 -> 10 ; @@ -102,7 +102,7 @@ digraph iCFG { 6 -> 8 ; -5 [label="5: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_sharedInstance______1); [line 29]\n DECLARE_LOCALS(&__objc_anonymous_block_A_sharedInstance______1); [line 27]\n n$6=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_sharedInstance______1 ):unsigned long ) [line 27]\n *&__objc_anonymous_block_A_sharedInstance______1:class __objc_anonymous_block_A_sharedInstance______1 =n$6 [line 27]\n *&infer___objc_anonymous_block_A_sharedInstance______1:_fn_ (*)=(_fun___objc_anonymous_block_A_sharedInstance______1) [line 29]\n REMOVE_TEMPS(n$6); [line 29]\n " shape="box"] +5 [label="5: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_sharedInstance______1); [line 29]\n DECLARE_LOCALS(&__objc_anonymous_block_A_sharedInstance______1); [line 27]\n n$6=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_sharedInstance______1 ):unsigned long ) [line 27]\n *&__objc_anonymous_block_A_sharedInstance______1:class __objc_anonymous_block_A_sharedInstance______1 =n$6 [line 27]\n n$7=*&#GB$A_sharedInstance_sharedInstance:struct objc_object * [line 27]\n *n$6.A_sharedInstance_sharedInstance:struct objc_object *=n$7 [line 27]\n *&infer___objc_anonymous_block_A_sharedInstance______1:_fn_ (*)=(_fun___objc_anonymous_block_A_sharedInstance______1) [line 29]\n REMOVE_TEMPS(n$6,n$7); [line 29]\n " shape="box"] 5 -> 4 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot b/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot index 7a5934295..58230c385 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/dispatch_examples.dot @@ -3,11 +3,11 @@ digraph iCFG { 60 -> 55 ; -59 [label="59: BinaryOperatorStmt: Assign \n n$52=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 71]\n n$50=_fun_A_init(n$52:class A *) virtual [line 71]\n *&#GB$A_dispatch_barrier_example_a:class A *=n$50 [line 71]\n REMOVE_TEMPS(n$50,n$52); [line 71]\n " shape="box"] +59 [label="59: BinaryOperatorStmt: Assign \n n$57=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 71]\n n$55=_fun_A_init(n$57:class A *) virtual [line 71]\n *&#GB$A_dispatch_barrier_example_a:class A *=n$55 [line 71]\n REMOVE_TEMPS(n$55,n$57); [line 71]\n " shape="box"] 59 -> 58 ; -58 [label="58: BinaryOperatorStmt: Assign \n n$49=*&#GB$A_dispatch_barrier_example_a:class A * [line 72]\n *n$49.x:int =10 [line 72]\n REMOVE_TEMPS(n$49); [line 72]\n APPLY_ABSTRACTION; [line 72]\n " shape="box"] +58 [label="58: BinaryOperatorStmt: Assign \n n$54=*&#GB$A_dispatch_barrier_example_a:class A * [line 72]\n *n$54.x:int =10 [line 72]\n REMOVE_TEMPS(n$54); [line 72]\n APPLY_ABSTRACTION; [line 72]\n " shape="box"] 58 -> 57 ; @@ -18,15 +18,15 @@ digraph iCFG { 56 -> 59 ; -55 [label="55: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_barrier_example______6); [line 70]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_barrier_example______6); [line 70]\n n$53=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_barrier_example______6 ):unsigned long ) [line 70]\n *&__objc_anonymous_block_A_dispatch_barrier_example______6:class __objc_anonymous_block_A_dispatch_barrier_example______6 =n$53 [line 70]\n *&infer___objc_anonymous_block_A_dispatch_barrier_example______6:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_barrier_example______6) [line 70]\n REMOVE_TEMPS(n$53); [line 70]\n " shape="box"] +55 [label="55: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_barrier_example______6); [line 70]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_barrier_example______6); [line 70]\n n$58=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_barrier_example______6 ):unsigned long ) [line 70]\n *&__objc_anonymous_block_A_dispatch_barrier_example______6:class __objc_anonymous_block_A_dispatch_barrier_example______6 =n$58 [line 70]\n n$59=*&#GB$A_dispatch_barrier_example_a:class A * [line 70]\n *n$58.A_dispatch_barrier_example_a:class A *=n$59 [line 70]\n *&infer___objc_anonymous_block_A_dispatch_barrier_example______6:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_barrier_example______6) [line 70]\n REMOVE_TEMPS(n$58,n$59); [line 70]\n " shape="box"] 55 -> 54 ; -54 [label="54: Call n$47 \n n$47=*&infer___objc_anonymous_block_A_dispatch_barrier_example______6:_fn_ (*) [line 70]\n n$48=n$47() [line 70]\n REMOVE_TEMPS(n$47,n$48); [line 70]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_barrier_example______6,true); [line 70]\n " shape="box"] +54 [label="54: Call n$52 \n n$52=*&infer___objc_anonymous_block_A_dispatch_barrier_example______6:_fn_ (*) [line 70]\n n$53=n$52() [line 70]\n REMOVE_TEMPS(n$52,n$53); [line 70]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_barrier_example______6,true); [line 70]\n " shape="box"] 54 -> 53 ; -53 [label="53: Return Stmt \n n$45=*&#GB$A_dispatch_barrier_example_a:class A * [line 74]\n n$46=*n$45.x:int [line 74]\n *&return:int =n$46 [line 74]\n REMOVE_TEMPS(n$45,n$46); [line 74]\n NULLIFY(&__objc_anonymous_block_A_dispatch_barrier_example______6,true); [line 74]\n APPLY_ABSTRACTION; [line 74]\n " shape="box"] +53 [label="53: Return Stmt \n n$50=*&#GB$A_dispatch_barrier_example_a:class A * [line 74]\n n$51=*n$50.x:int [line 74]\n *&return:int =n$51 [line 74]\n REMOVE_TEMPS(n$50,n$51); [line 74]\n NULLIFY(&__objc_anonymous_block_A_dispatch_barrier_example______6,true); [line 74]\n APPLY_ABSTRACTION; [line 74]\n " shape="box"] 53 -> 52 ; @@ -41,11 +41,11 @@ digraph iCFG { 50 -> 45 ; -49 [label="49: BinaryOperatorStmt: Assign \n n$43=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 62]\n n$41=_fun_A_init(n$43:class A *) virtual [line 62]\n *&#GB$A_dispatch_group_notify_example_a:class A *=n$41 [line 62]\n REMOVE_TEMPS(n$41,n$43); [line 62]\n " shape="box"] +49 [label="49: BinaryOperatorStmt: Assign \n n$47=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 62]\n n$45=_fun_A_init(n$47:class A *) virtual [line 62]\n *&#GB$A_dispatch_group_notify_example_a:class A *=n$45 [line 62]\n REMOVE_TEMPS(n$45,n$47); [line 62]\n " shape="box"] 49 -> 48 ; -48 [label="48: BinaryOperatorStmt: Assign \n n$40=*&#GB$A_dispatch_group_notify_example_a:class A * [line 63]\n *n$40.x:int =10 [line 63]\n REMOVE_TEMPS(n$40); [line 63]\n APPLY_ABSTRACTION; [line 63]\n " shape="box"] +48 [label="48: BinaryOperatorStmt: Assign \n n$44=*&#GB$A_dispatch_group_notify_example_a:class A * [line 63]\n *n$44.x:int =10 [line 63]\n REMOVE_TEMPS(n$44); [line 63]\n APPLY_ABSTRACTION; [line 63]\n " shape="box"] 48 -> 47 ; @@ -56,15 +56,15 @@ digraph iCFG { 46 -> 49 ; -45 [label="45: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_group_notify_example______5); [line 61]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_group_notify_example______5); [line 61]\n n$44=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_group_notify_example______5 ):unsigned long ) [line 61]\n *&__objc_anonymous_block_A_dispatch_group_notify_example______5:class __objc_anonymous_block_A_dispatch_group_notify_example______5 =n$44 [line 61]\n *&infer___objc_anonymous_block_A_dispatch_group_notify_example______5:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_group_notify_example______5) [line 61]\n REMOVE_TEMPS(n$44); [line 61]\n " shape="box"] +45 [label="45: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_group_notify_example______5); [line 61]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_group_notify_example______5); [line 61]\n n$48=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_group_notify_example______5 ):unsigned long ) [line 61]\n *&__objc_anonymous_block_A_dispatch_group_notify_example______5:class __objc_anonymous_block_A_dispatch_group_notify_example______5 =n$48 [line 61]\n n$49=*&#GB$A_dispatch_group_notify_example_a:class A * [line 61]\n *n$48.A_dispatch_group_notify_example_a:class A *=n$49 [line 61]\n *&infer___objc_anonymous_block_A_dispatch_group_notify_example______5:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_group_notify_example______5) [line 61]\n REMOVE_TEMPS(n$48,n$49); [line 61]\n " shape="box"] 45 -> 44 ; -44 [label="44: Call n$38 \n n$38=*&infer___objc_anonymous_block_A_dispatch_group_notify_example______5:_fn_ (*) [line 61]\n n$39=n$38() [line 61]\n REMOVE_TEMPS(n$38,n$39); [line 61]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_group_notify_example______5,true); [line 61]\n " shape="box"] +44 [label="44: Call n$42 \n n$42=*&infer___objc_anonymous_block_A_dispatch_group_notify_example______5:_fn_ (*) [line 61]\n n$43=n$42() [line 61]\n REMOVE_TEMPS(n$42,n$43); [line 61]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_group_notify_example______5,true); [line 61]\n " shape="box"] 44 -> 43 ; -43 [label="43: Return Stmt \n n$36=*&#GB$A_dispatch_group_notify_example_a:class A * [line 65]\n n$37=*n$36.x:int [line 65]\n *&return:int =n$37 [line 65]\n REMOVE_TEMPS(n$36,n$37); [line 65]\n NULLIFY(&__objc_anonymous_block_A_dispatch_group_notify_example______5,true); [line 65]\n APPLY_ABSTRACTION; [line 65]\n " shape="box"] +43 [label="43: Return Stmt \n n$40=*&#GB$A_dispatch_group_notify_example_a:class A * [line 65]\n n$41=*n$40.x:int [line 65]\n *&return:int =n$41 [line 65]\n REMOVE_TEMPS(n$40,n$41); [line 65]\n NULLIFY(&__objc_anonymous_block_A_dispatch_group_notify_example______5,true); [line 65]\n APPLY_ABSTRACTION; [line 65]\n " shape="box"] 43 -> 42 ; @@ -79,11 +79,11 @@ digraph iCFG { 40 -> 35 ; -39 [label="39: BinaryOperatorStmt: Assign \n n$34=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 53]\n n$32=_fun_A_init(n$34:class A *) virtual [line 53]\n *&#GB$A_dispatch_group_example_a:class A *=n$32 [line 53]\n REMOVE_TEMPS(n$32,n$34); [line 53]\n " shape="box"] +39 [label="39: BinaryOperatorStmt: Assign \n n$37=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 53]\n n$35=_fun_A_init(n$37:class A *) virtual [line 53]\n *&#GB$A_dispatch_group_example_a:class A *=n$35 [line 53]\n REMOVE_TEMPS(n$35,n$37); [line 53]\n " shape="box"] 39 -> 38 ; -38 [label="38: BinaryOperatorStmt: Assign \n n$31=*&#GB$A_dispatch_group_example_a:class A * [line 54]\n *n$31.x:int =10 [line 54]\n REMOVE_TEMPS(n$31); [line 54]\n APPLY_ABSTRACTION; [line 54]\n " shape="box"] +38 [label="38: BinaryOperatorStmt: Assign \n n$34=*&#GB$A_dispatch_group_example_a:class A * [line 54]\n *n$34.x:int =10 [line 54]\n REMOVE_TEMPS(n$34); [line 54]\n APPLY_ABSTRACTION; [line 54]\n " shape="box"] 38 -> 37 ; @@ -94,15 +94,15 @@ digraph iCFG { 36 -> 39 ; -35 [label="35: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_group_example______4); [line 52]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_group_example______4); [line 52]\n n$35=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_group_example______4 ):unsigned long ) [line 52]\n *&__objc_anonymous_block_A_dispatch_group_example______4:class __objc_anonymous_block_A_dispatch_group_example______4 =n$35 [line 52]\n *&infer___objc_anonymous_block_A_dispatch_group_example______4:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_group_example______4) [line 52]\n REMOVE_TEMPS(n$35); [line 52]\n " shape="box"] +35 [label="35: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_group_example______4); [line 52]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_group_example______4); [line 52]\n n$38=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_group_example______4 ):unsigned long ) [line 52]\n *&__objc_anonymous_block_A_dispatch_group_example______4:class __objc_anonymous_block_A_dispatch_group_example______4 =n$38 [line 52]\n n$39=*&#GB$A_dispatch_group_example_a:class A * [line 52]\n *n$38.A_dispatch_group_example_a:class A *=n$39 [line 52]\n *&infer___objc_anonymous_block_A_dispatch_group_example______4:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_group_example______4) [line 52]\n REMOVE_TEMPS(n$38,n$39); [line 52]\n " shape="box"] 35 -> 34 ; -34 [label="34: Call n$29 \n n$29=*&infer___objc_anonymous_block_A_dispatch_group_example______4:_fn_ (*) [line 52]\n n$30=n$29() [line 52]\n REMOVE_TEMPS(n$29,n$30); [line 52]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_group_example______4,true); [line 52]\n " shape="box"] +34 [label="34: Call n$32 \n n$32=*&infer___objc_anonymous_block_A_dispatch_group_example______4:_fn_ (*) [line 52]\n n$33=n$32() [line 52]\n REMOVE_TEMPS(n$32,n$33); [line 52]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_group_example______4,true); [line 52]\n " shape="box"] 34 -> 33 ; -33 [label="33: Return Stmt \n n$27=*&#GB$A_dispatch_group_example_a:class A * [line 56]\n n$28=*n$27.x:int [line 56]\n *&return:int =n$28 [line 56]\n REMOVE_TEMPS(n$27,n$28); [line 56]\n NULLIFY(&__objc_anonymous_block_A_dispatch_group_example______4,true); [line 56]\n APPLY_ABSTRACTION; [line 56]\n " shape="box"] +33 [label="33: Return Stmt \n n$30=*&#GB$A_dispatch_group_example_a:class A * [line 56]\n n$31=*n$30.x:int [line 56]\n *&return:int =n$31 [line 56]\n REMOVE_TEMPS(n$30,n$31); [line 56]\n NULLIFY(&__objc_anonymous_block_A_dispatch_group_example______4,true); [line 56]\n APPLY_ABSTRACTION; [line 56]\n " shape="box"] 33 -> 32 ; @@ -117,11 +117,11 @@ digraph iCFG { 30 -> 25 ; -29 [label="29: BinaryOperatorStmt: Assign \n n$25=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 44]\n n$23=_fun_A_init(n$25:class A *) virtual [line 44]\n *&#GB$A_dispatch_after_example_a:class A *=n$23 [line 44]\n REMOVE_TEMPS(n$23,n$25); [line 44]\n " shape="box"] +29 [label="29: BinaryOperatorStmt: Assign \n n$27=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 44]\n n$25=_fun_A_init(n$27:class A *) virtual [line 44]\n *&#GB$A_dispatch_after_example_a:class A *=n$25 [line 44]\n REMOVE_TEMPS(n$25,n$27); [line 44]\n " shape="box"] 29 -> 28 ; -28 [label="28: BinaryOperatorStmt: Assign \n n$22=*&#GB$A_dispatch_after_example_a:class A * [line 45]\n *n$22.x:int =10 [line 45]\n REMOVE_TEMPS(n$22); [line 45]\n APPLY_ABSTRACTION; [line 45]\n " shape="box"] +28 [label="28: BinaryOperatorStmt: Assign \n n$24=*&#GB$A_dispatch_after_example_a:class A * [line 45]\n *n$24.x:int =10 [line 45]\n REMOVE_TEMPS(n$24); [line 45]\n APPLY_ABSTRACTION; [line 45]\n " shape="box"] 28 -> 27 ; @@ -132,15 +132,15 @@ digraph iCFG { 26 -> 29 ; -25 [label="25: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_after_example______3); [line 42]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_after_example______3); [line 43]\n n$26=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_after_example______3 ):unsigned long ) [line 43]\n *&__objc_anonymous_block_A_dispatch_after_example______3:class __objc_anonymous_block_A_dispatch_after_example______3 =n$26 [line 43]\n *&infer___objc_anonymous_block_A_dispatch_after_example______3:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_after_example______3) [line 42]\n REMOVE_TEMPS(n$26); [line 42]\n " shape="box"] +25 [label="25: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_after_example______3); [line 42]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_after_example______3); [line 43]\n n$28=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_after_example______3 ):unsigned long ) [line 43]\n *&__objc_anonymous_block_A_dispatch_after_example______3:class __objc_anonymous_block_A_dispatch_after_example______3 =n$28 [line 43]\n n$29=*&#GB$A_dispatch_after_example_a:class A * [line 43]\n *n$28.A_dispatch_after_example_a:class A *=n$29 [line 43]\n *&infer___objc_anonymous_block_A_dispatch_after_example______3:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_after_example______3) [line 42]\n REMOVE_TEMPS(n$28,n$29); [line 42]\n " shape="box"] 25 -> 24 ; -24 [label="24: Call n$20 \n n$20=*&infer___objc_anonymous_block_A_dispatch_after_example______3:_fn_ (*) [line 42]\n n$21=n$20() [line 42]\n REMOVE_TEMPS(n$20,n$21); [line 42]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_after_example______3,true); [line 42]\n " shape="box"] +24 [label="24: Call n$22 \n n$22=*&infer___objc_anonymous_block_A_dispatch_after_example______3:_fn_ (*) [line 42]\n n$23=n$22() [line 42]\n REMOVE_TEMPS(n$22,n$23); [line 42]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_after_example______3,true); [line 42]\n " shape="box"] 24 -> 23 ; -23 [label="23: Return Stmt \n n$18=*&#GB$A_dispatch_after_example_a:class A * [line 47]\n n$19=*n$18.x:int [line 47]\n *&return:int =n$19 [line 47]\n REMOVE_TEMPS(n$18,n$19); [line 47]\n NULLIFY(&__objc_anonymous_block_A_dispatch_after_example______3,true); [line 47]\n APPLY_ABSTRACTION; [line 47]\n " shape="box"] +23 [label="23: Return Stmt \n n$20=*&#GB$A_dispatch_after_example_a:class A * [line 47]\n n$21=*n$20.x:int [line 47]\n *&return:int =n$21 [line 47]\n REMOVE_TEMPS(n$20,n$21); [line 47]\n NULLIFY(&__objc_anonymous_block_A_dispatch_after_example______3,true); [line 47]\n APPLY_ABSTRACTION; [line 47]\n " shape="box"] 23 -> 22 ; @@ -155,11 +155,11 @@ digraph iCFG { 20 -> 15 ; -19 [label="19: BinaryOperatorStmt: Assign \n n$16=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 34]\n n$14=_fun_A_init(n$16:class A *) virtual [line 34]\n *&#GB$A_dispatch_async_example_a:class A *=n$14 [line 34]\n REMOVE_TEMPS(n$14,n$16); [line 34]\n " shape="box"] +19 [label="19: BinaryOperatorStmt: Assign \n n$17=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 34]\n n$15=_fun_A_init(n$17:class A *) virtual [line 34]\n *&#GB$A_dispatch_async_example_a:class A *=n$15 [line 34]\n REMOVE_TEMPS(n$15,n$17); [line 34]\n " shape="box"] 19 -> 18 ; -18 [label="18: BinaryOperatorStmt: Assign \n n$13=*&#GB$A_dispatch_async_example_a:class A * [line 35]\n *n$13.x:int =10 [line 35]\n REMOVE_TEMPS(n$13); [line 35]\n APPLY_ABSTRACTION; [line 35]\n " shape="box"] +18 [label="18: BinaryOperatorStmt: Assign \n n$14=*&#GB$A_dispatch_async_example_a:class A * [line 35]\n *n$14.x:int =10 [line 35]\n REMOVE_TEMPS(n$14); [line 35]\n APPLY_ABSTRACTION; [line 35]\n " shape="box"] 18 -> 17 ; @@ -170,15 +170,15 @@ digraph iCFG { 16 -> 19 ; -15 [label="15: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_async_example______2); [line 33]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_async_example______2); [line 33]\n n$17=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_async_example______2 ):unsigned long ) [line 33]\n *&__objc_anonymous_block_A_dispatch_async_example______2:class __objc_anonymous_block_A_dispatch_async_example______2 =n$17 [line 33]\n *&infer___objc_anonymous_block_A_dispatch_async_example______2:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_async_example______2) [line 33]\n REMOVE_TEMPS(n$17); [line 33]\n " shape="box"] +15 [label="15: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_async_example______2); [line 33]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_async_example______2); [line 33]\n n$18=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_async_example______2 ):unsigned long ) [line 33]\n *&__objc_anonymous_block_A_dispatch_async_example______2:class __objc_anonymous_block_A_dispatch_async_example______2 =n$18 [line 33]\n n$19=*&#GB$A_dispatch_async_example_a:class A * [line 33]\n *n$18.A_dispatch_async_example_a:class A *=n$19 [line 33]\n *&infer___objc_anonymous_block_A_dispatch_async_example______2:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_async_example______2) [line 33]\n REMOVE_TEMPS(n$18,n$19); [line 33]\n " shape="box"] 15 -> 14 ; -14 [label="14: Call n$11 \n n$11=*&infer___objc_anonymous_block_A_dispatch_async_example______2:_fn_ (*) [line 33]\n n$12=n$11() [line 33]\n REMOVE_TEMPS(n$11,n$12); [line 33]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_async_example______2,true); [line 33]\n " shape="box"] +14 [label="14: Call n$12 \n n$12=*&infer___objc_anonymous_block_A_dispatch_async_example______2:_fn_ (*) [line 33]\n n$13=n$12() [line 33]\n REMOVE_TEMPS(n$12,n$13); [line 33]\n NULLIFY(&infer___objc_anonymous_block_A_dispatch_async_example______2,true); [line 33]\n " shape="box"] 14 -> 13 ; -13 [label="13: Return Stmt \n n$9=*&#GB$A_dispatch_async_example_a:class A * [line 37]\n n$10=*n$9.x:int [line 37]\n *&return:int =n$10 [line 37]\n REMOVE_TEMPS(n$9,n$10); [line 37]\n NULLIFY(&__objc_anonymous_block_A_dispatch_async_example______2,true); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"] +13 [label="13: Return Stmt \n n$10=*&#GB$A_dispatch_async_example_a:class A * [line 37]\n n$11=*n$10.x:int [line 37]\n *&return:int =n$11 [line 37]\n REMOVE_TEMPS(n$10,n$11); [line 37]\n NULLIFY(&__objc_anonymous_block_A_dispatch_async_example______2,true); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"] 13 -> 12 ; @@ -208,7 +208,7 @@ digraph iCFG { 6 -> 9 ; -5 [label="5: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_once_example______1); [line 23]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_once_example______1); [line 24]\n n$8=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_once_example______1 ):unsigned long ) [line 24]\n *&__objc_anonymous_block_A_dispatch_once_example______1:class __objc_anonymous_block_A_dispatch_once_example______1 =n$8 [line 24]\n *&infer___objc_anonymous_block_A_dispatch_once_example______1:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_once_example______1) [line 23]\n REMOVE_TEMPS(n$8); [line 23]\n " shape="box"] +5 [label="5: DeclStmt \n DECLARE_LOCALS(&infer___objc_anonymous_block_A_dispatch_once_example______1); [line 23]\n DECLARE_LOCALS(&__objc_anonymous_block_A_dispatch_once_example______1); [line 24]\n n$8=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_dispatch_once_example______1 ):unsigned long ) [line 24]\n *&__objc_anonymous_block_A_dispatch_once_example______1:class __objc_anonymous_block_A_dispatch_once_example______1 =n$8 [line 24]\n n$9=*&#GB$A_dispatch_once_example_a:class A * [line 24]\n *n$8.A_dispatch_once_example_a:class A *=n$9 [line 24]\n *&infer___objc_anonymous_block_A_dispatch_once_example______1:_fn_ (*)=(_fun___objc_anonymous_block_A_dispatch_once_example______1) [line 23]\n REMOVE_TEMPS(n$8,n$9); [line 23]\n " shape="box"] 5 -> 4 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/static.dot b/infer/tests/codetoanalyze/objc/frontend/block/static.dot index b40657042..2115f2beb 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/static.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/static.dot @@ -10,11 +10,11 @@ digraph iCFG { 29 -> 31 ; -28 [label="28: Call (_fun___objc_anonymous_block_A_test3______4) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test3______4); [line 59]\n n$17=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test3______4 ):unsigned long ) [line 59]\n *&__objc_anonymous_block_A_test3______4:class __objc_anonymous_block_A_test3______4 =n$17 [line 59]\n (_fun___objc_anonymous_block_A_test3______4)() [line 59]\n REMOVE_TEMPS(n$17); [line 59]\n " shape="box"] +28 [label="28: Call (_fun___objc_anonymous_block_A_test3______4) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test3______4); [line 59]\n n$20=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test3______4 ):unsigned long ) [line 59]\n *&__objc_anonymous_block_A_test3______4:class __objc_anonymous_block_A_test3______4 =n$20 [line 59]\n n$21=*&#GB$A_test3_i:int [line 59]\n *n$20.A_test3_i:int =n$21 [line 59]\n (_fun___objc_anonymous_block_A_test3______4)() [line 59]\n REMOVE_TEMPS(n$20,n$21); [line 59]\n " shape="box"] 28 -> 24 ; -27 [label="27: UnaryOperator \n n$16=*&#GB$A_test3_i:int [line 61]\n *&#GB$A_test3_i:int =(n$16 + 1) [line 61]\n REMOVE_TEMPS(n$16); [line 61]\n APPLY_ABSTRACTION; [line 61]\n " shape="box"] +27 [label="27: UnaryOperator \n n$19=*&#GB$A_test3_i:int [line 61]\n *&#GB$A_test3_i:int =(n$19 + 1) [line 61]\n REMOVE_TEMPS(n$19); [line 61]\n APPLY_ABSTRACTION; [line 61]\n " shape="box"] 27 -> 26 ; @@ -25,7 +25,7 @@ digraph iCFG { 25 -> 27 ; -24 [label="24: Return Stmt \n n$15=*&#GB$A_test3_i:int [line 64]\n *&return:int =n$15 [line 64]\n REMOVE_TEMPS(n$15); [line 64]\n NULLIFY(&__objc_anonymous_block_A_test3______4,true); [line 64]\n APPLY_ABSTRACTION; [line 64]\n " shape="box"] +24 [label="24: Return Stmt \n n$18=*&#GB$A_test3_i:int [line 64]\n *&return:int =n$18 [line 64]\n REMOVE_TEMPS(n$18); [line 64]\n NULLIFY(&__objc_anonymous_block_A_test3______4,true); [line 64]\n APPLY_ABSTRACTION; [line 64]\n " shape="box"] 24 -> 23 ; @@ -36,15 +36,15 @@ digraph iCFG { 22 -> 28 ; -21 [label="21: BinaryOperatorStmt: Assign \n n$14=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 43]\n n$12=_fun_A_init(n$14:class A *) virtual [line 43]\n *&#GB$A_test2_sharedInstance:struct objc_object *=n$12 [line 43]\n REMOVE_TEMPS(n$12,n$14); [line 43]\n " shape="box"] +21 [label="21: BinaryOperatorStmt: Assign \n n$17=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 43]\n n$15=_fun_A_init(n$17:class A *) virtual [line 43]\n *&#GB$A_test2_sharedInstance:struct objc_object *=n$15 [line 43]\n REMOVE_TEMPS(n$15,n$17); [line 43]\n " shape="box"] 21 -> 20 ; -20 [label="20: Call (_fun___objc_anonymous_block_A_test2______3) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test2______3); [line 44]\n n$11=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test2______3 ):unsigned long ) [line 44]\n *&__objc_anonymous_block_A_test2______3:class __objc_anonymous_block_A_test2______3 =n$11 [line 44]\n (_fun___objc_anonymous_block_A_test2______3)() [line 44]\n REMOVE_TEMPS(n$11); [line 44]\n " shape="box"] +20 [label="20: Call (_fun___objc_anonymous_block_A_test2______3) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test2______3); [line 44]\n n$13=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test2______3 ):unsigned long ) [line 44]\n *&__objc_anonymous_block_A_test2______3:class __objc_anonymous_block_A_test2______3 =n$13 [line 44]\n n$14=*&#GB$A_test2_sharedInstance:struct objc_object * [line 44]\n *n$13.A_test2_sharedInstance:struct objc_object *=n$14 [line 44]\n (_fun___objc_anonymous_block_A_test2______3)() [line 44]\n REMOVE_TEMPS(n$13,n$14); [line 44]\n " shape="box"] 20 -> 16 ; -19 [label="19: DeclStmt \n n$10=*&#GB$A_test2_sharedInstance:struct objc_object * [line 46]\n *&p:struct objc_object *=n$10 [line 46]\n REMOVE_TEMPS(n$10); [line 46]\n NULLIFY(&p,false); [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="box"] +19 [label="19: DeclStmt \n n$12=*&#GB$A_test2_sharedInstance:struct objc_object * [line 46]\n *&p:struct objc_object *=n$12 [line 46]\n REMOVE_TEMPS(n$12); [line 46]\n NULLIFY(&p,false); [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="box"] 19 -> 18 ; @@ -55,7 +55,7 @@ digraph iCFG { 17 -> 19 ; -16 [label="16: Return Stmt \n n$9=*&#GB$A_test2_sharedInstance:struct objc_object * [line 49]\n *&return:struct objc_object *=n$9 [line 49]\n REMOVE_TEMPS(n$9); [line 49]\n NULLIFY(&__objc_anonymous_block_A_test2______3,true); [line 49]\n APPLY_ABSTRACTION; [line 49]\n " shape="box"] +16 [label="16: Return Stmt \n n$11=*&#GB$A_test2_sharedInstance:struct objc_object * [line 49]\n *&return:struct objc_object *=n$11 [line 49]\n REMOVE_TEMPS(n$11); [line 49]\n NULLIFY(&__objc_anonymous_block_A_test2______3,true); [line 49]\n APPLY_ABSTRACTION; [line 49]\n " shape="box"] 16 -> 15 ; @@ -66,11 +66,11 @@ digraph iCFG { 14 -> 21 ; -13 [label="13: Call (_fun___objc_anonymous_block_A_test_leak______2) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test_leak______2); [line 32]\n n$8=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test_leak______2 ):unsigned long ) [line 32]\n *&__objc_anonymous_block_A_test_leak______2:class __objc_anonymous_block_A_test_leak______2 =n$8 [line 32]\n (_fun___objc_anonymous_block_A_test_leak______2)() [line 32]\n REMOVE_TEMPS(n$8); [line 32]\n NULLIFY(&__objc_anonymous_block_A_test_leak______2,true); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"] +13 [label="13: Call (_fun___objc_anonymous_block_A_test_leak______2) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test_leak______2); [line 32]\n n$9=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test_leak______2 ):unsigned long ) [line 32]\n *&__objc_anonymous_block_A_test_leak______2:class __objc_anonymous_block_A_test_leak______2 =n$9 [line 32]\n n$10=*&#GB$A_test_leak_sharedInstance:struct objc_object * [line 32]\n *n$9.A_test_leak_sharedInstance:struct objc_object *=n$10 [line 32]\n (_fun___objc_anonymous_block_A_test_leak______2)() [line 32]\n REMOVE_TEMPS(n$9,n$10); [line 32]\n NULLIFY(&__objc_anonymous_block_A_test_leak______2,true); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"] 13 -> 9 ; -12 [label="12: BinaryOperatorStmt: Assign \n n$7=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 33]\n n$5=_fun_A_init(n$7:class A *) virtual [line 33]\n *&#GB$A_test_leak_sharedInstance:struct objc_object *=n$5 [line 33]\n REMOVE_TEMPS(n$5,n$7); [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] +12 [label="12: BinaryOperatorStmt: Assign \n n$8=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 33]\n n$6=_fun_A_init(n$8:class A *) virtual [line 33]\n *&#GB$A_test_leak_sharedInstance:struct objc_object *=n$6 [line 33]\n REMOVE_TEMPS(n$6,n$8); [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] 12 -> 11 ; @@ -88,7 +88,7 @@ digraph iCFG { 8 -> 13 ; -7 [label="7: Call (_fun___objc_anonymous_block_A_test______1) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test______1); [line 21]\n n$4=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test______1 ):unsigned long ) [line 21]\n *&__objc_anonymous_block_A_test______1:class __objc_anonymous_block_A_test______1 =n$4 [line 21]\n (_fun___objc_anonymous_block_A_test______1)() [line 21]\n REMOVE_TEMPS(n$4); [line 21]\n " shape="box"] +7 [label="7: Call (_fun___objc_anonymous_block_A_test______1) \n DECLARE_LOCALS(&__objc_anonymous_block_A_test______1); [line 21]\n n$4=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_A_test______1 ):unsigned long ) [line 21]\n *&__objc_anonymous_block_A_test______1:class __objc_anonymous_block_A_test______1 =n$4 [line 21]\n n$5=*&#GB$A_test_sharedInstance:struct objc_object * [line 21]\n *n$4.A_test_sharedInstance:struct objc_object *=n$5 [line 21]\n (_fun___objc_anonymous_block_A_test______1)() [line 21]\n REMOVE_TEMPS(n$4,n$5); [line 21]\n " shape="box"] 7 -> 3 ; diff --git a/infer/tests/endtoend/objc/RetainCycleStaticVarTest.java b/infer/tests/endtoend/objc/RetainCycleStaticVarTest.java new file mode 100644 index 000000000..0fee5feee --- /dev/null +++ b/infer/tests/endtoend/objc/RetainCycleStaticVarTest.java @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2013 - present Facebook, Inc. +* All rights reserved. +* +* This source code is licensed under the BSD style license found in the +* LICENSE file in the root directory of this source tree. An additional grant +* of patent rights can be found in the PATENTS file in the same directory. +*/ + +package endtoend.objc; + +import static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.ResultContainsErrorInMethod.contains; +import static utils.matchers.ResultContainsExactly.containsExactly; +import static utils.matchers.ResultContainsNoErrorInMethod.doesNotContain; + +import com.google.common.collect.ImmutableList; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.InferResults; +import utils.InferRunner; + +public class RetainCycleStaticVarTest { + + public static final String FILE = + "infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleStaticVar.m"; + + private static ImmutableList inferCmd; + + public static final String RETAIN_CYCLE = "RETAIN_CYCLE"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createObjCInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnStrongCycleThenRCIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferObjC(inferCmd); + String[] procedures = { + "main", + }; + assertThat( + "Results should contain the expected retain cycles", + inferResults, + containsExactly( + RETAIN_CYCLE, + FILE, + procedures + ) + ); + } +}