diff --git a/infer/src/absint/PatternMatch.ml b/infer/src/absint/PatternMatch.ml index ce0e2d2f4..2202dc607 100644 --- a/infer/src/absint/PatternMatch.ml +++ b/infer/src/absint/PatternMatch.ml @@ -281,6 +281,11 @@ module Java = struct end module ObjectiveC = struct + let implements interface tenv typename = + let is_interface s _ = String.equal interface (Typ.Name.name s) in + supertype_exists tenv is_interface (Typ.Name.Objc.from_string typename) + + let is_core_graphics_create_or_copy _ procname = String.is_prefix ~prefix:"CG" procname && ( String.is_substring ~substring:"Create" procname diff --git a/infer/src/absint/PatternMatch.mli b/infer/src/absint/PatternMatch.mli index b41a72651..8ab0ba4b8 100644 --- a/infer/src/absint/PatternMatch.mli +++ b/infer/src/absint/PatternMatch.mli @@ -182,6 +182,9 @@ val has_same_signature : Procname.t -> (Procname.t -> bool) Staged.t parameters.) *) module ObjectiveC : sig + val implements : string -> Tenv.t -> string -> bool + (** Check whether class implements a given ObjC class *) + val is_core_graphics_create_or_copy : Tenv.t -> string -> bool val is_core_foundation_create_or_copy : Tenv.t -> string -> bool diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index 8f41a3cf3..b65ae245b 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -1553,33 +1553,43 @@ module Call = struct ; -"CFArrayGetValueAtIndex" <>$ capt_var_exn $+ capt_exp $!--> NSCollection.get_at_index ; -"CFDictionaryGetCount" <>$ capt_exp $!--> NSCollection.length ; -"MCFArrayGetCount" <>$ capt_exp $!--> NSCollection.length - ; -"NSArray" &:: "array" <>--> NSCollection.empty_array - ; -"NSArray" &:: "init" <>--> NSCollection.empty_array - ; -"NSArray" &:: "count" <>$ capt_exp $!--> NSCollection.length - ; -"NSArray" &:: "objectAtIndexedSubscript:" <>$ capt_var_exn $+ capt_exp - $!--> NSCollection.get_at_index - ; -"NSArray" &:: "arrayWithObjects:count:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "array" <>--> NSCollection.empty_array + ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "init" <>--> NSCollection.empty_array + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "count" <>$ capt_exp $!--> NSCollection.length + ; +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_array + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "arrayWithObjects" &++> NSCollection.array_from_list + ; +PatternMatch.ObjectiveC.implements "NSDictionary" + &:: "dictionaryWithObjects:forKeys:count:" <>$ any_arg $+ capt_exp $+ capt_exp $--> NSCollection.create_array - ; -"NSArray" &:: "arrayWithObjects" &++> NSCollection.array_from_list - ; -"NSDictionary" &:: "dictionaryWithObjects:forKeys:count:" <>$ any_arg $+ capt_exp - $+ capt_exp $--> NSCollection.create_array - ; -"NSDictionary" &:: "objectForKeyedSubscript:" <>$ capt_var_exn $+ capt_exp - $--> NSCollection.get_at_index - ; -"NSDictionary" &:: "objectForKey:" <>$ capt_var_exn $+ capt_exp - $--> NSCollection.get_at_index - ; -"NSDictionary" &:: "count" <>$ capt_exp $--> NSCollection.length - ; -"NSDictionary" &:: "allKeys" <>$ capt_exp $--> create_copy_array - ; -"NSDictionary" &:: "allValues" <>$ capt_exp $--> create_copy_array - ; -"NSNumber" &:: "numberWithInt:" <>$ capt_exp $--> id - ; -"NSNumber" &:: "integerValue" <>$ capt_exp $--> id - ; -"NSString" &:: "stringWithUTF8String:" <>$ capt_exp - $!--> NSString.create_string_from_c_string - ; -"NSString" &:: "length" <>$ capt_exp $--> NSString.length - ; -"NSString" &:: "stringByAppendingString:" <>$ capt_exp $+ capt_exp $!--> NSString.concat - ; -"NSString" &:: "substringFromIndex:" <>$ capt_exp $+ capt_exp - $--> NSString.substring_from_index - ; -"NSString" &:: "appendString:" <>$ capt_exp $+ capt_exp $--> NSString.append_string - ; -"NSString" &:: "componentsSeparatedByString:" <>$ capt_exp $+ any_arg $--> NSString.split + ; +PatternMatch.ObjectiveC.implements "NSDictionary" + &:: "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.length + ; +PatternMatch.ObjectiveC.implements "NSDictionary" + &:: "allKeys" <>$ capt_exp $--> create_copy_array + ; +PatternMatch.ObjectiveC.implements "NSDictionary" + &:: "allValues" <>$ capt_exp $--> create_copy_array + ; +PatternMatch.ObjectiveC.implements "NSNumber" &:: "numberWithInt:" <>$ capt_exp $--> id + ; +PatternMatch.ObjectiveC.implements "NSNumber" &:: "integerValue" <>$ capt_exp $--> id + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "stringWithUTF8String:" <>$ capt_exp $!--> NSString.create_string_from_c_string + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "length" <>$ capt_exp $--> NSString.length + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "stringByAppendingString:" <>$ capt_exp $+ capt_exp $!--> NSString.concat + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "substringFromIndex:" <>$ capt_exp $+ capt_exp $--> NSString.substring_from_index + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "appendString:" <>$ capt_exp $+ capt_exp $--> NSString.append_string + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "componentsSeparatedByString:" <>$ capt_exp $+ any_arg $--> NSString.split ; (* C++ models *) -"boost" &:: "split" $ capt_arg_of_typ (-"std" &:: "vector") diff --git a/infer/src/cost/costModels.ml b/infer/src/cost/costModels.ml index 79197660b..da3fd5e38 100644 --- a/infer/src/cost/costModels.ml +++ b/infer/src/cost/costModels.ml @@ -170,26 +170,34 @@ module Call = struct make_dispatcher [ -"google" &:: "StrLen" <>$ capt_exp $--> BoundsOfCString.linear_length ~of_function:"google::StrLen" - ; -"NSString" &:: "stringWithUTF8String:" <>$ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "stringWithUTF8String:" <>$ capt_exp $--> BoundsOfCString.linear_length ~of_function:"NSString.stringWithUTF8String:" - ; -"NSString" &:: "stringByAppendingString:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "stringByAppendingString:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.plus ~of_function:"NSString.stringByAppendingString:" - ; -"NSString" &:: "stringByAppendingPathComponent:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "stringByAppendingPathComponent:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.plus ~of_function:"NSString.stringByAppendingPathComponent:" - ; -"NSString" &:: "isEqualToString:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "isEqualToString:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.min_default_left ~of_function:"NSString.isEqualToString:" - ; -"NSString" &:: "hasPrefix:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "hasPrefix:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.min_default_left ~of_function:"NSString.hasPrefix:" - ; -"NSString" &:: "substringFromIndex:" <>$ capt_exp $+ capt_exp - $!--> NSString.substring_from_index - ; -"NSString" &:: "rangeOfString:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "substringFromIndex:" <>$ capt_exp $+ capt_exp $!--> NSString.substring_from_index + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "rangeOfString:" <>$ capt_exp $+ capt_exp $!--> NSString.op_on_two_str BasicCost.mult ~of_function:"NSString.rangeOfString:" - ; -"NSMutableString" &:: "appendString:" <>$ any_arg $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSMutableString" + &:: "appendString:" <>$ any_arg $+ capt_exp $--> NSString.get_length ~of_function:"NSMutableString.appendString:" - ; -"NSString" &:: "componentsSeparatedByString:" <>$ capt_exp $+ capt_exp + ; +PatternMatch.ObjectiveC.implements "NSString" + &:: "componentsSeparatedByString:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.mult ~of_function:"NSString.componentsSeparatedByString:" ; +PatternMatch.Java.implements_collections diff --git a/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m b/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m index 9889aa475..442f8a1d0 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m +++ b/infer/tests/codetoanalyze/objc/performance/NSMutableArray.m @@ -23,7 +23,7 @@ void nsmarray_empty_ok_costant() { [array insertObject:@1 atIndex:0]; } -void nsmarray_add_in_loop_constant_FP() { +void nsmarray_add_in_loop_constant() { NSMutableArray* array = [[NSMutableArray alloc] init]; for (int i = 0; i < 10; i++) { [array addObject:[NSNumber numberWithInt:i]]; @@ -50,7 +50,7 @@ void nsmarray_add_in_loop_quadratic(NSUInteger n, NSUInteger m) { } } -void nsmarray_add_then_loop_constant_FP() { +void nsmarray_add_then_loop_constant() { NSMutableArray* array = [[NSMutableArray alloc] init]; [array addObject:@0]; [array addObject:@1]; @@ -92,7 +92,7 @@ void nsmarray_set_linear(NSMutableArray* array) { } } -void nsmarray_set_constant_FP() { +void nsmarray_set_in_loop_constant() { NSMutableArray* array = [[NSMutableArray alloc] init]; [array addObject:@0]; [array addObject:@1]; @@ -105,7 +105,7 @@ void nsmarray_set_constant_FP() { // remove element -id nsmarray_reomove_constant() { +id nsmarray_remove_constant() { NSMutableArray* array = [[NSMutableArray alloc] init]; [array addObject:@0]; [array addObject:@1]; @@ -113,7 +113,7 @@ id nsmarray_reomove_constant() { return array[0]; } -void nsmarray_remove_in_loop_constant_FP() { +void nsmarray_remove_in_loop_constant() { NSMutableArray* array = [[NSMutableArray alloc] init]; for (int i = 0; i < 10; i++) { [array addObject:[NSNumber numberWithInt:i]]; diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index 4b848478d..cdaa5b25e 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -37,20 +37,20 @@ codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_with_dictionary codetoanalyze/objc/performance/NSInteger.m, nsinteger_value_linear, 3 + 3 ⋅ integer + 2 ⋅ (1+max(0, integer)), OnUIThread:false, [{1+max(0, integer)},Loop,{integer},Loop] codetoanalyze/objc/performance/NSInteger.m, nsnumber_number_with_int_integer_value_constant, 34, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_all_constant, 25, OnUIThread:false, [] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_constant_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_constant, 92, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_linear, 8 + 7 ⋅ n + 3 ⋅ n + 2 ⋅ (n + 1) + 2 ⋅ (n + 1), OnUIThread:false, [{n + 1},Loop,{n + 1},Loop,{n},Loop,{n},Loop] 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_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_then_loop_constant, 42, 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_remove_in_loop_constant_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_reomove_constant, 15, OnUIThread:false, [] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 15, OnUIThread:false, [] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 92, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_constant, 4, OnUIThread:false, [] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_constant_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_in_loop_constant, 18, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 3 + 11 ⋅ array.length + 3 ⋅ (array.length + 1), OnUIThread:false, [{array.length + 1},Loop,{array.length},Loop] codetoanalyze/objc/performance/NSMutableDictionary.m, nsmutabledictionary_set_element_in_loop_linear_FN, 14, OnUIThread:false, [] -codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_constant, 14 + 3 ⋅ str.length.ub + 3 ⋅ (str.length.ub + 1), OnUIThread:false, [{str.length.ub + 1},Loop,{str.length.ub},Loop] -codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_linear, 5 + str2.length.ub + 3 ⋅ str1.length.ub + 3 ⋅ (str1.length.ub + 1), OnUIThread:false, [{str1.length.ub + 1},Loop,{str1.length.ub},Loop,{str2.length.ub},Modeled call to NSMutableString.appendString:] +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/NSString.m, call_component_separated_by_char_constant, 46, OnUIThread:false, [] codetoanalyze/objc/performance/NSString.m, call_init_with_string_constant_FP, ⊤, OnUIThread:false, [Call to init_with_string_linear_FP,Unbounded loop,Loop] 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 9f1a91a66..491154fa1 100644 --- a/infer/tests/codetoanalyze/objc/performance/issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/issues.exp @@ -10,17 +10,13 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear_FN, 3, INTEGER_ codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 6, BUFFER_OVERRUN_U5, no_bucket, ERROR, [,Unknown value from: NSDictionary.nextObject,Assignment,,Unknown value from: NSDictionary.dictionaryWithObjects:forKeys:count:,Assignment,Array access: Offset: [-oo, +oo] (⇐ [-oo, +oo] + [-oo, +oo]) Size: [0, +oo]] 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_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_constant_FP, 5, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_then_loop_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_then_loop_constant_FP, 14, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_in_loop_constant, 5, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_add_then_loop_constant, 14, 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_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant_FP, 5, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_reomove_constant, 5, BUFFER_OVERRUN_U5, no_bucket, ERROR, [,Unknown value from: NSMutableArray.init,Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_constant_FP, 6, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 5, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Array declaration,Assignment,Array access: Offset: 0 Size: 0] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 5, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_in_loop_constant, 6, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] 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/NSString.m, call_init_with_string_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Call to init_with_string_linear_FP,Unbounded loop,Loop] codetoanalyze/objc/performance/NSString.m, init_with_bytes_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]