diff --git a/infer/src/bufferoverrun/bufferOverrunChecker.ml b/infer/src/bufferoverrun/bufferOverrunChecker.ml index 3fdbe9712..4a112d4c1 100644 --- a/infer/src/bufferoverrun/bufferOverrunChecker.ml +++ b/infer/src/bufferoverrun/bufferOverrunChecker.ml @@ -265,6 +265,14 @@ module TransferFunctions = struct Dom.Mem.forget_locs (PowLoc.add ret_loc (PowLoc.singleton ret_var)) mem + let is_external pname = + match pname with + | Typ.Procname.Java java_pname -> + Typ.Procname.Java.is_external java_pname + | _ -> + false + + let instantiate_mem : Tenv.t -> Typ.IntegerWidths.t @@ -359,7 +367,7 @@ module TransferFunctions = struct mem | Prune (exp, _, _, _) -> Sem.Prune.prune integer_type_widths exp mem - | Call (((id, _) as ret), Const (Cfun callee_pname), params, location, _) -> ( + | Call (((id, ret_typ) as ret), Const (Cfun callee_pname), params, location, _) -> ( let mem = Dom.Mem.add_stack_loc (Loc.of_id id) mem in match Models.Call.dispatch tenv callee_pname params with | Some {Models.exec} -> @@ -383,7 +391,15 @@ module TransferFunctions = struct Dom.Mem.add_unknown_from id ~callee_pname ~location mem ) | None -> L.d_printfln "/!\\ Unknown call to %a" Typ.Procname.pp callee_pname ; - Dom.Mem.add_unknown_from id ~callee_pname ~location mem ) ) + if is_external callee_pname then ( + let node_hash = CFG.Node.hash node in + let path = Itv.SymbolPath.of_callsite (CallSite.make callee_pname location) in + L.(debug BufferOverrun Verbose) + "/!\\ External call to unknown %a \n\n" Typ.Procname.pp callee_pname ; + Init.declare_symbolic_val callee_pname symbol_table path tenv integer_type_widths + ~node_hash location (Loc.of_id id) ret_typ ~new_sym_num:(Counter.make node_hash) + mem ) + else Dom.Mem.add_unknown_from id ~callee_pname ~location mem ) ) | Call ((id, _), fun_exp, _, location, _) -> let mem = Dom.Mem.add_stack_loc (Loc.of_id id) mem in let () = L.d_printfln "/!\\ Call to non-const function %a" Exp.pp fun_exp in diff --git a/infer/src/bufferoverrun/bufferOverrunSemantics.ml b/infer/src/bufferoverrun/bufferOverrunSemantics.ml index 5494baa50..1ec530dce 100644 --- a/infer/src/bufferoverrun/bufferOverrunSemantics.ml +++ b/infer/src/bufferoverrun/bufferOverrunSemantics.ml @@ -321,6 +321,10 @@ let rec eval_sympath_partial params p mem = L.(debug BufferOverrun Verbose) "Symbol %a is not found in parameters.@\n" (Pvar.pp Pp.text) x ; Val.Itv.top ) + | Symb.SymbolPath.Callsite cs -> + L.(debug BufferOverrun Verbose) + "Symbol for %a is not expected to be in parameters.@\n" Typ.Procname.pp (CallSite.pname cs) ; + Val.Itv.top | Symb.SymbolPath.Deref _ | Symb.SymbolPath.Field _ -> let locs = eval_locpath params p mem in Mem.find_set locs mem @@ -334,6 +338,9 @@ and eval_locpath params p mem = | Symb.SymbolPath.Deref (_, p) -> let v = eval_sympath_partial params p mem in Val.get_all_locs v + | Symb.SymbolPath.Callsite _ -> + let v = eval_sympath_partial params p mem in + Val.get_all_locs v | Symb.SymbolPath.Field (fn, p) -> let locs = eval_locpath params p mem in PowLoc.append_field ~fn locs diff --git a/infer/src/bufferoverrun/symb.ml b/infer/src/bufferoverrun/symb.ml index f657e5c84..aa10ffca0 100644 --- a/infer/src/bufferoverrun/symb.ml +++ b/infer/src/bufferoverrun/symb.ml @@ -22,6 +22,7 @@ module SymbolPath = struct | Pvar of Pvar.t | Deref of deref_kind * partial | Field of Typ.Fieldname.t * partial + | Callsite of CallSite.t [@@deriving compare] type t = Normal of partial | Offset of partial | Length of partial [@@deriving compare] @@ -32,6 +33,8 @@ module SymbolPath = struct let of_pvar pvar = Pvar pvar + let of_callsite cs = Callsite cs + let field p fn = Field (fn, p) let deref ~deref_kind p = Deref (deref_kind, p) @@ -55,6 +58,8 @@ module SymbolPath = struct F.fprintf fmt "%a->%s" (pp_partial_paren ~paren:true) p (Typ.Fieldname.to_flat_string fn) | Field (fn, p) -> F.fprintf fmt "%a.%s" (pp_partial_paren ~paren:true) p (Typ.Fieldname.to_flat_string fn) + | Callsite cs -> + F.fprintf fmt "%a" Typ.Procname.pp (CallSite.pname cs) let pp_partial = pp_partial_paren ~paren:false @@ -69,7 +74,8 @@ module SymbolPath = struct let rec represents_multiple_values = function - | Pvar _ -> + (* TODO depending on the result, the call might represent multiple values *) + | Callsite _ | Pvar _ -> false | Deref (Deref_ArrayIndex, _) -> true @@ -79,45 +85,89 @@ module SymbolPath = struct represents_multiple_values p + let rec represents_callsite_sound_partial = function + | Callsite _ -> + true + | Pvar _ -> + false + | Deref (_, p) | Field (_, p) -> + represents_callsite_sound_partial p + + + let represents_partial_sound ~f = function Normal p | Offset p | Length p -> f p + let pp_mark ~markup = if markup then MarkupFormatter.wrap_monospaced pp else pp end module Symbol = struct type t = - {id: int; pname: Typ.Procname.t; unsigned: bool; path: SymbolPath.t; bound_end: BoundEnd.t} + | IntraProc of + { id: int + ; pname: Typ.Procname.t + ; unsigned: bool + ; path: SymbolPath.t + ; bound_end: BoundEnd.t } + (* symbols for unknown calls *) + | Call of + { id: int + ; pname: Typ.Procname.t + ; unsigned: bool + ; path: SymbolPath.t + ; bound_end: BoundEnd.t } type 'res eval = t -> 'res AbstractDomain.Types.bottom_lifted let compare s1 s2 = - (* Symbols only make sense within a given function, so shouldn't be compared across function boundaries. *) - assert (phys_equal s1.pname s2.pname) ; - Int.compare s1.id s2.id + match (s1, s2) with + | IntraProc s1, IntraProc s2 -> + (* Parameter symbols only make sense within a given function, so shouldn't be compared across function boundaries. *) + assert (phys_equal s1.pname s2.pname) ; + Int.compare s1.id s2.id + | Call s1, Call s2 -> + Int.compare s1.id s2.id + | Call _, IntraProc _ -> + -1 + | IntraProc _, Call _ -> + 1 let equal = [%compare.equal: t] - let paths_equal s1 s2 = SymbolPath.equal s1.path s2.path + let paths_equal s1 s2 = + match (s1, s2) with + | IntraProc _, Call _ | Call _, IntraProc _ -> + false + | IntraProc {path= path1}, IntraProc {path= path2} | Call {path= path1}, Call {path= path2} -> + SymbolPath.equal path1 path2 + + + let make_intraproc : unsigned:bool -> Typ.Procname.t -> SymbolPath.t -> BoundEnd.t -> int -> t = + fun ~unsigned pname path bound_end id -> IntraProc {id; pname; unsigned; path; bound_end} + - let make : unsigned:bool -> Typ.Procname.t -> SymbolPath.t -> BoundEnd.t -> int -> t = - fun ~unsigned pname path bound_end id -> {id; pname; unsigned; path; bound_end} + let make_call : unsigned:bool -> Typ.Procname.t -> SymbolPath.t -> BoundEnd.t -> int -> t = + fun ~unsigned pname path bound_end id -> Call {id; pname; unsigned; path; bound_end} let pp : F.formatter -> t -> unit = - fun fmt {pname; id; unsigned; path; bound_end} -> - SymbolPath.pp fmt path ; - if Config.developer_mode then Format.fprintf fmt ".%s" (BoundEnd.to_string bound_end) ; - if Config.bo_debug > 1 then - let symbol_name = if unsigned then 'u' else 's' in - F.fprintf fmt "(%s-%c$%d)" (Typ.Procname.to_string pname) symbol_name id + fun fmt s -> + match s with + | Call {id; pname; unsigned; path; bound_end} | IntraProc {id; pname; unsigned; path; bound_end} + -> + SymbolPath.pp fmt path ; + if Config.developer_mode then Format.fprintf fmt ".%s" (BoundEnd.to_string bound_end) ; + if Config.bo_debug > 1 then + let symbol_name = if unsigned then 'u' else 's' in + F.fprintf fmt "(%s-%c$%d)" (Typ.Procname.to_string pname) symbol_name id let pp_mark ~markup = if markup then MarkupFormatter.wrap_monospaced pp else pp - let is_unsigned : t -> bool = fun x -> x.unsigned + let is_unsigned : t -> bool = function IntraProc {unsigned} | Call {unsigned} -> unsigned - let path {path} = path + let path = function IntraProc {path} | Call {path} -> path - let bound_end {bound_end} = bound_end + let bound_end = function IntraProc {bound_end} | Call {bound_end} -> bound_end end module SymbolTable = struct @@ -133,8 +183,15 @@ module SymbolTable = struct s | None -> let s = - ( Symbol.make ~unsigned pname path LowerBound (Counter.next new_sym_num) - , Symbol.make ~unsigned pname path UpperBound (Counter.next new_sym_num) ) + if + SymbolPath.represents_partial_sound ~f:SymbolPath.represents_callsite_sound_partial + path + then + ( Symbol.make_call ~unsigned pname path LowerBound (Counter.next new_sym_num) + , Symbol.make_call ~unsigned pname path UpperBound (Counter.next new_sym_num) ) + else + ( Symbol.make_intraproc ~unsigned pname path LowerBound (Counter.next new_sym_num) + , Symbol.make_intraproc ~unsigned pname path UpperBound (Counter.next new_sym_num) ) in symbol_table := M.add path s !symbol_table ; s diff --git a/infer/src/bufferoverrun/symb.mli b/infer/src/bufferoverrun/symb.mli index 0d6de8cec..0d923b9b1 100644 --- a/infer/src/bufferoverrun/symb.mli +++ b/infer/src/bufferoverrun/symb.mli @@ -21,6 +21,7 @@ module SymbolPath : sig | Pvar of Pvar.t | Deref of deref_kind * partial | Field of Typ.Fieldname.t * partial + | Callsite of CallSite.t [@@deriving compare] type t = private Normal of partial | Offset of partial | Length of partial @@ -33,6 +34,8 @@ module SymbolPath : sig val of_pvar : Pvar.t -> partial + val of_callsite : CallSite.t -> partial + val deref : deref_kind:deref_kind -> partial -> partial val field : partial -> Typ.Fieldname.t -> partial diff --git a/infer/tests/codetoanalyze/java/performance/.inferconfig b/infer/tests/codetoanalyze/java/performance/.inferconfig new file mode 100644 index 000000000..61c40d64c --- /dev/null +++ b/infer/tests/codetoanalyze/java/performance/.inferconfig @@ -0,0 +1,11 @@ +{ + "external-java-packages": [ + "android.", + "com.android.", + "com.fasterxml", + "com.google.", + "com.sun.", + "io.netty.", + "java.", + "org." + ]} diff --git a/infer/tests/codetoanalyze/java/performance/ArrayListTest.java b/infer/tests/codetoanalyze/java/performance/ArrayListTest.java index 7d5030172..31f3bfcf4 100644 --- a/infer/tests/codetoanalyze/java/performance/ArrayListTest.java +++ b/infer/tests/codetoanalyze/java/performance/ArrayListTest.java @@ -186,7 +186,8 @@ public class ArrayListTest { } } - // Control vars include element which is in [-oo,+oo]. Hence, we get T + // Control vars include element which is some intValue and list + // length. Hence, we get quadratic bound. // Simplified version of real code https://fburl.com/a3gge1b7 public boolean iterate_over_arraylist_shortcut_FP(ArrayList list) { for (Integer element : list) { diff --git a/infer/tests/codetoanalyze/java/performance/UnknownCallsTest.java b/infer/tests/codetoanalyze/java/performance/UnknownCallsTest.java new file mode 100644 index 000000000..c734a1cbd --- /dev/null +++ b/infer/tests/codetoanalyze/java/performance/UnknownCallsTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import org.json.JSONArray; + +class UnknownCallsTest { + + private int mBytesToRead; + + public void jsonArray_linear(JSONArray jsonArray) { + int length = jsonArray.length(); + for (int i = 0; i < length; ++i) {} + } + + // call to JSONArray.length is not modeled, hence the result will + // not be invariant. Therefore we get quadratic bound. + public void jsonArray_quadratic(JSONArray jsonArray) { + for (int i = 0; i < jsonArray.length(); ++i) {} + } + + public int read_sum_cost( + InputStream in, byte[] buffer, int byteOffset, int byteCount, ArrayList list) + throws IOException { + int maxBytesToRead = Math.min(byteCount, mBytesToRead); + int bytesRead = in.read(buffer, byteOffset, maxBytesToRead); + + for (int index = 0; index < bytesRead + maxBytesToRead; ++index) {} + return 0; + } + + // Expected: Max(Math,min(...), InputStream.read(....)) but we get T + public int read_max_cost( + InputStream in, byte[] buffer, int byteOffset, int byteCount, ArrayList list) + throws IOException { + int maxBytesToRead = Math.min(byteCount, mBytesToRead); + int bytesRead = in.read(buffer, byteOffset, maxBytesToRead); + // after the join, we get maxBytesToRead in [0, +oo]. Hence, the loop gets T + if (bytesRead > 0) { + maxBytesToRead = bytesRead + 1; + } + for (int index = 0; index < maxBytesToRead; ++index) {} + return 0; + } + + private static void loop_over_charArray(StringBuilder builder, String input) { + for (Character c : input.toCharArray()) {} + } + + // We can't instantiate loop_over_charArray properly because I don't + // know what to do with the symbol for the call to "toCharArray()" + private static void call_loop_over_charArray_FN(StringBuilder out, String in) { + loop_over_charArray(out, in); + } +} diff --git a/infer/tests/codetoanalyze/java/performance/issues.exp b/infer/tests/codetoanalyze/java/performance/issues.exp index c12605152..2a2e376fb 100644 --- a/infer/tests/codetoanalyze/java/performance/issues.exp +++ b/infer/tests/codetoanalyze/java/performance/issues.exp @@ -27,8 +27,11 @@ codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.arraylist_set_o codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.arraylist_set_underrun_bad():void, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Array declaration,Assignment,Array access: Offset: 0 Size: 0] codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist(java.util.ArrayList):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 7 + 5 ⋅ list.length.ub, degree = 1] codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist(java.util.ArrayList):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 5 ⋅ list.length.ub, degree = 1] -codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_shortcut_FP(java.util.ArrayList):boolean, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_shortcut_FP(java.util.ArrayList):boolean, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 13 ⋅ (list.length.ub - 1) + 2 ⋅ (list.length.ub - 1) × (-int Integer.intValue().lb + 11) + 4 ⋅ list.length.ub × (-int Integer.intValue().lb + 11), degree = 2] +codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_shortcut_FP(java.util.ArrayList):boolean, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 13 ⋅ (list.length.ub - 1) + 2 ⋅ (list.length.ub - 1) × (-int Integer.intValue().lb + 11) + 4 ⋅ list.length.ub × (-int Integer.intValue().lb + 11), degree = 2] codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_shortcut_FP(java.util.ArrayList):boolean, 2, BUFFER_OVERRUN_U5, no_bucket, ERROR, [,Unknown value from: __cast,Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]] +codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_shortcut_FP(java.util.ArrayList):boolean, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 13 ⋅ (list.length.ub - 1) + 2 ⋅ (list.length.ub - 1) × (-int Integer.intValue().lb + 11) + 4 ⋅ list.length.ub × (-int Integer.intValue().lb + 11), degree = 2] +codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_shortcut_FP(java.util.ArrayList):boolean, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 13 ⋅ (list.length.ub - 1) + 2 ⋅ (list.length.ub - 1) × (-int Integer.intValue().lb + 11) + 4 ⋅ list.length.ub × (-int Integer.intValue().lb + 11), degree = 2] codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_with_inner(java.util.ArrayList):void, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 8 + 13 ⋅ (list1.length.ub - 1) + 4 ⋅ list1.length.ub, degree = 1] codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_arraylist_with_inner(java.util.ArrayList):void, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 9 + 13 ⋅ (list1.length.ub - 1) + 4 ⋅ list1.length.ub, degree = 1] codetoanalyze/java/performance/ArrayListTest.java, ArrayListTest.iterate_over_local_arraylist(java.util.ArrayList):void, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 9 + 5 ⋅ list.length.ub, degree = 1] @@ -119,21 +122,12 @@ codetoanalyze/java/performance/Invariant.java, Invariant.x_is_invariant_ok(int): codetoanalyze/java/performance/IteratorTest.java, IteratorTest.appendTo(java.util.Iterator):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1 + 12 ⋅ (parts.length.ub - 1) + 4 ⋅ parts.length.ub, degree = 1] codetoanalyze/java/performance/IteratorTest.java, IteratorTest.appendTo(java.util.Iterator):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 12 ⋅ (parts.length.ub - 1) + 4 ⋅ parts.length.ub, degree = 1] codetoanalyze/java/performance/IteratorTest.java, IteratorTest.appendTo(java.util.Iterator):void, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1 + 12 ⋅ (parts.length.ub - 1) + 4 ⋅ parts.length.ub, degree = 1] -codetoanalyze/java/performance/JsonArray.java, libraries.marauder.analytics.utils.json.JsonArray.addStringEntry(java.lang.String):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,boolean):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,double):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,java.lang.Object):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,java.lang.String):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,libraries.marauder.analytics.utils.json.JsonType):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,libraries.marauder.analytics.utils.json.JsonType):void, 6, BUFFER_OVERRUN_U5, no_bucket, ERROR, [,Call,Unknown value from: StringBuilder StringBuilder.append(String),Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addEntry(java.lang.String,long):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, libraries.marauder.analytics.utils.json.JsonMap.addKeyToMap(java.lang.String):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonString.java, libraries.marauder.analytics.utils.json.JsonString.(java.lang.String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 1, BUFFER_OVERRUN_U5, no_bucket, ERROR, [,Assignment,,Unknown value from: char[] String.toCharArray(),Assignment,Array access: Offset: [-oo, +oo] (⇐ [-oo, +oo] + [0, +oo]) Size: [0, +oo]] -codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 1, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] -codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.serialize(java.lang.String):java.lang.StringBuilder, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.serialize(java.lang.StringBuilder,java.lang.String):void, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 11 + 74 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 10 + 74 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 10 + 74 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 10 + 74 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 10 + 74 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/JsonUtils.java, libraries.marauder.analytics.utils.json.JsonUtils.escape(java.lang.StringBuilder,java.lang.String):void, 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 10 + 74 ⋅ (char[] String.toCharArray().length.ub), degree = 1] codetoanalyze/java/performance/Loops.java, codetoanalyze.java.performance.Loops.do_while_independent_of_p(int):int, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 250, degree = 0] codetoanalyze/java/performance/Loops.java, codetoanalyze.java.performance.Loops.do_while_independent_of_p(int):int, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 251, degree = 0] codetoanalyze/java/performance/Loops.java, codetoanalyze.java.performance.Loops.do_while_independent_of_p(int):int, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 250, degree = 0] @@ -159,3 +153,13 @@ codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switc codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switch.test_switch():int, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 798, degree = 0] codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switch.test_switch():int, 13, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 798, degree = 0] codetoanalyze/java/performance/Switch.java, codetoanalyze.java.performance.Switch.vanilla_switch(int):void, 2, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.jsonArray_linear(org.json.JSONArray):void, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 7 + 5 ⋅ (int JSONArray.length().ub), degree = 1] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.jsonArray_linear(org.json.JSONArray):void, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 5 ⋅ (int JSONArray.length().ub), degree = 1] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.jsonArray_quadratic(org.json.JSONArray):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ (int JSONArray.length().ub)² + 4 ⋅ (1+max(0, int JSONArray.length().ub)), degree = 2] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.jsonArray_quadratic(org.json.JSONArray):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 5 ⋅ (int JSONArray.length().ub)² + 4 ⋅ (1+max(0, int JSONArray.length().ub)), degree = 2] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.loop_over_charArray(java.lang.StringBuilder,java.lang.String):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 11 + 13 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.loop_over_charArray(java.lang.StringBuilder,java.lang.String):void, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 10 + 13 ⋅ (char[] String.toCharArray().length.ub), degree = 1] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.read_max_cost(java.io.InputStream,byte[],int,int,java.util.ArrayList):int, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.read_max_cost(java.io.InputStream,byte[],int,int,java.util.ArrayList):int, 9, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [,Assignment,Binary operation: ([0, +oo] + 1):signed32] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.read_sum_cost(java.io.InputStream,byte[],int,int,java.util.ArrayList):int, 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 16 + 6 ⋅ (int InputStream.read(byte[],int,int).ub + int Math.min(int,int).ub), degree = 1] +codetoanalyze/java/performance/UnknownCallsTest.java, UnknownCallsTest.read_sum_cost(java.io.InputStream,byte[],int,int,java.util.ArrayList):int, 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 17 + 6 ⋅ (int InputStream.read(byte[],int,int).ub + int Math.min(int,int).ub), degree = 1]