diff --git a/infer/src/backend/preanal.ml b/infer/src/backend/preanal.ml index 7c577a7f6..e2465f32f 100644 --- a/infer/src/backend/preanal.ml +++ b/infer/src/backend/preanal.ml @@ -48,29 +48,23 @@ end module Vset = AddressTaken.PvarSet -let captured_var = ref Vset.empty - let is_not_function cfg x = let pname = Procname.from_string_c_fun (Mangled.to_string (Pvar.get_name x)) in Cfg.Procdesc.find_from_name cfg pname = None -let is_captured pdesc x = - let captured = Cfg.Procdesc.get_captured pdesc in - IList.exists (fun (m, _) -> (Pvar.to_string x) = (Mangled.to_string m)) captured - (** variables read in the expression *) let rec use_exp cfg pdesc (exp: Sil.exp) acc = match exp with | Sil.Var _ | Sil.Sizeof _ -> acc - | Sil.Const (Cclosure { captured_vars }) -> - IList.iter - (fun (_, captured, _) -> captured_var:= Vset.add captured !captured_var) - captured_vars; + | Sil.Const (Cclosure { captured_vars; }) -> + IList.fold_left + (fun vset_acc (_, captured_pvar, _) -> Vset.add captured_pvar vset_acc) + acc + captured_vars + | Sil.Const + (Cint _ | Cfun _ | Cstr _ | Cfloat _ | Cattribute _ | Cexn _ | Cclass _ | Cptr_to_fld _) -> acc - | Sil.Const _ -> acc - | Sil.Lvar x -> - (* If x is a captured var in the current procdesc don't add it to acc *) - if is_captured pdesc x then acc else Vset.add x acc + | Sil.Lvar x -> Vset.add x acc | Sil.Cast (_, e) | Sil.UnOp (_, e, _) | Sil.Lfield (e, _, _) -> use_exp cfg pdesc e acc | Sil.BinOp (_, e1, e2) | Sil.Lindex (e1, e2) -> use_exp cfg pdesc e1 (use_exp cfg pdesc e2 acc) @@ -179,12 +173,8 @@ let compute_candidates procdesc : Vset.t * (Vset.t -> Vset.elt list) = | _ -> false in let add_vi (pvar, typ) = let pv = Pvar.mk pvar (Cfg.Procdesc.get_proc_name procdesc) in - if is_captured procdesc pv then () - (* don't add captured vars of the current pdesc to candidates *) - else ( - candidates := Vset.add pv !candidates; - if typ_is_struct_array typ then struct_array_cand := Vset.add pv !struct_array_cand - ) in + candidates := Vset.add pv !candidates; + if typ_is_struct_array typ then struct_array_cand := Vset.add pv !struct_array_cand in IList.iter add_vi (Cfg.Procdesc.get_formals procdesc); IList.iter add_vi (Cfg.Procdesc.get_locals procdesc); let get_sorted_candidates vs = @@ -306,7 +296,6 @@ let analyze_and_annotate_proc cfg pname pdesc = match AddressTaken.Analyzer.compute_post pdesc with | Some post -> post | None -> Vset.empty in - captured_var:= Vset.empty; analyze_proc cfg pdesc cand; @@ -321,13 +310,11 @@ let analyze_and_annotate_proc cfg pname pdesc = L.err "WARNING: liveness: more than %d dead pvars added in procedure %a, stopping@." dead_pvars_limit Procname.pp pname in Table.iter cand (fun n live_at_predecessors live_current -> (* set dead variables on nodes *) - let nonnull_pvars = - Vset.inter (def_node cfg n live_at_predecessors) cand in (* live before, or assigned to *) - let dead_pvars = - Vset.diff nonnull_pvars live_current in (* only nullify when variable become live *) - let dead_pvars_no_captured = Vset.diff dead_pvars !captured_var in - let dead_pvars_no_addr_taken = - get_sorted_cand (Vset.diff dead_pvars_no_captured addr_taken_vars) in + (* live before, or assigned to *) + let nonnull_pvars = Vset.inter (def_node cfg n live_at_predecessors) cand in + (* only nullify when variables become live *) + let dead_pvars = Vset.diff nonnull_pvars live_current in + let dead_pvars_no_addr_taken = get_sorted_cand (Vset.diff dead_pvars addr_taken_vars) in let dead_pvars_to_add = if exit_node_is_succ n (* add dead address taken vars just before the exit node *) then dead_pvars_no_addr_taken @ (get_sorted_cand (Vset.inter cand addr_taken_vars)) diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot index 2abd2be5c..d208c5040 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.dot @@ -1,143 +1,238 @@ digraph iCFG { -50 [label="50: DeclStmt \n n$35=_fun_FBColorCreateWithGray(0.000000:double ,0.300000:double ) [line 86]\n *&borderColor:struct CGColor *=n$35 [line 86]\n REMOVE_TEMPS(n$35); [line 86]\n " shape="box"] +75 [label="75: DeclStmt \n n$59=_fun_malloc_no_fail(sizeof(int ):int ) [line 103]\n *&x:int *=n$59 [line 103]\n REMOVE_TEMPS(n$59); [line 103]\n " shape="box"] + + + 75 -> 74 ; +74 [label="74: BinaryOperatorStmt: Assign \n n$58=*&x:int * [line 104]\n *n$58:int =2 [line 104]\n REMOVE_TEMPS(n$58); [line 104]\n " shape="box"] + + + 74 -> 73 ; +73 [label="73: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2); [line 105]\n n$56=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2 ):unsigned long ) [line 105]\n *&__objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2:class __objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2 =n$56 [line 105]\n n$57=*&x:int * [line 105]\n *n$56.x:int *=n$57 [line 105]\n n$51=*&x:int * [line 105]\n *&blk:_fn_ (*)=(_fun___objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2,n$51) [line 105]\n REMOVE_TEMPS(n$56,n$57,n$51); [line 105]\n NULLIFY(&x,false); [line 105]\n " shape="box"] + + + 73 -> 67 ; +72 [label="72: DeclStmt \n n$54=*&x:int * [line 106]\n n$55=*n$54:int [line 106]\n *&i:int =n$55 [line 106]\n REMOVE_TEMPS(n$54,n$55); [line 106]\n " shape="box"] + + + 72 -> 71 ; +71 [label="71: Call _fun_free \n n$53=*&x:int * [line 107]\n _fun_free(n$53:void *) [line 107]\n REMOVE_TEMPS(n$53); [line 107]\n NULLIFY(&x,false); [line 107]\n " shape="box"] + + + 71 -> 70 ; +70 [label="70: Return Stmt \n n$52=*&i:int [line 108]\n *&return:int =n$52 [line 108]\n REMOVE_TEMPS(n$52); [line 108]\n NULLIFY(&i,false); [line 108]\n APPLY_ABSTRACTION; [line 108]\n " shape="box"] + + + 70 -> 69 ; +69 [label="69: Exit __objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2 \n " color=yellow style=filled] + + +68 [label="68: Start __objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2\nFormals: x:int *\nLocals: i:int \nCaptured: x:int * \n DECLARE_LOCALS(&return,&i); [line 105]\n NULLIFY(&i,false); [line 105]\n " color=yellow style=filled] + + + 68 -> 72 ; +67 [label="67: Return Stmt \n n$49=*&blk:_fn_ (*) [line 110]\n n$50=n$49() [line 110]\n *&return:int =n$50 [line 110]\n REMOVE_TEMPS(n$49,n$50); [line 110]\n NULLIFY(&__objc_anonymous_block_MemoryLeakExample_blockFreeNoLeakTODO______2,true); [line 110]\n NULLIFY(&blk,false); [line 110]\n APPLY_ABSTRACTION; [line 110]\n " shape="box"] + + + 67 -> 66 ; +66 [label="66: Exit MemoryLeakExample_blockFreeNoLeakTODO \n " color=yellow style=filled] + + +65 [label="65: Start MemoryLeakExample_blockFreeNoLeakTODO\nFormals: self:class MemoryLeakExample *\nLocals: blk:_fn_ (*) x:int * \n DECLARE_LOCALS(&return,&blk,&x); [line 102]\n NULLIFY(&blk,false); [line 102]\n NULLIFY(&self,false); [line 102]\n NULLIFY(&x,false); [line 102]\n " color=yellow style=filled] + + + 65 -> 75 ; +64 [label="64: DeclStmt \n n$48=_fun_malloc_no_fail(sizeof(int ):int ) [line 94]\n *&x:int *=n$48 [line 94]\n REMOVE_TEMPS(n$48); [line 94]\n " shape="box"] + + + 64 -> 63 ; +63 [label="63: BinaryOperatorStmt: Assign \n n$47=*&x:int * [line 95]\n *n$47:int =2 [line 95]\n REMOVE_TEMPS(n$47); [line 95]\n " shape="box"] + + + 63 -> 62 ; +62 [label="62: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1); [line 96]\n n$45=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1 ):unsigned long ) [line 96]\n *&__objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1:class __objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1 =n$45 [line 96]\n n$46=*&x:int * [line 96]\n *n$45.x:int *=n$46 [line 96]\n n$42=*&x:int * [line 96]\n *&blk:_fn_ (*)=(_fun___objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1,n$42) [line 96]\n REMOVE_TEMPS(n$45,n$46,n$42); [line 96]\n NULLIFY(&x,false); [line 96]\n " shape="box"] + + + 62 -> 58 ; +61 [label="61: Return Stmt \n n$43=*&x:int * [line 97]\n n$44=*n$43:int [line 97]\n *&return:int =n$44 [line 97]\n REMOVE_TEMPS(n$43,n$44); [line 97]\n NULLIFY(&x,false); [line 97]\n APPLY_ABSTRACTION; [line 97]\n " shape="box"] + + + 61 -> 60 ; +60 [label="60: Exit __objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1 \n " color=yellow style=filled] + + +59 [label="59: Start __objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1\nFormals: x:int *\nLocals: \nCaptured: x:int * \n DECLARE_LOCALS(&return); [line 96]\n " color=yellow style=filled] + + + 59 -> 61 ; +58 [label="58: Return Stmt \n n$40=*&blk:_fn_ (*) [line 99]\n n$41=n$40() [line 99]\n *&return:int =n$41 [line 99]\n REMOVE_TEMPS(n$40,n$41); [line 99]\n NULLIFY(&__objc_anonymous_block_MemoryLeakExample_blockCapturedVarLeak______1,true); [line 99]\n NULLIFY(&blk,false); [line 99]\n APPLY_ABSTRACTION; [line 99]\n " shape="box"] + + + 58 -> 57 ; +57 [label="57: Exit MemoryLeakExample_blockCapturedVarLeak \n " color=yellow style=filled] + + +56 [label="56: Start MemoryLeakExample_blockCapturedVarLeak\nFormals: self:class MemoryLeakExample *\nLocals: blk:_fn_ (*) x:int * \n DECLARE_LOCALS(&return,&blk,&x); [line 93]\n NULLIFY(&blk,false); [line 93]\n NULLIFY(&self,false); [line 93]\n NULLIFY(&x,false); [line 93]\n " color=yellow style=filled] + + + 56 -> 64 ; +55 [label="55: DeclStmt \n n$39=_fun_malloc_no_fail(sizeof(int ):int ) [line 88]\n *&x:int *=n$39 [line 88]\n REMOVE_TEMPS(n$39); [line 88]\n " shape="box"] + + + 55 -> 54 ; +54 [label="54: BinaryOperatorStmt: Assign \n n$38=*&x:int * [line 89]\n *n$38:int =7 [line 89]\n REMOVE_TEMPS(n$38); [line 89]\n " shape="box"] + + + 54 -> 53 ; +53 [label="53: Return Stmt \n n$36=*&x:int * [line 90]\n n$37=*n$36:int [line 90]\n *&return:int =n$37 [line 90]\n REMOVE_TEMPS(n$36,n$37); [line 90]\n NULLIFY(&x,false); [line 90]\n APPLY_ABSTRACTION; [line 90]\n " shape="box"] + + + 53 -> 52 ; +52 [label="52: Exit MemoryLeakExample_regularLeak \n " color=yellow style=filled] + + +51 [label="51: Start MemoryLeakExample_regularLeak\nFormals: self:class MemoryLeakExample *\nLocals: x:int * \n DECLARE_LOCALS(&return,&x); [line 87]\n NULLIFY(&self,false); [line 87]\n NULLIFY(&x,false); [line 87]\n " color=yellow style=filled] + + + 51 -> 55 ; +50 [label="50: DeclStmt \n n$35=_fun_FBColorCreateWithGray(0.000000:double ,0.300000:double ) [line 83]\n *&borderColor:struct CGColor *=n$35 [line 83]\n REMOVE_TEMPS(n$35); [line 83]\n " shape="box"] 50 -> 49 ; -49 [label="49: Call _fun_CGColorRelease \n n$34=*&borderColor:struct CGColor * [line 87]\n _fun_CGColorRelease(n$34:struct CGColor *) [line 87]\n REMOVE_TEMPS(n$34); [line 87]\n NULLIFY(&borderColor,false); [line 87]\n APPLY_ABSTRACTION; [line 87]\n " shape="box"] +49 [label="49: Call _fun_CGColorRelease \n n$34=*&borderColor:struct CGColor * [line 84]\n _fun_CGColorRelease(n$34:struct CGColor *) [line 84]\n REMOVE_TEMPS(n$34); [line 84]\n NULLIFY(&borderColor,false); [line 84]\n APPLY_ABSTRACTION; [line 84]\n " shape="box"] 49 -> 48 ; 48 [label="48: Exit MemoryLeakExample_testFBColorCreateWithGray \n " color=yellow style=filled] -47 [label="47: Start MemoryLeakExample_testFBColorCreateWithGray\nFormals: self:class MemoryLeakExample *\nLocals: borderColor:struct CGColor * \n DECLARE_LOCALS(&return,&borderColor); [line 85]\n NULLIFY(&borderColor,false); [line 85]\n NULLIFY(&self,false); [line 85]\n " color=yellow style=filled] +47 [label="47: Start MemoryLeakExample_testFBColorCreateWithGray\nFormals: self:class MemoryLeakExample *\nLocals: borderColor:struct CGColor * \n DECLARE_LOCALS(&return,&borderColor); [line 82]\n NULLIFY(&borderColor,false); [line 82]\n NULLIFY(&self,false); [line 82]\n " color=yellow style=filled] 47 -> 50 ; -46 [label="46: DeclStmt \n n$33=_fun_CGBitmapContextCreateImage(0:struct CGContext *) [line 79]\n *&newImage:struct CGImage *=n$33 [line 79]\n REMOVE_TEMPS(n$33); [line 79]\n " shape="box"] +46 [label="46: DeclStmt \n n$33=_fun_CGBitmapContextCreateImage(0:struct CGContext *) [line 76]\n *&newImage:struct CGImage *=n$33 [line 76]\n REMOVE_TEMPS(n$33); [line 76]\n " shape="box"] 46 -> 45 ; -45 [label="45: Call _fun_CGImageRelease \n n$32=*&newImage:struct CGImage * [line 80]\n _fun_CGImageRelease(n$32:struct CGImage *) [line 80]\n REMOVE_TEMPS(n$32); [line 80]\n NULLIFY(&newImage,false); [line 80]\n APPLY_ABSTRACTION; [line 80]\n " shape="box"] +45 [label="45: Call _fun_CGImageRelease \n n$32=*&newImage:struct CGImage * [line 77]\n _fun_CGImageRelease(n$32:struct CGImage *) [line 77]\n REMOVE_TEMPS(n$32); [line 77]\n NULLIFY(&newImage,false); [line 77]\n APPLY_ABSTRACTION; [line 77]\n " shape="box"] 45 -> 44 ; 44 [label="44: Exit MemoryLeakExample_testImageRefRelease \n " color=yellow style=filled] -43 [label="43: Start MemoryLeakExample_testImageRefRelease\nFormals: \nLocals: newImage:struct CGImage * \n DECLARE_LOCALS(&return,&newImage); [line 78]\n NULLIFY(&newImage,false); [line 78]\n " color=yellow style=filled] +43 [label="43: Start MemoryLeakExample_testImageRefRelease\nFormals: \nLocals: newImage:struct CGImage * \n DECLARE_LOCALS(&return,&newImage); [line 75]\n NULLIFY(&newImage,false); [line 75]\n " color=yellow style=filled] 43 -> 46 ; -42 [label="42: DeclStmt \n n$31=_fun_SecTrustCopyPublicKey(0:struct __SecTrust *) [line 74]\n *&allowedPublicKey:struct __SecKey *=n$31 [line 74]\n REMOVE_TEMPS(n$31); [line 74]\n " shape="box"] +42 [label="42: DeclStmt \n n$31=_fun_SecTrustCopyPublicKey(0:struct __SecTrust *) [line 71]\n *&allowedPublicKey:struct __SecKey *=n$31 [line 71]\n REMOVE_TEMPS(n$31); [line 71]\n " shape="box"] 42 -> 41 ; -41 [label="41: Call _fun___objc_release_cf \n n$30=*&allowedPublicKey:struct __SecKey * [line 75]\n _fun___objc_release_cf(1:_Bool ,n$30:void *) [line 75]\n REMOVE_TEMPS(n$30); [line 75]\n NULLIFY(&allowedPublicKey,false); [line 75]\n APPLY_ABSTRACTION; [line 75]\n " shape="box"] +41 [label="41: Call _fun___objc_release_cf \n n$30=*&allowedPublicKey:struct __SecKey * [line 72]\n _fun___objc_release_cf(1:_Bool ,n$30:void *) [line 72]\n REMOVE_TEMPS(n$30); [line 72]\n NULLIFY(&allowedPublicKey,false); [line 72]\n APPLY_ABSTRACTION; [line 72]\n " shape="box"] 41 -> 40 ; 40 [label="40: Exit MemoryLeakExample_test2NoLeak \n " color=yellow style=filled] -39 [label="39: Start MemoryLeakExample_test2NoLeak\nFormals: \nLocals: allowedPublicKey:struct __SecKey * \n DECLARE_LOCALS(&return,&allowedPublicKey); [line 73]\n NULLIFY(&allowedPublicKey,false); [line 73]\n " color=yellow style=filled] +39 [label="39: Start MemoryLeakExample_test2NoLeak\nFormals: \nLocals: allowedPublicKey:struct __SecKey * \n DECLARE_LOCALS(&return,&allowedPublicKey); [line 70]\n NULLIFY(&allowedPublicKey,false); [line 70]\n " color=yellow style=filled] 39 -> 42 ; -38 [label="38: DeclStmt \n n$28=*&trust:struct __SecTrust * [line 70]\n n$29=_fun_SecTrustCopyPublicKey(n$28:struct __SecTrust *) [line 70]\n *&allowedPublicKey:struct __SecKey *=n$29 [line 70]\n REMOVE_TEMPS(n$28,n$29); [line 70]\n NULLIFY(&allowedPublicKey,false); [line 70]\n NULLIFY(&trust,false); [line 70]\n APPLY_ABSTRACTION; [line 70]\n " shape="box"] +38 [label="38: Call _fun_SecTrustCopyPublicKey \n n$28=*&trust:struct __SecTrust * [line 67]\n n$29=_fun_SecTrustCopyPublicKey(n$28:struct __SecTrust *) [line 67]\n REMOVE_TEMPS(n$28,n$29); [line 67]\n NULLIFY(&trust,false); [line 67]\n APPLY_ABSTRACTION; [line 67]\n " shape="box"] 38 -> 37 ; 37 [label="37: Exit MemoryLeakExample_test2: \n " color=yellow style=filled] -36 [label="36: Start MemoryLeakExample_test2:\nFormals: trust:struct __SecTrust *\nLocals: allowedPublicKey:struct __SecKey * \n DECLARE_LOCALS(&return,&allowedPublicKey); [line 69]\n NULLIFY(&allowedPublicKey,false); [line 69]\n " color=yellow style=filled] +36 [label="36: Start MemoryLeakExample_test2:\nFormals: trust:struct __SecTrust *\nLocals: \n DECLARE_LOCALS(&return); [line 66]\n " color=yellow style=filled] 36 -> 38 ; -35 [label="35: DeclStmt \n n$26=*&rect:struct CGRect [line 62]\n n$27=_fun_CGRectGetHeight(n$26:struct CGRect ) [line 62]\n *&lineThickness:double =(0.200000 * n$27) [line 62]\n REMOVE_TEMPS(n$26,n$27); [line 62]\n NULLIFY(&rect,false); [line 62]\n NULLIFY(&lineThickness,false); [line 62]\n " shape="box"] +35 [label="35: DeclStmt \n n$26=*&rect:struct CGRect [line 59]\n n$27=_fun_CGRectGetHeight(n$26:struct CGRect ) [line 59]\n *&lineThickness:double =(0.200000 * n$27) [line 59]\n REMOVE_TEMPS(n$26,n$27); [line 59]\n NULLIFY(&rect,false); [line 59]\n NULLIFY(&lineThickness,false); [line 59]\n " shape="box"] 35 -> 34 ; -34 [label="34: DeclStmt \n n$25=_fun_CGPathCreateMutable() [line 65]\n *&path1:struct CGPath *=n$25 [line 65]\n REMOVE_TEMPS(n$25); [line 65]\n " shape="box"] +34 [label="34: DeclStmt \n n$25=_fun_CGPathCreateMutable() [line 62]\n *&path1:struct CGPath *=n$25 [line 62]\n REMOVE_TEMPS(n$25); [line 62]\n " shape="box"] 34 -> 33 ; -33 [label="33: Call _fun___objc_release_cf \n n$24=*&path1:struct CGPath * [line 66]\n _fun___objc_release_cf(1:_Bool ,n$24:void *) [line 66]\n REMOVE_TEMPS(n$24); [line 66]\n NULLIFY(&path1,false); [line 66]\n APPLY_ABSTRACTION; [line 66]\n " shape="box"] +33 [label="33: Call _fun___objc_release_cf \n n$24=*&path1:struct CGPath * [line 63]\n _fun___objc_release_cf(1:_Bool ,n$24:void *) [line 63]\n REMOVE_TEMPS(n$24); [line 63]\n NULLIFY(&path1,false); [line 63]\n APPLY_ABSTRACTION; [line 63]\n " shape="box"] 33 -> 32 ; 32 [label="32: Exit MemoryLeakExample_createCloseCrossGlyphNoLeak: \n " color=yellow style=filled] -31 [label="31: Start MemoryLeakExample_createCloseCrossGlyphNoLeak:\nFormals: rect:struct CGRect \nLocals: path1:struct CGPath * lineThickness:double \n DECLARE_LOCALS(&return,&path1,&lineThickness); [line 61]\n NULLIFY(&lineThickness,false); [line 61]\n NULLIFY(&path1,false); [line 61]\n " color=yellow style=filled] +31 [label="31: Start MemoryLeakExample_createCloseCrossGlyphNoLeak:\nFormals: rect:struct CGRect \nLocals: path1:struct CGPath * lineThickness:double \n DECLARE_LOCALS(&return,&path1,&lineThickness); [line 58]\n NULLIFY(&lineThickness,false); [line 58]\n NULLIFY(&path1,false); [line 58]\n " color=yellow style=filled] 31 -> 35 ; -30 [label="30: DeclStmt \n n$22=*&rect:struct CGRect [line 55]\n n$23=_fun_CGRectGetHeight(n$22:struct CGRect ) [line 55]\n *&lineThickness:double =(0.200000 * n$23) [line 55]\n REMOVE_TEMPS(n$22,n$23); [line 55]\n NULLIFY(&rect,false); [line 55]\n NULLIFY(&lineThickness,false); [line 55]\n " shape="box"] +30 [label="30: BinaryOperatorStmt: Mul \n n$22=*&rect:struct CGRect [line 54]\n n$23=_fun_CGRectGetHeight(n$22:struct CGRect ) [line 54]\n REMOVE_TEMPS(n$22,n$23); [line 54]\n NULLIFY(&rect,false); [line 54]\n " shape="box"] 30 -> 29 ; -29 [label="29: DeclStmt \n n$21=_fun_CGPathCreateMutable() [line 58]\n *&path1:struct CGPath *=n$21 [line 58]\n REMOVE_TEMPS(n$21); [line 58]\n NULLIFY(&path1,false); [line 58]\n APPLY_ABSTRACTION; [line 58]\n " shape="box"] +29 [label="29: Call _fun_CGPathCreateMutable \n n$21=_fun_CGPathCreateMutable() [line 55]\n REMOVE_TEMPS(n$21); [line 55]\n APPLY_ABSTRACTION; [line 55]\n " shape="box"] 29 -> 28 ; 28 [label="28: Exit MemoryLeakExample_createCloseCrossGlyph: \n " color=yellow style=filled] -27 [label="27: Start MemoryLeakExample_createCloseCrossGlyph:\nFormals: rect:struct CGRect \nLocals: path1:struct CGPath * lineThickness:double \n DECLARE_LOCALS(&return,&path1,&lineThickness); [line 54]\n NULLIFY(&lineThickness,false); [line 54]\n NULLIFY(&path1,false); [line 54]\n " color=yellow style=filled] +27 [label="27: Start MemoryLeakExample_createCloseCrossGlyph:\nFormals: rect:struct CGRect \nLocals: \n DECLARE_LOCALS(&return); [line 53]\n " color=yellow style=filled] 27 -> 30 ; -26 [label="26: DeclStmt \n n$20=_fun_CTFramesetterCreateWithAttributedString(0:struct __CFAttributedString *) [line 50]\n *&framesetter:struct __CTFramesetter *=n$20 [line 50]\n REMOVE_TEMPS(n$20); [line 50]\n " shape="box"] +26 [label="26: DeclStmt \n n$20=_fun_CTFramesetterCreateWithAttributedString(0:struct __CFAttributedString *) [line 49]\n *&framesetter:struct __CTFramesetter *=n$20 [line 49]\n REMOVE_TEMPS(n$20); [line 49]\n " shape="box"] 26 -> 25 ; -25 [label="25: Call _fun___objc_release_cf \n n$19=*&framesetter:struct __CTFramesetter * [line 51]\n _fun___objc_release_cf(1:_Bool ,n$19:void *) [line 51]\n REMOVE_TEMPS(n$19); [line 51]\n NULLIFY(&framesetter,false); [line 51]\n APPLY_ABSTRACTION; [line 51]\n " shape="box"] +25 [label="25: Call _fun___objc_release_cf \n n$19=*&framesetter:struct __CTFramesetter * [line 50]\n _fun___objc_release_cf(1:_Bool ,n$19:void *) [line 50]\n REMOVE_TEMPS(n$19); [line 50]\n NULLIFY(&framesetter,false); [line 50]\n APPLY_ABSTRACTION; [line 50]\n " shape="box"] 25 -> 24 ; 24 [label="24: Exit MemoryLeakExample_test1NoLeak \n " color=yellow style=filled] -23 [label="23: Start MemoryLeakExample_test1NoLeak\nFormals: \nLocals: framesetter:struct __CTFramesetter * \n DECLARE_LOCALS(&return,&framesetter); [line 49]\n NULLIFY(&framesetter,false); [line 49]\n " color=yellow style=filled] +23 [label="23: Start MemoryLeakExample_test1NoLeak\nFormals: \nLocals: framesetter:struct __CTFramesetter * \n DECLARE_LOCALS(&return,&framesetter); [line 48]\n NULLIFY(&framesetter,false); [line 48]\n " color=yellow style=filled] 23 -> 26 ; -22 [label="22: DeclStmt \n n$17=*&str:struct __CFAttributedString * [line 46]\n n$18=_fun_CTFramesetterCreateWithAttributedString(n$17:struct __CFAttributedString *) [line 46]\n *&framesetter:struct __CTFramesetter *=n$18 [line 46]\n REMOVE_TEMPS(n$17,n$18); [line 46]\n NULLIFY(&framesetter,false); [line 46]\n NULLIFY(&str,false); [line 46]\n APPLY_ABSTRACTION; [line 46]\n " shape="box"] +22 [label="22: Call _fun_CTFramesetterCreateWithAttributedString \n n$17=*&str:struct __CFAttributedString * [line 45]\n n$18=_fun_CTFramesetterCreateWithAttributedString(n$17:struct __CFAttributedString *) [line 45]\n REMOVE_TEMPS(n$17,n$18); [line 45]\n NULLIFY(&str,false); [line 45]\n APPLY_ABSTRACTION; [line 45]\n " shape="box"] 22 -> 21 ; 21 [label="21: Exit MemoryLeakExample_test1: \n " color=yellow style=filled] -20 [label="20: Start MemoryLeakExample_test1:\nFormals: str:struct __CFAttributedString *\nLocals: framesetter:struct __CTFramesetter * \n DECLARE_LOCALS(&return,&framesetter); [line 45]\n NULLIFY(&framesetter,false); [line 45]\n " color=yellow style=filled] +20 [label="20: Start MemoryLeakExample_test1:\nFormals: str:struct __CFAttributedString *\nLocals: \n DECLARE_LOCALS(&return); [line 44]\n " color=yellow style=filled] 20 -> 22 ; -19 [label="19: DeclStmt \n n$16=_fun_CFAttributedStringCreateMutable(0:struct __CFAllocator *,0:long ) [line 41]\n *&maString:struct __CFAttributedString *=n$16 [line 41]\n REMOVE_TEMPS(n$16); [line 41]\n " shape="box"] +19 [label="19: DeclStmt \n n$16=_fun_CFAttributedStringCreateMutable(0:struct __CFAllocator *,0:long ) [line 40]\n *&maString:struct __CFAttributedString *=n$16 [line 40]\n REMOVE_TEMPS(n$16); [line 40]\n " shape="box"] 19 -> 18 ; -18 [label="18: Call _fun___objc_release_cf \n n$15=*&maString:struct __CFAttributedString * [line 42]\n _fun___objc_release_cf(1:_Bool ,n$15:void *) [line 42]\n REMOVE_TEMPS(n$15); [line 42]\n NULLIFY(&maString,false); [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"] +18 [label="18: Call _fun___objc_release_cf \n n$15=*&maString:struct __CFAttributedString * [line 41]\n _fun___objc_release_cf(1:_Bool ,n$15:void *) [line 41]\n REMOVE_TEMPS(n$15); [line 41]\n NULLIFY(&maString,false); [line 41]\n APPLY_ABSTRACTION; [line 41]\n " shape="box"] 18 -> 17 ; 17 [label="17: Exit MemoryLeakExample_measureFrameSizeForTextNoLeak \n " color=yellow style=filled] -16 [label="16: Start MemoryLeakExample_measureFrameSizeForTextNoLeak\nFormals: \nLocals: maString:struct __CFAttributedString * \n DECLARE_LOCALS(&return,&maString); [line 39]\n NULLIFY(&maString,false); [line 39]\n " color=yellow style=filled] +16 [label="16: Start MemoryLeakExample_measureFrameSizeForTextNoLeak\nFormals: \nLocals: maString:struct __CFAttributedString * \n DECLARE_LOCALS(&return,&maString); [line 38]\n NULLIFY(&maString,false); [line 38]\n " color=yellow style=filled] 16 -> 19 ; -15 [label="15: DeclStmt \n n$14=_fun_CFAttributedStringCreateMutable(0:struct __CFAllocator *,0:long ) [line 36]\n *&maString:struct __CFAttributedString *=n$14 [line 36]\n REMOVE_TEMPS(n$14); [line 36]\n NULLIFY(&maString,false); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"] +15 [label="15: Call _fun_CFAttributedStringCreateMutable \n n$14=_fun_CFAttributedStringCreateMutable(0:struct __CFAllocator *,0:long ) [line 35]\n REMOVE_TEMPS(n$14); [line 35]\n APPLY_ABSTRACTION; [line 35]\n " shape="box"] 15 -> 14 ; 14 [label="14: Exit MemoryLeakExample_measureFrameSizeForText \n " color=yellow style=filled] -13 [label="13: Start MemoryLeakExample_measureFrameSizeForText\nFormals: \nLocals: maString:struct __CFAttributedString * \n DECLARE_LOCALS(&return,&maString); [line 34]\n NULLIFY(&maString,false); [line 34]\n " color=yellow style=filled] +13 [label="13: Start MemoryLeakExample_measureFrameSizeForText\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 34]\n " color=yellow style=filled] 13 -> 15 ; diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.m index 30077ad0c..d1c0f09bb 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.m +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakExample.m @@ -32,8 +32,7 @@ } + (void)measureFrameSizeForText { - CFMutableAttributedStringRef maString = - CFAttributedStringCreateMutable(nil, 0); + CFAttributedStringCreateMutable(nil, 0); } + (void)measureFrameSizeForTextNoLeak { @@ -43,7 +42,7 @@ } + (void)test1:(CFAttributedStringRef)str { - CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(str); + CTFramesetterCreateWithAttributedString(str); } + (void)test1NoLeak { @@ -52,10 +51,8 @@ } + (void)createCloseCrossGlyph:(CGRect)rect { - CGFloat lineThickness = 0.20f * CGRectGetHeight(rect); - - // One rectangle - CGMutablePathRef path1 = CGPathCreateMutable(); + 0.20f * CGRectGetHeight(rect); + CGPathCreateMutable(); } + (void)createCloseCrossGlyphNoLeak:(CGRect)rect { @@ -67,7 +64,7 @@ } + (void)test2:(SecTrustRef)trust { - SecKeyRef allowedPublicKey = SecTrustCopyPublicKey(trust); + SecTrustCopyPublicKey(trust); } + (void)test2NoLeak { @@ -87,4 +84,30 @@ CGColorRef FBColorCreateWithGray(CGFloat gray, CGFloat a); CGColorRelease(borderColor); } +- (int)regularLeak { + int* x = malloc(sizeof(int)); + *x = 7; + return *x; +} + +- (int)blockCapturedVarLeak { + int* x = malloc(sizeof(int)); + *x = 2; + int (^blk)(void) = ^() { + return *x; + }; + return blk(); +} + +- (int)blockFreeNoLeakTODO { + int* x = malloc(sizeof(int)); + *x = 2; + int (^blk)(void) = ^() { + int i = *x; + free(x); + return i; + }; + return blk(); +} + @end diff --git a/infer/tests/codetoanalyze/objc/frontend/block/BlockVar.dot b/infer/tests/codetoanalyze/objc/frontend/block/BlockVar.dot index e29ff68b5..584b17ad8 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/BlockVar.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/BlockVar.dot @@ -7,11 +7,11 @@ digraph iCFG { 54 -> 53 ; -53 [label="53: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_capturedNoNullDeref______5); [line 59]\n n$37=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_capturedNoNullDeref______5 ):unsigned long ) [line 59]\n *&__objc_anonymous_block_BlockVar_capturedNoNullDeref______5:class __objc_anonymous_block_BlockVar_capturedNoNullDeref______5 =n$37 [line 59]\n n$38=*&x:int * [line 59]\n *n$37.x:int *=n$38 [line 59]\n n$34=*&x:int * [line 59]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_capturedNoNullDeref______5,n$34) [line 59]\n REMOVE_TEMPS(n$37,n$38,n$34); [line 59]\n " shape="box"] +53 [label="53: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_capturedNoNullDeref______5); [line 59]\n n$37=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_capturedNoNullDeref______5 ):unsigned long ) [line 59]\n *&__objc_anonymous_block_BlockVar_capturedNoNullDeref______5:class __objc_anonymous_block_BlockVar_capturedNoNullDeref______5 =n$37 [line 59]\n n$38=*&x:int * [line 59]\n *n$37.x:int *=n$38 [line 59]\n n$34=*&x:int * [line 59]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_capturedNoNullDeref______5,n$34) [line 59]\n REMOVE_TEMPS(n$37,n$38,n$34); [line 59]\n NULLIFY(&x,false); [line 59]\n " shape="box"] 53 -> 49 ; -52 [label="52: Return Stmt \n n$35=*&x:int * [line 60]\n n$36=*n$35:int [line 60]\n *&return:int =n$36 [line 60]\n REMOVE_TEMPS(n$35,n$36); [line 60]\n APPLY_ABSTRACTION; [line 60]\n " shape="box"] +52 [label="52: Return Stmt \n n$35=*&x:int * [line 60]\n n$36=*n$35:int [line 60]\n *&return:int =n$36 [line 60]\n REMOVE_TEMPS(n$35,n$36); [line 60]\n NULLIFY(&x,false); [line 60]\n APPLY_ABSTRACTION; [line 60]\n " shape="box"] 52 -> 51 ; @@ -22,7 +22,7 @@ digraph iCFG { 50 -> 52 ; -49 [label="49: BinaryOperatorStmt: Assign \n *&x:int *=0 [line 62]\n " shape="box"] +49 [label="49: BinaryOperatorStmt: Assign \n *&x:int *=0 [line 62]\n NULLIFY(&x,false); [line 62]\n " shape="box"] 49 -> 48 ; @@ -33,7 +33,7 @@ digraph iCFG { 47 [label="47: Exit BlockVar_capturedNoNullDeref \n " color=yellow style=filled] -46 [label="46: Start BlockVar_capturedNoNullDeref\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * i:int \n DECLARE_LOCALS(&return,&my_block,&x,&i); [line 56]\n NULLIFY(&my_block,false); [line 56]\n NULLIFY(&self,false); [line 56]\n " color=yellow style=filled] +46 [label="46: Start BlockVar_capturedNoNullDeref\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * i:int \n DECLARE_LOCALS(&return,&my_block,&x,&i); [line 56]\n NULLIFY(&my_block,false); [line 56]\n NULLIFY(&self,false); [line 56]\n NULLIFY(&x,false); [line 56]\n " color=yellow style=filled] 46 -> 55 ; @@ -41,11 +41,11 @@ digraph iCFG { 45 -> 44 ; -44 [label="44: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_capturedNullDeref______4); [line 50]\n n$30=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_capturedNullDeref______4 ):unsigned long ) [line 50]\n *&__objc_anonymous_block_BlockVar_capturedNullDeref______4:class __objc_anonymous_block_BlockVar_capturedNullDeref______4 =n$30 [line 50]\n n$31=*&x:int * [line 50]\n *n$30.x:int *=n$31 [line 50]\n n$27=*&x:int * [line 50]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_capturedNullDeref______4,n$27) [line 50]\n REMOVE_TEMPS(n$30,n$31,n$27); [line 50]\n " shape="box"] +44 [label="44: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_capturedNullDeref______4); [line 50]\n n$30=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_capturedNullDeref______4 ):unsigned long ) [line 50]\n *&__objc_anonymous_block_BlockVar_capturedNullDeref______4:class __objc_anonymous_block_BlockVar_capturedNullDeref______4 =n$30 [line 50]\n n$31=*&x:int * [line 50]\n *n$30.x:int *=n$31 [line 50]\n n$27=*&x:int * [line 50]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_capturedNullDeref______4,n$27) [line 50]\n REMOVE_TEMPS(n$30,n$31,n$27); [line 50]\n NULLIFY(&x,false); [line 50]\n " shape="box"] 44 -> 40 ; -43 [label="43: Return Stmt \n n$28=*&x:int * [line 51]\n n$29=*n$28:int [line 51]\n *&return:int =n$29 [line 51]\n REMOVE_TEMPS(n$28,n$29); [line 51]\n APPLY_ABSTRACTION; [line 51]\n " shape="box"] +43 [label="43: Return Stmt \n n$28=*&x:int * [line 51]\n n$29=*n$28:int [line 51]\n *&return:int =n$29 [line 51]\n REMOVE_TEMPS(n$28,n$29); [line 51]\n NULLIFY(&x,false); [line 51]\n APPLY_ABSTRACTION; [line 51]\n " shape="box"] 43 -> 42 ; @@ -63,7 +63,7 @@ digraph iCFG { 39 [label="39: Exit BlockVar_capturedNullDeref \n " color=yellow style=filled] -38 [label="38: Start BlockVar_capturedNullDeref\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * \n DECLARE_LOCALS(&return,&my_block,&x); [line 48]\n NULLIFY(&my_block,false); [line 48]\n NULLIFY(&self,false); [line 48]\n " color=yellow style=filled] +38 [label="38: Start BlockVar_capturedNullDeref\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * \n DECLARE_LOCALS(&return,&my_block,&x); [line 48]\n NULLIFY(&my_block,false); [line 48]\n NULLIFY(&self,false); [line 48]\n NULLIFY(&x,false); [line 48]\n " color=yellow style=filled] 38 -> 45 ; @@ -75,11 +75,11 @@ digraph iCFG { 36 -> 35 ; -35 [label="35: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_blockPostOk______3); [line 42]\n n$23=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_blockPostOk______3 ):unsigned long ) [line 42]\n *&__objc_anonymous_block_BlockVar_blockPostOk______3:class __objc_anonymous_block_BlockVar_blockPostOk______3 =n$23 [line 42]\n n$24=*&x:int * [line 42]\n *n$23.x:int *=n$24 [line 42]\n n$21=*&x:int * [line 42]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_blockPostOk______3,n$21) [line 42]\n REMOVE_TEMPS(n$23,n$24,n$21); [line 42]\n " shape="box"] +35 [label="35: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_blockPostOk______3); [line 42]\n n$23=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_blockPostOk______3 ):unsigned long ) [line 42]\n *&__objc_anonymous_block_BlockVar_blockPostOk______3:class __objc_anonymous_block_BlockVar_blockPostOk______3 =n$23 [line 42]\n n$24=*&x:int * [line 42]\n *n$23.x:int *=n$24 [line 42]\n n$21=*&x:int * [line 42]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_blockPostOk______3,n$21) [line 42]\n REMOVE_TEMPS(n$23,n$24,n$21); [line 42]\n NULLIFY(&x,false); [line 42]\n " shape="box"] 35 -> 31 ; -34 [label="34: Return Stmt \n n$22=*&x:int * [line 43]\n *&return:int *=n$22 [line 43]\n REMOVE_TEMPS(n$22); [line 43]\n APPLY_ABSTRACTION; [line 43]\n " shape="box"] +34 [label="34: Return Stmt \n n$22=*&x:int * [line 43]\n *&return:int *=n$22 [line 43]\n REMOVE_TEMPS(n$22); [line 43]\n NULLIFY(&x,false); [line 43]\n APPLY_ABSTRACTION; [line 43]\n " shape="box"] 34 -> 33 ; @@ -97,7 +97,7 @@ digraph iCFG { 30 [label="30: Exit BlockVar_blockPostOk \n " color=yellow style=filled] -29 [label="29: Start BlockVar_blockPostOk\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * i:int \n DECLARE_LOCALS(&return,&my_block,&x,&i); [line 39]\n NULLIFY(&my_block,false); [line 39]\n NULLIFY(&self,false); [line 39]\n " color=yellow style=filled] +29 [label="29: Start BlockVar_blockPostOk\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * i:int \n DECLARE_LOCALS(&return,&my_block,&x,&i); [line 39]\n NULLIFY(&my_block,false); [line 39]\n NULLIFY(&self,false); [line 39]\n NULLIFY(&x,false); [line 39]\n " color=yellow style=filled] 29 -> 37 ; @@ -105,11 +105,11 @@ digraph iCFG { 28 -> 27 ; -27 [label="27: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_blockPostBad______2); [line 33]\n n$16=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_blockPostBad______2 ):unsigned long ) [line 33]\n *&__objc_anonymous_block_BlockVar_blockPostBad______2:class __objc_anonymous_block_BlockVar_blockPostBad______2 =n$16 [line 33]\n n$17=*&x:int * [line 33]\n *n$16.x:int *=n$17 [line 33]\n n$14=*&x:int * [line 33]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_blockPostBad______2,n$14) [line 33]\n REMOVE_TEMPS(n$16,n$17,n$14); [line 33]\n " shape="box"] +27 [label="27: DeclStmt \n DECLARE_LOCALS(&__objc_anonymous_block_BlockVar_blockPostBad______2); [line 33]\n n$16=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_BlockVar_blockPostBad______2 ):unsigned long ) [line 33]\n *&__objc_anonymous_block_BlockVar_blockPostBad______2:class __objc_anonymous_block_BlockVar_blockPostBad______2 =n$16 [line 33]\n n$17=*&x:int * [line 33]\n *n$16.x:int *=n$17 [line 33]\n n$14=*&x:int * [line 33]\n *&my_block:_fn_ (*)=(_fun___objc_anonymous_block_BlockVar_blockPostBad______2,n$14) [line 33]\n REMOVE_TEMPS(n$16,n$17,n$14); [line 33]\n NULLIFY(&x,false); [line 33]\n " shape="box"] 27 -> 23 ; -26 [label="26: Return Stmt \n n$15=*&x:int * [line 34]\n *&return:int *=n$15 [line 34]\n REMOVE_TEMPS(n$15); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"] +26 [label="26: Return Stmt \n n$15=*&x:int * [line 34]\n *&return:int *=n$15 [line 34]\n REMOVE_TEMPS(n$15); [line 34]\n NULLIFY(&x,false); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"] 26 -> 25 ; @@ -127,7 +127,7 @@ digraph iCFG { 22 [label="22: Exit BlockVar_blockPostBad \n " color=yellow style=filled] -21 [label="21: Start BlockVar_blockPostBad\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * \n DECLARE_LOCALS(&return,&my_block,&x); [line 31]\n NULLIFY(&my_block,false); [line 31]\n NULLIFY(&self,false); [line 31]\n " color=yellow style=filled] +21 [label="21: Start BlockVar_blockPostBad\nFormals: self:class BlockVar *\nLocals: my_block:_fn_ (*) x:int * \n DECLARE_LOCALS(&return,&my_block,&x); [line 31]\n NULLIFY(&my_block,false); [line 31]\n NULLIFY(&self,false); [line 31]\n NULLIFY(&x,false); [line 31]\n " color=yellow style=filled] 21 -> 28 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/block.dot b/infer/tests/codetoanalyze/objc/frontend/block/block.dot index 5c077403b..ee1ee858b 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 18]\n n$27=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_main1______2 ):unsigned long ) [line 18]\n *&__objc_anonymous_block_main1______2:class __objc_anonymous_block_main1______2 =n$27 [line 18]\n n$28=*&x:int [line 18]\n *n$27.x:int =n$28 [line 18]\n n$11=*&x:int [line 18]\n *&addblock:_fn_ (*)=(_fun___objc_anonymous_block_main1______2,n$11) [line 18]\n REMOVE_TEMPS(n$27,n$28,n$11); [line 18]\n " shape="box"] +20 [label="20: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_main1______2); [line 18]\n n$27=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_main1______2 ):unsigned long ) [line 18]\n *&__objc_anonymous_block_main1______2:class __objc_anonymous_block_main1______2 =n$27 [line 18]\n n$28=*&x:int [line 18]\n *n$27.x:int =n$28 [line 18]\n n$11=*&x:int [line 18]\n *&addblock:_fn_ (*)=(_fun___objc_anonymous_block_main1______2,n$11) [line 18]\n REMOVE_TEMPS(n$27,n$28,n$11); [line 18]\n NULLIFY(&x,false); [line 18]\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 24]\n n$23=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block___objc_anonymous_block_main1______2______3 ):unsigned long ) [line 24]\n *&__objc_anonymous_block___objc_anonymous_block_main1______2______3:class __objc_anonymous_block___objc_anonymous_block_main1______2______3 =n$23 [line 24]\n n$24=*&x:int [line 24]\n n$25=*&bla:int [line 24]\n n$26=*&#GB$main1_s:int [line 24]\n *n$23.x:int =n$24 [line 24]\n *n$23.bla:int =n$25 [line 24]\n *n$23.main1_s:int =n$26 [line 24]\n n$17=*&x:int [line 24]\n n$18=*&bla:int [line 24]\n *&addblock2:_fn_ (*)=(_fun___objc_anonymous_block___objc_anonymous_block_main1______2______3,n$17,n$18) [line 24]\n REMOVE_TEMPS(n$23,n$24,n$25,n$26,n$17,n$18); [line 24]\n " shape="box"] +18 [label="18: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block___objc_anonymous_block_main1______2______3); [line 24]\n n$23=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block___objc_anonymous_block_main1______2______3 ):unsigned long ) [line 24]\n *&__objc_anonymous_block___objc_anonymous_block_main1______2______3:class __objc_anonymous_block___objc_anonymous_block_main1______2______3 =n$23 [line 24]\n n$24=*&x:int [line 24]\n n$25=*&bla:int [line 24]\n n$26=*&#GB$main1_s:int [line 24]\n *n$23.x:int =n$24 [line 24]\n *n$23.bla:int =n$25 [line 24]\n *n$23.main1_s:int =n$26 [line 24]\n n$17=*&x:int [line 24]\n n$18=*&bla:int [line 24]\n *&addblock2:_fn_ (*)=(_fun___objc_anonymous_block___objc_anonymous_block_main1______2______3,n$17,n$18) [line 24]\n REMOVE_TEMPS(n$23,n$24,n$25,n$26,n$17,n$18); [line 24]\n NULLIFY(&x,false); [line 24]\n " shape="box"] 18 -> 14 ; -17 [label="17: Return Stmt \n n$19=*&z:int [line 25]\n n$20=*&#GB$main1_s:int [line 25]\n n$21=*&x:int [line 25]\n n$22=*&bla:int [line 25]\n *&return:int =(((n$19 + n$20) + n$21) + n$22) [line 25]\n REMOVE_TEMPS(n$19,n$20,n$21,n$22); [line 25]\n NULLIFY(&z,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] +17 [label="17: Return Stmt \n n$19=*&z:int [line 25]\n n$20=*&#GB$main1_s:int [line 25]\n n$21=*&x:int [line 25]\n n$22=*&bla:int [line 25]\n *&return:int =(((n$19 + n$20) + n$21) + n$22) [line 25]\n REMOVE_TEMPS(n$19,n$20,n$21,n$22); [line 25]\n NULLIFY(&bla,false); [line 25]\n NULLIFY(&x,false); [line 25]\n NULLIFY(&z,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] 17 -> 16 ; @@ -45,14 +45,14 @@ digraph iCFG { 14 -> 13 ; -13 [label="13: Return Stmt \n n$12=*&c:int [line 29]\n n$13=*&add2:int [line 29]\n n$14=*&bla:int [line 29]\n *&return:int =((n$12 + n$13) + n$14) [line 29]\n REMOVE_TEMPS(n$12,n$13,n$14); [line 29]\n NULLIFY(&__objc_anonymous_block___objc_anonymous_block_main1______2______3,true); [line 29]\n NULLIFY(&add2,false); [line 29]\n NULLIFY(&c,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"] +13 [label="13: Return Stmt \n n$12=*&c:int [line 29]\n n$13=*&add2:int [line 29]\n n$14=*&bla:int [line 29]\n *&return:int =((n$12 + n$13) + n$14) [line 29]\n REMOVE_TEMPS(n$12,n$13,n$14); [line 29]\n NULLIFY(&__objc_anonymous_block___objc_anonymous_block_main1______2______3,true); [line 29]\n NULLIFY(&add2,false); [line 29]\n NULLIFY(&bla,false); [line 29]\n NULLIFY(&c,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"] 13 -> 12 ; 12 [label="12: Exit __objc_anonymous_block_main1______2 \n " color=yellow style=filled] -11 [label="11: Start __objc_anonymous_block_main1______2\nFormals: x:int c:int d:int \nLocals: bla:int add2:int addblock2:_fn_ (*)\nCaptured: x:int \n DECLARE_LOCALS(&return,&bla,&add2,&addblock2); [line 18]\n NULLIFY(&add2,false); [line 18]\n NULLIFY(&addblock2,false); [line 18]\n NULLIFY(&d,false); [line 18]\n " color=yellow style=filled] +11 [label="11: Start __objc_anonymous_block_main1______2\nFormals: x:int c:int d:int \nLocals: bla:int add2:int addblock2:_fn_ (*)\nCaptured: x:int \n DECLARE_LOCALS(&return,&bla,&add2,&addblock2); [line 18]\n NULLIFY(&add2,false); [line 18]\n NULLIFY(&addblock2,false); [line 18]\n NULLIFY(&bla,false); [line 18]\n NULLIFY(&d,false); [line 18]\n " color=yellow style=filled] 11 -> 19 ; @@ -90,7 +90,7 @@ digraph iCFG { 2 [label="2: Exit main1 \n " color=yellow style=filled] -1 [label="1: Start main1\nFormals: y:int \nLocals: addblock:_fn_ (*) add2:int add1:int x:int \n DECLARE_LOCALS(&return,&addblock,&add2,&add1,&x); [line 10]\n NULLIFY(&add1,false); [line 10]\n NULLIFY(&add2,false); [line 10]\n NULLIFY(&addblock,false); [line 10]\n NULLIFY(&y,false); [line 10]\n " color=yellow style=filled] +1 [label="1: Start main1\nFormals: y:int \nLocals: addblock:_fn_ (*) add2:int add1:int x:int \n DECLARE_LOCALS(&return,&addblock,&add2,&add1,&x); [line 10]\n NULLIFY(&add1,false); [line 10]\n NULLIFY(&add2,false); [line 10]\n NULLIFY(&addblock,false); [line 10]\n NULLIFY(&x,false); [line 10]\n NULLIFY(&y,false); [line 10]\n " color=yellow style=filled] 1 -> 22 ; 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 4a90c63b4..d4265d1ca 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot @@ -11,7 +11,7 @@ digraph iCFG { 16 -> 12 ; -15 [label="15: BinaryOperatorStmt: Assign \n n$6=*&z:int [line 26]\n *&#GB$g:int =(n$6 + 3) [line 26]\n REMOVE_TEMPS(n$6); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] +15 [label="15: BinaryOperatorStmt: Assign \n n$6=*&z:int [line 26]\n *&#GB$g:int =(n$6 + 3) [line 26]\n REMOVE_TEMPS(n$6); [line 26]\n NULLIFY(&z,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] 15 -> 14 ; @@ -30,11 +30,11 @@ digraph iCFG { 11 -> 6 ; -10 [label="10: Return Stmt \n NULLIFY(&p,false); [line 33]\n n$3=*&z:int [line 33]\n *&return:int =n$3 [line 33]\n REMOVE_TEMPS(n$3); [line 33]\n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] +10 [label="10: Return Stmt \n NULLIFY(&p,false); [line 33]\n n$3=*&z:int [line 33]\n *&return:int =n$3 [line 33]\n REMOVE_TEMPS(n$3); [line 33]\n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 33]\n NULLIFY(&z,false); [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] 10 -> 4 ; -9 [label="9: Return Stmt \n n$1=*&p:int * [line 31]\n n$2=*n$1:int [line 31]\n *&return:int =n$2 [line 31]\n REMOVE_TEMPS(n$1,n$2); [line 31]\n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 31]\n NULLIFY(&p,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] +9 [label="9: Return Stmt \n NULLIFY(&z,false); [line 31]\n n$1=*&p:int * [line 31]\n n$2=*n$1:int [line 31]\n *&return:int =n$2 [line 31]\n REMOVE_TEMPS(n$1,n$2); [line 31]\n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 31]\n NULLIFY(&p,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] 9 -> 4 ; @@ -51,14 +51,14 @@ digraph iCFG { 6 -> 7 ; 6 -> 8 ; -5 [label="5: + \n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 30]\n NULLIFY(&b,false); [line 30]\n NULLIFY(&p,false); [line 30]\n NULLIFY(&self,false); [line 30]\n " ] +5 [label="5: + \n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 30]\n NULLIFY(&b,false); [line 30]\n NULLIFY(&p,false); [line 30]\n NULLIFY(&self,false); [line 30]\n NULLIFY(&z,false); [line 30]\n " ] 5 -> 4 ; 4 [label="4: Exit My_manager_m \n " color=yellow style=filled] -3 [label="3: Start My_manager_m\nFormals: self:class My_manager *\nLocals: p:int * z:int b:_fn_ (*) \n DECLARE_LOCALS(&return,&p,&z,&b); [line 21]\n NULLIFY(&b,false); [line 21]\n NULLIFY(&p,false); [line 21]\n NULLIFY(&self,false); [line 21]\n " color=yellow style=filled] +3 [label="3: Start My_manager_m\nFormals: self:class My_manager *\nLocals: p:int * z:int b:_fn_ (*) \n DECLARE_LOCALS(&return,&p,&z,&b); [line 21]\n NULLIFY(&b,false); [line 21]\n NULLIFY(&p,false); [line 21]\n NULLIFY(&self,false); [line 21]\n NULLIFY(&z,false); [line 21]\n " color=yellow style=filled] 3 -> 18 ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/block_release.m b/infer/tests/codetoanalyze/objc/frontend/block/block_release.m index fac89f398..ccaf983c7 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/block_release.m +++ b/infer/tests/codetoanalyze/objc/frontend/block/block_release.m @@ -11,13 +11,13 @@ #import @interface My_manager : NSObject -- (int)my_mehtod; +- (int)my_method; @end @implementation My_manager -- (int)m { +- (int)blockReleaseTODO { void (^b)(int a); int z = 3; CGContextRef context = CGBitmapContextCreate(NULL, 0, 0, 8, 0, 0, 0); @@ -26,7 +26,7 @@ if (newImage) CGImageRelease(newImage); }; - b(z); + b(z); // currently doesn't work due to PRECONDITION_NOT_MET here if (context) CGContextRelease(context); return z; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.dot b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.dot index 480faeacc..2685ef349 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.dot @@ -41,7 +41,7 @@ digraph iCFG { 13 -> 9 ; -12 [label="12: BinaryOperatorStmt: Assign \n n$3=*&self:class A * [line 48]\n n$4=*&d:class D * [line 48]\n *n$3._data:class D *=n$4 [line 48]\n REMOVE_TEMPS(n$3,n$4); [line 48]\n NULLIFY(&d,false); [line 48]\n APPLY_ABSTRACTION; [line 48]\n " shape="box"] +12 [label="12: BinaryOperatorStmt: Assign \n n$3=*&self:class A * [line 48]\n n$4=*&d:class D * [line 48]\n *n$3._data:class D *=n$4 [line 48]\n REMOVE_TEMPS(n$3,n$4); [line 48]\n NULLIFY(&d,false); [line 48]\n NULLIFY(&self,false); [line 48]\n APPLY_ABSTRACTION; [line 48]\n " shape="box"] 12 -> 11 ; diff --git a/infer/tests/endtoend/objc/BlockReleaseTest.java b/infer/tests/endtoend/objc/BlockReleaseTest.java index 98d0c8e63..ff9c252d3 100644 --- a/infer/tests/endtoend/objc/BlockReleaseTest.java +++ b/infer/tests/endtoend/objc/BlockReleaseTest.java @@ -45,7 +45,9 @@ public class BlockReleaseTest { public void whenInferRunsOnMnThenMemoryLeakIsNotFound() throws InterruptedException, IOException, InferException { InferResults inferResults = InferRunner.runInferObjC(inferCmd); - String[] procedures = { // no memory leak found + String[] procedures = { + // TODO: don't report on this test + "blockReleaseTODO" }; assertThat( "Results should contain the expected memory leak", diff --git a/infer/tests/endtoend/objc/MemoryLeakTest.java b/infer/tests/endtoend/objc/MemoryLeakTest.java index e815b3a33..d0508bb00 100644 --- a/infer/tests/endtoend/objc/MemoryLeakTest.java +++ b/infer/tests/endtoend/objc/MemoryLeakTest.java @@ -10,8 +10,7 @@ package endtoend.objc; import static org.hamcrest.MatcherAssert.assertThat; -import static utils.matchers.ResultContainsErrorInMethod.contains; -import static utils.matchers.ResultContainsNoErrorInMethod.doesNotContain; +import static utils.matchers.ResultContainsExactly.containsExactly; import com.google.common.collect.ImmutableList; @@ -49,144 +48,30 @@ public class MemoryLeakTest { false); } - @Test - public void whenInferRunsOnLayoutSubviewsThenMLIsNotFound() + @Test + public void matchErrors() throws InterruptedException, IOException, InferException { InferResults inferResults = InferRunner.runInferObjC(inferCmd); + String[] procedures = { + "test", + "measureFrameSizeForText", + "test1:", + "createCloseCrossGlyph:", + "test2:", + "regularLeak", + "blockCapturedVarLeak", + // TODO: don't report on this test + "blockFreeNoLeakTODO" + }; assertThat( - "Results should not contain memory leak", + "Results should contain the expected memory leak", inferResults, - doesNotContain( + containsExactly( MEMORY_LEAK, memory_leak_file, - "layoutSubviews")); - } - - @Test - public void whenInferRunsOnTestThenMLIsFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should contain memory leak", - inferResults, - contains( - MEMORY_LEAK, - memory_leak_file, - "test" - ) - ); - } - - @Test - public void whenInferRunsOnMeasureFrameSizeForTextThenMLIsFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should contain memory leak", - inferResults, - contains( - MEMORY_LEAK, - memory_leak_file, - "measureFrameSizeForText" - ) - ); - } - - @Test - public void whenInferRunsOnMeasureFrameSizeForTextNoLeakThenMLIsFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should not contain a memory leak", - inferResults, - doesNotContain( - MEMORY_LEAK, - memory_leak_file, - "measureFrameSizeForTextNoLeak")); - } - - @Test - public void whenInferRunsOnTest1ThenMLIsFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should contain memory leak", - inferResults, - contains( - MEMORY_LEAK, - memory_leak_file, - "test1:" - ) - ); - } - - @Test - public void whenInferRunsOnTest1NoLeakThenMLIsFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should not contain a memory leak", - inferResults, - doesNotContain( - MEMORY_LEAK, - memory_leak_file, - "test1NoLeak")); - } - - @Test - public void whenInferRunsOn_createCloseCrossGlyphWithRectThenMLIsFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should contain memory leak", - inferResults, - contains( - MEMORY_LEAK, - memory_leak_file, - "createCloseCrossGlyph:" - ) - ); - } - - @Test - public void whenInferRunsOn_createCloseCrossGlyphWithRectNoLeakThenMLIsNotFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should not contain a memory leak", - inferResults, - doesNotContain( - MEMORY_LEAK, - memory_leak_file, - "createCloseCrossGlyphNoLeak:")); - } - - @Test - public void whenInferRunsOnTest2ThenMLIFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should contain memory leak", - inferResults, - contains( - MEMORY_LEAK, - memory_leak_file, - "test2:" + procedures ) ); } - @Test - public void whenInferTest2NoLakNoLeakThenMLIsNotFound() - throws InterruptedException, IOException, InferException { - InferResults inferResults = InferRunner.runInferObjC(inferCmd); - assertThat( - "Results should not contain a memory leak", - inferResults, - doesNotContain( - MEMORY_LEAK, - memory_leak_file, - "test2NoLeak")); - } - }