diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index acb0f2565..e58900f20 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -1512,14 +1512,17 @@ module NSString = struct {exec; check= no_check} end +let is_objc_collection = + let coll = ["NSArray"; "NSDictionary"; "NSOrderedSet"; "NSSet"] in + fun tenv typ_str -> + List.exists ~f:(fun obj_class -> PatternMatch.ObjectiveC.implements obj_class tenv typ_str) coll + + let objc_malloc exp = let can_be_zero = true in let exec ({tenv} as model) ~ret mem = match exp with - | Exp.Sizeof {typ} when PatternMatch.ObjectiveC.implements "NSArray" tenv (Typ.to_string typ) -> - NSCollection.new_collection.exec model ~ret mem - | Exp.Sizeof {typ} - when PatternMatch.ObjectiveC.implements "NSDictionary" tenv (Typ.to_string typ) -> + | Exp.Sizeof {typ} when is_objc_collection tenv (Typ.to_string typ) -> NSCollection.new_collection.exec model ~ret mem | Exp.Sizeof {typ} when PatternMatch.ObjectiveC.implements "NSString" tenv (Typ.to_string typ) -> @@ -1684,21 +1687,21 @@ module Call = struct &:: "firstObject" <>$ capt_var_exn $!--> NSCollection.get_first ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "initWithDictionary:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.copy + ; +PatternMatch.ObjectiveC.implements "NSSet" + &:: "initWithArray:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.copy ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "initWithArray:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.copy ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "initWithArray:copyItems:" <>$ capt_var_exn $+ capt_exp $+ any_arg $--> NSCollection.copy - ; +PatternMatch.ObjectiveC.implements "NSArray" - &:: "count" <>$ capt_exp $!--> NSCollection.size + ; +is_objc_collection &:: "count" <>$ capt_exp $!--> NSCollection.size + ; +is_objc_collection &:: "objectEnumerator" <>$ capt_exp $--> NSCollection.iterator ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "objectAtIndexedSubscript:" <>$ capt_var_exn $+ capt_exp $!--> NSCollection.get_at_index ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "arrayWithObjects:count:" <>$ capt_exp $+ capt_exp $--> NSCollection.create_from_array ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "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 @@ -1729,18 +1732,12 @@ module Call = struct &:: "objectForKeyedSubscript:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.get_at_index ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "objectForKey:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.get_at_index - ; +PatternMatch.ObjectiveC.implements "NSDictionary" - &:: "count" <>$ capt_exp $--> NSCollection.size ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "allKeys" <>$ capt_exp $--> create_copy_array ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "allValues" <>$ capt_exp $--> create_copy_array - ; +PatternMatch.ObjectiveC.implements "NSDictionary" - &:: "objectEnumerator" <>$ capt_exp $--> NSCollection.iterator ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "keyEnumerator" <>$ capt_exp $--> NSCollection.iterator - ; +PatternMatch.ObjectiveC.implements "NSOrderedSet" - &:: "objectEnumerator" <>$ capt_exp $--> NSCollection.iterator ; +PatternMatch.ObjectiveC.implements "NSOrderedSet" &:: "reverseObjectEnumerator" <>$ capt_exp $--> NSCollection.iterator ; +PatternMatch.ObjectiveC.implements "NSNumber" &:: "numberWithInt:" <>$ capt_exp $--> id diff --git a/infer/tests/codetoanalyze/objc/performance/NSSet.m b/infer/tests/codetoanalyze/objc/performance/NSSet.m new file mode 100644 index 000000000..06dafd9dd --- /dev/null +++ b/infer/tests/codetoanalyze/objc/performance/NSSet.m @@ -0,0 +1,53 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#import + +// init set + +void nsset_init_constant() { + NSSet* set = [[NSSet alloc] init]; + + for (int i = 0; i < set.count; i++) { + } +} + +void nsset_init_with_set_constant() { + NSSet* set = [[NSSet alloc] init]; + nsset_init_with_set_linear(set); +} + +void nsset_init_with_array_linear(NSArray* array) { + NSSet* ref_set = [[NSSet alloc] initWithArray:array]; + + for (int i = 0; i < ref_set.count; i++) { + } +} + +// iterate through set + +void nsset_iterate_linear(NSSet* set) { + NSInteger sum = 0; + for (id obj in set) { + sum += (NSInteger)obj; + } +} + +void nsset_enumerator_linear(NSSet* set) { + NSEnumerator* enumerator = [set objectEnumerator]; + + id obj; + NSInteger sum = 0; + + while (obj = [enumerator nextObject]) { + sum += (NSInteger)obj; + } +} + +void nsset_next_object_linear(NSSet* set) { + for (id item in set) { + } +} diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index 2f264e9bc..c350fa70b 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -61,6 +61,12 @@ codetoanalyze/objc/performance/NSMutableDictionary.m, nsmutabledictionary_set_el codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_constant, 14 + 3 ⋅ (str.length.ub + 5) + 3 ⋅ (str.length.ub + 6), OnUIThread:false, [{str.length.ub + 6},Loop,{str.length.ub + 5},Loop] codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_linear, 5 + str2.length.ub + 3 ⋅ (str2.length.ub + str1.length.ub) + 3 ⋅ (str2.length.ub + str1.length.ub + 1), OnUIThread:false, [{str2.length.ub + str1.length.ub + 1},Loop,{str2.length.ub + str1.length.ub},Loop,{str2.length.ub},Modeled call to NSMutableString.appendString:] codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_iterate_linear, 5 + ordered_set->elements.length.ub + 4 ⋅ (ordered_set->elements.length.ub + 1), OnUIThread:false, [{ordered_set->elements.length.ub + 1},Loop,{ordered_set->elements.length.ub},Loop] +codetoanalyze/objc/performance/NSSet.m, nsset_enumerator_linear, 6 + 4 ⋅ set->elements.length.ub + 4 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop,{set->elements.length.ub},Loop] +codetoanalyze/objc/performance/NSSet.m, nsset_init_constant, 9, OnUIThread:false, [] +codetoanalyze/objc/performance/NSSet.m, nsset_init_with_array_linear, 7 + 3 ⋅ 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/NSSet.m, nsset_init_with_set_constant, 6, OnUIThread:false, [] +codetoanalyze/objc/performance/NSSet.m, nsset_iterate_linear, 6 + 4 ⋅ set->elements.length.ub + 4 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop,{set->elements.length.ub},Loop] +codetoanalyze/objc/performance/NSSet.m, nsset_next_object_linear, 5 + set->elements.length.ub + 4 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop,{set->elements.length.ub},Loop] codetoanalyze/objc/performance/NSString.m, call_component_separated_by_char_constant, 46, OnUIThread:false, [] codetoanalyze/objc/performance/NSString.m, call_init_with_string_constant, 15, OnUIThread:false, [] codetoanalyze/objc/performance/NSString.m, component_seperated_by_char_linear, 6 + m.length.ub + 3 ⋅ (-1+max(2, m.length.ub)) + 3 ⋅ (max(2, m.length.ub)), OnUIThread:false, [{max(2, m.length.ub)},Loop,{-1+max(2, m.length.ub)},Loop,{m.length.ub},Modeled call to NSString.componentsSeparatedByString:] diff --git a/infer/tests/codetoanalyze/objc/performance/issues.exp b/infer/tests/codetoanalyze/objc/performance/issues.exp index e42093ad5..78f9630d3 100644 --- a/infer/tests/codetoanalyze/objc/performance/issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/issues.exp @@ -4,6 +4,7 @@ codetoanalyze/objc/performance/NSMutableArray.m, nsarray_new_constant, 2, CONDIT 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] +codetoanalyze/objc/performance/NSSet.m, nsset_init_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] codetoanalyze/objc/performance/NSString.m, init_string_constant, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] codetoanalyze/objc/performance/NSString.m, replace_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] codetoanalyze/objc/performance/NSString.m, replace_linear_FP, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [,Unknown value from: NSString.stringByReplacingOccurrencesOfString:withString:,Binary operation: ([0, +oo] + 1):signed32]