diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index 2c3de412c..ab43652b3 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -1087,6 +1087,25 @@ module NSCollection = struct {exec; check= no_check} + let new_collection_of_size coll_id size_exp = + let exec ({integer_type_widths} as model_env) ~ret:((id, _) as ret) mem = + let coll = Dom.Mem.find_stack (Loc.of_id coll_id) mem in + let to_add_length = Sem.eval integer_type_widths size_exp mem |> Dom.Val.get_itv in + change_size_by ~size_f:(fun _ -> to_add_length) coll_id model_env ~ret mem + |> model_by_value coll id + in + {exec; check= no_check} + + + let new_collection_by_add_all coll_exp1 coll_exp2 = + let exec model_env ~ret:((ret_id, _) as ret) mem = + create_collection model_env ~ret mem ~size_exp:Exp.zero + |> (addAll ret_id coll_exp1).exec model_env ~ret + |> (addAll ret_id coll_exp2).exec model_env ~ret + in + {exec; check= no_check} + + let get_first coll_id = get_at_index coll_id Exp.zero let remove_last coll_id = {exec= change_size_by ~size_f:Itv.decr coll_id; check= no_check} @@ -1675,8 +1694,14 @@ module Call = struct &:: "arrayWithObjects" &++> NSCollection.of_list ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "objectEnumerator" <>$ capt_exp $--> NSCollection.iterator + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "arrayByAddingObjectsFromArray:" <>$ capt_exp $+ capt_exp + $--> NSCollection.new_collection_by_add_all ; +PatternMatch.ObjectiveC.implements "NSEnumerator" &:: "nextObject" <>$ capt_exp $--> NSCollection.next_object + ; +PatternMatch.ObjectiveC.implements "NSMutableArray" + &:: "initWithCapacity:" <>$ capt_var_exn $+ capt_exp + $--> NSCollection.new_collection_of_size ; +PatternMatch.ObjectiveC.implements "NSMutableArray" &:: "addObject:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.add ; +PatternMatch.ObjectiveC.implements "NSMutableArray" diff --git a/infer/src/cost/costModels.ml b/infer/src/cost/costModels.ml index 8c4b17224..987be3bdd 100644 --- a/infer/src/cost/costModels.ml +++ b/infer/src/cost/costModels.ml @@ -229,6 +229,10 @@ module Call = struct &:: "sortedArrayUsingDescriptors:" <>$ capt_exp $+ any_arg $--> BoundsOfNSCollection.n_log_n_length ~of_function:"NSArray.sortedArrayUsingDescriptors:" + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "arrayByAddingObjectsFromArray:" <>$ capt_exp $+ capt_exp + $--> NSCollection.op_on_two_coll BasicCost.plus + ~of_function:"NSArray.arrayByAddingObjectsFromArray:" ; +PatternMatch.ObjectiveC.implements "NSMutableArray" &:: "removeAllObjects" <>$ capt_exp $--> BoundsOfNSCollection.linear_length ~of_function:"NSArray.removeAllObjects" diff --git a/infer/tests/codetoanalyze/objc/performance/NSArray.m b/infer/tests/codetoanalyze/objc/performance/NSArray.m index c4f243e2b..2f271db12 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSArray.m +++ b/infer/tests/codetoanalyze/objc/performance/NSArray.m @@ -70,9 +70,12 @@ NSArray* nsarray_add_object_constant(id obj) { return [array arrayByAddingObject:obj]; } -NSArray* nsarray_add_objects_from_array_linear_FN(NSArray* append_array) { +NSArray* nsarray_add_objects_from_array_linear(NSArray* append_array) { NSArray* array = [[NSArray alloc] init]; - return [array arrayByAddingObjectsFromArray:append_array]; + NSArray* new_array = [array arrayByAddingObjectsFromArray:append_array]; + + for (int i = 0; i < new_array.count; i++) { + } } // query element diff --git a/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m b/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m index 7347edd53..35ae077c7 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m +++ b/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m @@ -8,7 +8,7 @@ // init array -void nsmarray_init_with_capacity_constant_FP() { +void nsmarray_init_with_capacity_constant() { NSMutableArray* table = [[NSMutableArray alloc] initWithCapacity:256]; for (int i = 0; i < table.count; i++) { diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index d60c4309d..9e3f86d55 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -1,7 +1,7 @@ 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] codetoanalyze/objc/performance/NSArray.m, nsarray_add_object_constant, 8, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear_FN, 8, OnUIThread:false, [] +codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear, 9 + 3 ⋅ append_array->elements.length.ub + append_array->elements.length.ub + 3 ⋅ (append_array->elements.length.ub + 1), OnUIThread:false, [{append_array->elements.length.ub + 1},Loop,{append_array->elements.length.ub},Modeled call to NSArray.arrayByAddingObjectsFromArray:,{append_array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant, 27, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_contains_object_linear, 3 + array->elements.length.ub, OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.containsObject:] codetoanalyze/objc/performance/NSArray.m, nsarray_count_bounded_linear, 3 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] @@ -45,7 +45,7 @@ codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_linear, 8 codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_quadratic, 6 + 5 ⋅ n + 8 ⋅ n × m + 2 ⋅ n × (m + 1) + 2 ⋅ (n + 1), OnUIThread:false, [{n + 1},Loop,{m + 1},Loop,{m},Loop,{n},Loop] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_then_loop_constant, 108, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_empty_ok_costant, 7, OnUIThread:false, [] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_init_with_capacity_constant_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_init_with_capacity_constant, 4617, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_all_linear, 4 + 3 ⋅ array->elements.length.ub + array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Modeled call to NSArray.removeAllObjects,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 17, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 182, OnUIThread:false, [] diff --git a/infer/tests/codetoanalyze/objc/performance/issues.exp b/infer/tests/codetoanalyze/objc/performance/issues.exp index 0971eebc0..1a461078d 100644 --- a/infer/tests/codetoanalyze/objc/performance/issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/issues.exp @@ -5,8 +5,6 @@ codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_call_const codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_with_dictionary_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_with_dictionary_linear_FP, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [,Unknown value from: NSDictionary.initWithDictionary:,Binary operation: ([0, +oo] + 1):signed32] codetoanalyze/objc/performance/NSMutableArray.m, nsarray_new_constant, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_init_with_capacity_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_init_with_capacity_constant_FP, 3, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [,Unknown value from: NSMutableArray.initWithCapacity:,Binary operation: ([0, +oo] + 1):signed32] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 6, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Array declaration,Through,Through,Through,Through,Array access: Offset: 0 Size: 0] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 6, BUFFER_OVERRUN_L3, no_bucket, ERROR, [,Set array size,,Assignment,Set array size,Array access: Offset: [0, 9] Size: [1, 10]] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [,Unknown value from: NSNumber.intValue,Binary operation: ([-oo, +oo] + 1):signed32]