diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index a25564d44..c00847372 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -664,6 +664,13 @@ module Collection = struct let add coll_id = {exec= change_size_by ~size_f:Itv.incr coll_id; check= no_check} + (** increase the size by [0, 1] because put replaces the value + rather than add a new one when the key is found in the map *) + let put coll_id = + let zero_one = Itv.set_lb_zero Itv.one in + {exec= change_size_by ~size_f:(Itv.plus zero_one) coll_id; check= no_check} + + let size coll_exp = let exec _ ~ret:(ret_id, _) mem = let result = eval_collection_length coll_exp mem in @@ -769,6 +776,9 @@ module Call = struct ; -"infer_print" <>$ capt_exp $!--> infer_print ; -"malloc" <>$ capt_exp $+...$--> malloc ~can_be_zero:false ; -"calloc" <>$ capt_exp $+ capt_exp $!--> calloc ~can_be_zero:false + ; -"__new" + <>$ capt_exp_of_typ (+PatternMatch.implements_pseudo_collection) + $+...$--> Collection.new_collection ; -"__new" <>$ capt_exp_of_typ (+PatternMatch.implements_collection) $+...$--> Collection.new_collection @@ -860,6 +870,8 @@ module Call = struct &:: "remove" <>$ capt_var_exn $+ capt_exp $--> Collection.remove_at_index ; +PatternMatch.implements_collection &:: "add" <>$ capt_var_exn $+ any_arg $--> Collection.add + ; +PatternMatch.implements_pseudo_collection + &:: "put" <>$ capt_var_exn $+ any_arg $+ any_arg $--> Collection.put ; +PatternMatch.implements_collection &:: "add" <>$ capt_var_exn $+ capt_exp $+ any_arg $!--> Collection.add_at_index ; +PatternMatch.implements_lang "Iterable" @@ -869,5 +881,6 @@ module Call = struct &:: "addAll" <>$ capt_var_exn $+ capt_exp $--> Collection.addAll ; +PatternMatch.implements_collection &:: "addAll" <>$ capt_var_exn $+ capt_exp $+ capt_exp $!--> Collection.addAll_at_index - ; +PatternMatch.implements_collection &:: "size" <>$ capt_exp $!--> Collection.size ] + ; +PatternMatch.implements_collection &:: "size" <>$ capt_exp $!--> Collection.size + ; +PatternMatch.implements_pseudo_collection &:: "size" <>$ capt_exp $!--> Collection.size ] end diff --git a/infer/tests/codetoanalyze/java/performance/CollectionTest.java b/infer/tests/codetoanalyze/java/performance/CollectionTest.java index 648862b26..fe11dd65a 100644 --- a/infer/tests/codetoanalyze/java/performance/CollectionTest.java +++ b/infer/tests/codetoanalyze/java/performance/CollectionTest.java @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import android.util.SparseArray; import java.util.Collection; import java.util.concurrent.ConcurrentLinkedQueue; @@ -58,4 +59,14 @@ public class CollectionTest { } } } + + void sparse_array_linear(SparseArray arr) { + for (int i = 0; i < arr.size(); i++) {} + } + + void sparse_array_new_constant() { + SparseArray new_arr = new SparseArray(); + new_arr.put(1, 1); + for (int i = 0; i < new_arr.size(); i++) {} + } } diff --git a/infer/tests/codetoanalyze/java/performance/issues.exp b/infer/tests/codetoanalyze/java/performance/issues.exp index e5b5dc01a..068f0f12b 100644 --- a/infer/tests/codetoanalyze/java/performance/issues.exp +++ b/infer/tests/codetoanalyze/java/performance/issues.exp @@ -43,13 +43,14 @@ codetoanalyze/java/performance/CantHandle.java, CantHandle.square_root_FP(int):v codetoanalyze/java/performance/CantHandle.java, CantHandle.square_root_FP(int):void, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] codetoanalyze/java/performance/CantHandle.java, CantHandle.square_root_variant_FP(int):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [Unbounded loop,Loop at line 25] codetoanalyze/java/performance/CantHandle.java, CantHandle.square_root_variant_FP(int):void, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Parameter `x`,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.ensure_call(CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 11 + 5 ⋅ list.length, degree = 1,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 16] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_call_quad(int,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 18 ⋅ (list.length - 1) + 5 ⋅ (list.length - 1) × list.length + 3 ⋅ list.length, degree = 2,{list.length},Loop at line 47,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 16,{list.length - 1},Loop at line 47] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 5 + 5 ⋅ list.length, degree = 1,{list.length},Loop at line 16] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_mycollection_quad_FN(java.util.concurrent.ConcurrentLinkedQueue):void, 2, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 18 ⋅ (mSubscribers.length - 1) + 5 ⋅ (mSubscribers.length - 1) × Iterator.next().length.ub + 3 ⋅ mSubscribers.length, degree = 2,{mSubscribers.length},Loop at line 28,{Iterator.next().length.ub},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 16,{mSubscribers.length - 1},Loop at line 28] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_some_java_collection(java.util.concurrent.ConcurrentLinkedQueue):void, 2, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 8 ⋅ (mSubscribers.length - 1) + 3 ⋅ mSubscribers.length, degree = 1,{mSubscribers.length},Loop at line 21,{mSubscribers.length - 1},Loop at line 21] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.loop_over_call(int,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 15 ⋅ size + 5 ⋅ size × list.length, degree = 2,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 16,{size},Loop at line 40] -codetoanalyze/java/performance/CollectionTest.java, CollectionTest.nested_iterator_qubic(int,CollectionTest$MyCollection,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 13 ⋅ (list1.length - 1) + 28 ⋅ (list1.length - 1) × (list2.length - 1) + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 3 ⋅ (list1.length - 1) × list2.length + 3 ⋅ list1.length, degree = 3,{list1.length},Loop at line 54,{list2.length},Loop at line 55,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 16,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 16,{list2.length - 1},Loop at line 55,{list1.length - 1},Loop at line 54] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.ensure_call(CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 11 + 5 ⋅ list.length, degree = 1,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_call_quad(int,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 18 ⋅ (list.length - 1) + 5 ⋅ (list.length - 1) × list.length + 3 ⋅ list.length, degree = 2,{list.length},Loop at line 48,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list.length - 1},Loop at line 48] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 5 + 5 ⋅ list.length, degree = 1,{list.length},Loop at line 17] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_mycollection_quad_FN(java.util.concurrent.ConcurrentLinkedQueue):void, 2, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 18 ⋅ (mSubscribers.length - 1) + 5 ⋅ (mSubscribers.length - 1) × Iterator.next().length.ub + 3 ⋅ mSubscribers.length, degree = 2,{mSubscribers.length},Loop at line 29,{Iterator.next().length.ub},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{mSubscribers.length - 1},Loop at line 29] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_some_java_collection(java.util.concurrent.ConcurrentLinkedQueue):void, 2, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 8 ⋅ (mSubscribers.length - 1) + 3 ⋅ mSubscribers.length, degree = 1,{mSubscribers.length},Loop at line 22,{mSubscribers.length - 1},Loop at line 22] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.loop_over_call(int,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 15 ⋅ size + 5 ⋅ size × list.length, degree = 2,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{size},Loop at line 41] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.nested_iterator_qubic(int,CollectionTest$MyCollection,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 13 ⋅ (list1.length - 1) + 28 ⋅ (list1.length - 1) × (list2.length - 1) + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 3 ⋅ (list1.length - 1) × list2.length + 3 ⋅ list1.length, degree = 3,{list1.length},Loop at line 55,{list2.length},Loop at line 56,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list2.length - 1},Loop at line 56,{list1.length - 1},Loop at line 55] +codetoanalyze/java/performance/CollectionTest.java, CollectionTest.sparse_array_linear(android.util.SparseArray):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ arr.length + 3 ⋅ (arr.length + 1), degree = 1,{arr.length + 1},Loop at line 64,{arr.length},Loop at line 64] codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.compound_while(int):int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here] codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.compound_while(int):int, 3, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 5 ⋅ m + 2 ⋅ (1+max(0, m)), degree = 1,{1+max(0, m)},Loop at line 15,{m},Loop at line 15] codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.nested_while_and_or(int):int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]