From 3df2bbba9659170f43af00c193b8fede739ffd38 Mon Sep 17 00:00:00 2001 From: Sungkeun Cho Date: Tue, 27 Oct 2020 06:49:00 -0700 Subject: [PATCH] [cost] Fix on-demand generation of NSEnumerator Summary: This diff fixes on-demand symbolic value generation of a class that inherits NSEnumerator. Reviewed By: ngorogiannis Differential Revision: D24504955 fbshipit-source-id: bcb20e8aa --- infer/src/bufferoverrun/bufferOverrunDomain.ml | 3 ++- infer/tests/codetoanalyze/objc/performance/NSArray.m | 7 +++++++ infer/tests/codetoanalyze/objc/performance/cost-issues.exp | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/infer/src/bufferoverrun/bufferOverrunDomain.ml b/infer/src/bufferoverrun/bufferOverrunDomain.ml index 4be57ddfc..2433977a9 100644 --- a/infer/src/bufferoverrun/bufferOverrunDomain.ml +++ b/infer/src/bufferoverrun/bufferOverrunDomain.ml @@ -563,7 +563,8 @@ module Val = struct itv_val ~non_int:false |> set_itv_updated_by_addition | Tptr ({desc= Tfun}, _) -> of_func_ptrs (FuncPtr.Set.of_path path) - | Tptr ({desc= Tstruct name}, _) when Typ.equal_name name Typ.Name.Objc.objc_ns_enumerator -> + | Tptr ({desc= Tstruct name}, _) + when PatternMatch.is_subtype tenv name Typ.Name.Objc.objc_ns_enumerator -> (* NOTE: It generates a value of NSEnumerator specifically. Especially, it assigns zero to the offset, rather than a symbol, to avoid precision loss by limited handling of symbolic values in the domain. Although this is an unsound design choice, we expect it should not diff --git a/infer/tests/codetoanalyze/objc/performance/NSArray.m b/infer/tests/codetoanalyze/objc/performance/NSArray.m index b6ebe5101..04100fd14 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSArray.m +++ b/infer/tests/codetoanalyze/objc/performance/NSArray.m @@ -220,3 +220,10 @@ void call_my_enumerator_next_object_linear(MyEnumerator* enumerator) { // NSEnumerator.nextObject should be replaced to MyEnumerator.nextObject NSString* s = [enumerator nextObject]; } + +// The cost analyzer cannot reason the amortized complexity. +void loop_with_my_enumerator_next_object_linear_FP(MyEnumerator* enumerator) { + NSString* s; + while (s = [enumerator nextObject]) { + } +} diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index e36fbe542..8e05a1372 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -1,8 +1,9 @@ ${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.indexOfObject:inSortedRange:options:usingComparator:[objc_blocknsarray_binary_search_log_FN_1], 0, OnUIThread:false, [] codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.dealloc, 1, OnUIThread:false, [] -codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.nextObject, 6 + 3 ⋅ self->n + 3 ⋅ (1+max(0, self->n)), OnUIThread:false, [{1+max(0, self->n)},Loop,{self->n},Loop] +codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.nextObject, 6 + 3 ⋅ self->n.ub + 3 ⋅ (1+max(0, self->n.ub)), OnUIThread:false, [{1+max(0, self->n.ub)},Loop,{self->n.ub},Loop] codetoanalyze/objc/performance/NSArray.m, call_my_enumerator_next_object_linear, 9 + 3 ⋅ enumerator->n.ub + 3 ⋅ (1+max(0, enumerator->n.ub)), OnUIThread:false, [{1+max(0, enumerator->n.ub)},Call to MyEnumerator.nextObject,Loop,{enumerator->n.ub},Call to MyEnumerator.nextObject,Loop] codetoanalyze/objc/performance/NSArray.m, call_nsarray_enumerator_param_linear, 6, OnUIThread:false, [] +codetoanalyze/objc/performance/NSArray.m, loop_with_my_enumerator_next_object_linear_FP, 2 + 3 ⋅ enumerator->n.ub × (enumerator.length + 1) + 10 ⋅ (enumerator.length + 1) + 3 ⋅ (enumerator.length + 1) × (1+max(0, enumerator->n.ub)), OnUIThread:false, [{1+max(0, enumerator->n.ub)},Call to MyEnumerator.nextObject,Loop,{enumerator.length + 1},Loop,{enumerator.length + 1},Loop,{enumerator->n.ub},Call to MyEnumerator.nextObject,Loop] codetoanalyze/objc/performance/NSArray.m, multiple_nsarray_enumerators_param_linear, 12 + 5 ⋅ (enumerator2.length + enumerator1.length + 2), OnUIThread:false, [{enumerator2.length + enumerator1.length + 2},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 50, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]