diff --git a/infer/src/cost/cost.ml b/infer/src/cost/cost.ml index 7ca209885..3d35294a2 100644 --- a/infer/src/cost/cost.ml +++ b/infer/src/cost/cost.ml @@ -56,6 +56,15 @@ module InstrBasicCostWithReason = struct String.equal (Procname.get_method callee_pname) "autorelease" + (** The methods whose name start with one of the prefixes return an object that is owned by the + caller. Therefore ARC will not add any objects they return into an autorelease pool. *) + let return_object_owned_by_caller = + let prefixes = ["alloc"; "new"; "copy"; "mutableCopy"] in + fun callee_pname -> + let method_name = Procname.get_method callee_pname in + List.exists prefixes ~f:(fun prefix -> String.is_prefix method_name ~prefix) + + let is_objc_call_from_no_arc_to_arc {proc_resolve_attributes} caller_pdesc callee_pname = (not (Procdesc.is_objc_arc_on caller_pdesc)) && Option.exists (proc_resolve_attributes callee_pname) @@ -127,6 +136,7 @@ module InstrBasicCostWithReason = struct else if is_objc_call_from_no_arc_to_arc extras cfg callee_pname && Typ.is_pointer_to_objc_class ret_typ + && not (return_object_owned_by_caller callee_pname) then let autoreleasepool_trace = Bounds.BoundTrace.of_arc_from_non_arc (Procname.to_string callee_pname) location diff --git a/infer/tests/codetoanalyze/objc/autoreleasepool/cost-issues.exp b/infer/tests/codetoanalyze/objc/autoreleasepool/cost-issues.exp index f7620d2c8..dce262f7a 100644 --- a/infer/tests/codetoanalyze/objc/autoreleasepool/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/autoreleasepool/cost-issues.exp @@ -34,11 +34,11 @@ codetoanalyze/objc/autoreleasepool/no_arc_callee.m, NoArcCallee.dealloc, 0, OnU codetoanalyze/objc/autoreleasepool/no_arc_callee.m, NoArcCallee.giveMeObject, 1, OnUIThread:false, [autorelease,Modeled call to autorelease] codetoanalyze/objc/autoreleasepool/no_arc_callee.m, NoArcCallee.mutableCopyObject:, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/no_arc_callee.m, NoArcCallee.newObject, 0, OnUIThread:false, [] -codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callAllocObject_zero_FP:, n, OnUIThread:false, [{n},Loop,autorelease,ARC function call to ArcCallee.allocObject from non-ARC caller] -codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callCopyObject_zero_FP:x:, n, OnUIThread:false, [{n},Loop,autorelease,ARC function call to ArcCallee.copyObject: from non-ARC caller] +codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callAllocObject_zero:, 0, OnUIThread:false, [] +codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callCopyObject_zero:x:, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callGiveMeInt_zero, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callGiveMeObject_autoreleasepool_zero:, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callGiveMeObject_linear:, n, OnUIThread:false, [{n},Loop,autorelease,ARC function call to ArcCallee.giveMeObject from non-ARC caller] -codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callMutableCopyObject_zero_FP:x:, n, OnUIThread:false, [{n},Loop,autorelease,ARC function call to ArcCallee.mutableCopyObject: from non-ARC caller] -codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callNewObject_zero_FP:, n, OnUIThread:false, [{n},Loop,autorelease,ARC function call to ArcCallee.newObject from non-ARC caller] +codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callMutableCopyObject_zero:x:, 0, OnUIThread:false, [] +codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.callNewObject_zero:, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/no_arc_caller.m, NoArcCaller.dealloc, 0, OnUIThread:false, [] diff --git a/infer/tests/codetoanalyze/objc/autoreleasepool/no_arc_caller.m b/infer/tests/codetoanalyze/objc/autoreleasepool/no_arc_caller.m index 5a04669cd..dbf2fabb1 100644 --- a/infer/tests/codetoanalyze/objc/autoreleasepool/no_arc_caller.m +++ b/infer/tests/codetoanalyze/objc/autoreleasepool/no_arc_caller.m @@ -12,25 +12,25 @@ @implementation NoArcCaller -- (void)callAllocObject_zero_FP:(int)n { +- (void)callAllocObject_zero:(int)n { for (int i = 0; i < n; i++) { ArcCallee* obj = [ArcCallee allocObject]; } } -- (void)callNewObject_zero_FP:(int)n { +- (void)callNewObject_zero:(int)n { for (int i = 0; i < n; i++) { ArcCallee* obj = [ArcCallee newObject]; } } -- (void)callCopyObject_zero_FP:(int)n x:(ArcCallee*)x { +- (void)callCopyObject_zero:(int)n x:(ArcCallee*)x { for (int i = 0; i < n; i++) { ArcCallee* obj = [ArcCallee copyObject:x]; } } -- (void)callMutableCopyObject_zero_FP:(int)n x:(ArcCallee*)x { +- (void)callMutableCopyObject_zero:(int)n x:(ArcCallee*)x { for (int i = 0; i < n; i++) { ArcCallee* obj = [ArcCallee mutableCopyObject:x]; }