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 + ) + ); + } +}