diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index df60bec0a..045bfa36a 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -817,6 +817,11 @@ module Collection = struct {exec; check= check_index ~last_included:false coll_id index_exp} end +let unmodifiable _ s = + String.is_prefix ~prefix:"unmodifiable" s + && List.exists ~f:(fun suffix -> String.is_suffix ~suffix s) ["Set"; "Collection"; "Map"; "List"] + + module Call = struct let dispatch : (Tenv.t, model) ProcnameDispatcher.Call.dispatcher = let open ProcnameDispatcher.Call in @@ -939,6 +944,8 @@ module Call = struct ; +PatternMatch.implements_collection &:: "" <>$ capt_var_exn $+ capt_exp $--> Collection.init (* model sets as lists *) + ; +PatternMatch.implements_collections + &::+ unmodifiable <>$ capt_exp $--> Collection.iterator ; +PatternMatch.implements_collections &:: "singleton" <>$ capt_exp $--> Collection.singleton_collection ; +PatternMatch.implements_collections diff --git a/infer/tests/codetoanalyze/java/performance/CollectionsTest.java b/infer/tests/codetoanalyze/java/performance/CollectionsTest.java index 57adad3ff..45c70a778 100644 --- a/infer/tests/codetoanalyze/java/performance/CollectionsTest.java +++ b/infer/tests/codetoanalyze/java/performance/CollectionsTest.java @@ -6,6 +6,7 @@ */ import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.Set; @@ -46,4 +47,17 @@ class CollectionsTest { void copy_linear(List list_from, List list_to) { Collections.copy(list_to, list_from); } + + void unmodifiable_linear(List list) { + List unmod_list = Collections.unmodifiableList(list); + for (int i = 0; i < unmod_list.size(); i++) {} + } + + void unmodifiable_map(Map map) { + for (Map.Entry entry : Collections.unmodifiableMap(map).entrySet()) {} + } + + void unmodifiable_set(Set set) { + for (Integer el : Collections.unmodifiableSet(set)) {} + } } diff --git a/infer/tests/codetoanalyze/java/performance/issues.exp b/infer/tests/codetoanalyze/java/performance/issues.exp index 8e94f784d..ff8db5cd0 100644 --- a/infer/tests/codetoanalyze/java/performance/issues.exp +++ b/infer/tests/codetoanalyze/java/performance/issues.exp @@ -67,6 +67,9 @@ codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.reverse_lin codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.shuffle_linear(java.util.List,java.util.Random):void, 1, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 3 + list.length, degree = 1,{list.length},Modeled call to Collections.shuffle] codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.singletonList_constant(java.lang.String):void, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.singletonSet_constant():void, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here] +codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.unmodifiable_linear(java.util.List):void, 2, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 5 + 5 ⋅ list.length + 3 ⋅ (list.length + 1), degree = 1,{list.length + 1},Loop at line 53,{list.length},Loop at line 53] +codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.unmodifiable_map(java.util.Map):void, 1, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 10 + 8 ⋅ (map.length - 1) + 3 ⋅ map.length, degree = 1,{map.length},Loop at line 57,{map.length - 1},Loop at line 57] +codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.unmodifiable_set(java.util.Set):void, 1, EXPENSIVE_EXECUTION_TIME, no_bucket, ERROR, [with estimated cost 7 + 8 ⋅ (set.length - 1) + 3 ⋅ set.length, degree = 1,{set.length},Loop at line 61,{set.length - 1},Loop at line 61] 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_TIME, 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]