diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index fba40b9c1..f9bec5e91 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -533,7 +533,7 @@ module ArrObjCommon = struct cond_set end -module NSArray = struct +module NSCollection = struct (** Creates a new array from the given array by copying the first X elements. *) let create_array src_exp size_exp = let {exec= malloc_exec; check= _} = malloc ~can_be_zero:true size_exp in @@ -550,15 +550,6 @@ module NSArray = struct {exec; check} - let length e = - let exec {integer_type_widths} ~ret:(ret_id, _) mem = - let v = Sem.eval_arr integer_type_widths e mem in - let length = Dom.Val.of_itv (ArrayBlk.get_size (Dom.Val.get_array_blk v)) in - Dom.Mem.add_stack (Loc.of_id ret_id) length mem - in - {exec; check= no_check} - - let empty_array = malloc ~can_be_zero:true Exp.zero let get_internal_array_locs arr_id _ = Loc.of_id arr_id |> PowLoc.singleton @@ -568,6 +559,15 @@ module NSArray = struct Dom.Mem.find_set arr_locs mem |> Dom.Val.get_all_locs + let length e = + let exec {integer_type_widths} ~ret:(ret_id, _) mem = + let v = Sem.eval_arr integer_type_widths e mem in + let length = Dom.Val.of_itv (ArrayBlk.get_size (Dom.Val.get_array_blk v)) in + Dom.Mem.add_stack (Loc.of_id ret_id) length mem + in + {exec; check= no_check} + + let check_index ~last_included arr_id index_exp = ArrObjCommon.check_index ~last_included get_internal_array_locs arr_id index_exp @@ -1515,19 +1515,29 @@ module Call = struct ; -"strndup" <>$ capt_exp $+ capt_exp $+...$--> strndup ; -"vsnprintf" <>--> by_value Dom.Val.Itv.nat ; (* ObjC models *) - -"CFArrayCreate" <>$ any_arg $+ capt_exp $+ capt_exp $+...$--> NSArray.create_array + -"CFArrayCreate" <>$ any_arg $+ capt_exp $+ capt_exp $+...$--> NSCollection.create_array ; -"CFArrayCreateCopy" <>$ any_arg $+ capt_exp $!--> create_copy_array - ; -"CFArrayGetCount" <>$ capt_exp $!--> NSArray.length - ; -"CFArrayGetValueAtIndex" <>$ capt_var_exn $+ capt_exp $!--> NSArray.get_at_index - ; -"CFDictionaryGetCount" <>$ capt_exp $!--> NSArray.length - ; -"MCFArrayGetCount" <>$ capt_exp $!--> NSArray.length - ; -"NSArray" &:: "array" <>--> NSArray.empty_array - ; -"NSArray" &:: "init" <>--> NSArray.empty_array - ; -"NSArray" &:: "count" <>$ capt_exp $!--> NSArray.length + ; -"CFArrayGetCount" <>$ capt_exp $!--> NSCollection.length + ; -"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 - $!--> NSArray.get_at_index - ; -"NSArray" &:: "arrayWithObjects:count:" <>$ capt_exp $+ capt_exp $--> NSArray.create_array - ; -"NSArray" &:: "arrayWithObjects" &++> NSArray.array_from_list + $!--> NSCollection.get_at_index + ; -"NSArray" &:: "arrayWithObjects:count:" <>$ 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 diff --git a/infer/tests/codetoanalyze/objc/performance/NSDictionary.m b/infer/tests/codetoanalyze/objc/performance/NSDictionary.m index 102ffbbfc..7da86c1f5 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSDictionary.m +++ b/infer/tests/codetoanalyze/objc/performance/NSDictionary.m @@ -42,7 +42,7 @@ NSDictionary* nsdictionary_dictionary_with_objects_linear(int n_entries) { forKeys:(id*)keyArray count:n_entries]; - for (id key in asciiDict) { + for (int i = 0; i < [asciiDict.count integerValue]; i++) { } return asciiDict; @@ -50,12 +50,19 @@ NSDictionary* nsdictionary_dictionary_with_objects_linear(int n_entries) { // accessing values and keys -void nsdictionary_all_keys_linear_FP(NSDictionary* dict) { +void nsdictionary_all_keys_linear1(NSDictionary* dict) { for (int i = 0; i < [dict allKeys].count; i++) { } } -void nsdictionary_all_values_linear_FP(NSDictionary* dict) { +void nsdictionary_all_keys_linear2(NSDictionary* dict) { + NSArray* array = [dict allKeys]; + + for (int i = 0; i < array.count; i++) { + } +} + +void nsdictionary_all_values_linear(NSDictionary* dict) { for (int i = 0; i < [dict allValues].count; i++) { } } diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index be13deb00..e6acd3519 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -23,9 +23,10 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 34 codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 34, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn_FN, 10, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 5, OnUIThread:false, [] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear_FP, ⊤, OnUIThread:false, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_with_objects_linear, 21 + 15 ⋅ n_entries + 2 ⋅ (1+max(0, n_entries)), OnUIThread:false, [{1+max(0, n_entries)},Loop,{n_entries},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear1, 3 + 3 ⋅ dict.length + 4 ⋅ (dict.length + 1), OnUIThread:false, [{dict.length + 1},Loop,{dict.length},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear2, 6 + 3 ⋅ dict.length + 3 ⋅ (dict.length + 1), OnUIThread:false, [{dict.length + 1},Loop,{dict.length},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear, 3 + 3 ⋅ dict.length + 4 ⋅ (dict.length + 1), OnUIThread:false, [{dict.length + 1},Loop,{dict.length},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_with_objects_linear, 14 + 15 ⋅ n_entries + 3 ⋅ n_entries + 2 ⋅ (1+max(0, n_entries)) + 4 ⋅ (1+max(0, n_entries)), OnUIThread:false, [{1+max(0, n_entries)},Loop,{1+max(0, n_entries)},Loop,{n_entries},Loop,{n_entries},Loop] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 52, OnUIThread:false, [] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerator_linear_FN, 10, OnUIThread:false, [] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_fast_enumerate_linear_FN, 10, OnUIThread:false, [] diff --git a/infer/tests/codetoanalyze/objc/performance/issues.exp b/infer/tests/codetoanalyze/objc/performance/issues.exp index d212b9377..a0cbe5e9f 100644 --- a/infer/tests/codetoanalyze/objc/performance/issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/issues.exp @@ -7,10 +7,7 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_copy_linear_FP codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear_FP, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear_FN, 3, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [,Assignment,,Unknown value from: NSArray.nextObject,Assignment,Binary operation: ([-oo, +oo] + [-oo, +oo]):signed64] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear_FP, 1, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear_FP, 1, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] +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]