From cb8e734bbb70054a6a1c418ebc978b6080af268a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezgi=20=C3=87i=C3=A7ek?= Date: Thu, 7 Jun 2018 03:40:22 -0700 Subject: [PATCH] Get all the loop instructions Reviewed By: mbouaziz Differential Revision: D7776833 fbshipit-source-id: fb292a4 --- infer/src/IR/Sil.ml | 2 - infer/src/IR/Sil.mli | 2 - infer/src/checkers/control.ml | 99 ++++++++----- infer/src/checkers/cost.ml | 3 + infer/src/checkers/loop_control.ml | 130 ++++++++++++++++++ infer/src/jbuild.common.in | 4 +- .../tests/codetoanalyze/c/performance/break.c | 36 +++++ .../c/performance/compound_loop_guard.c | 47 +++++-- .../c/performance/cost_test_deps.c | 53 +++++++ .../codetoanalyze/c/performance/issues.exp | 47 ++++++- .../c/performance/jump_inside_loop.c | 28 +++- .../tests/codetoanalyze/c/performance/loops.c | 37 +++++ .../codetoanalyze/java/performance/Break.java | 30 ++++ .../java/performance/Compound_loop.java | 43 ++++++ .../java/performance/Cost_test.java | 122 ++++++++++++++++ .../java/performance/Cost_test_deps.java | 113 +++++++++++++++ .../codetoanalyze/java/performance/issues.exp | 57 ++++++-- 17 files changed, 787 insertions(+), 66 deletions(-) create mode 100644 infer/src/checkers/loop_control.ml create mode 100644 infer/tests/codetoanalyze/c/performance/break.c create mode 100644 infer/tests/codetoanalyze/c/performance/loops.c create mode 100644 infer/tests/codetoanalyze/java/performance/Break.java create mode 100644 infer/tests/codetoanalyze/java/performance/Compound_loop.java create mode 100644 infer/tests/codetoanalyze/java/performance/Cost_test.java create mode 100644 infer/tests/codetoanalyze/java/performance/Cost_test_deps.java diff --git a/infer/src/IR/Sil.ml b/infer/src/IR/Sil.ml index 1316cc6e3..d644f0d15 100644 --- a/infer/src/IR/Sil.ml +++ b/infer/src/IR/Sil.ml @@ -53,8 +53,6 @@ type instr = | Declare_locals of (Pvar.t * Typ.t) list * Location.t (** declare local variables *) [@@deriving compare] -let is_loop = function Ik_dowhile | Ik_while | Ik_for -> true | _ -> false - let equal_instr = [%compare.equal : instr] let skip_instr = Remove_temps ([], Location.dummy) diff --git a/infer/src/IR/Sil.mli b/infer/src/IR/Sil.mli index 0777731d5..96cd0103f 100644 --- a/infer/src/IR/Sil.mli +++ b/infer/src/IR/Sil.mli @@ -23,8 +23,6 @@ type if_kind = | Ik_switch [@@deriving compare] -val is_loop : if_kind -> bool - (** An instruction. *) type instr = (* Note for frontend writers: diff --git a/infer/src/checkers/control.ml b/infer/src/checkers/control.ml index 562a50c30..b9f40bad0 100644 --- a/infer/src/checkers/control.ml +++ b/infer/src/checkers/control.ml @@ -8,11 +8,16 @@ open! IStd module F = Format module L = Logging -(* forward dependency analysis for computing set of variables that affect the control flow at each program point - 1. perform a control flow dependency analysis CF dependency analysis by - getting all the variables that appear in the control flow path up to that node. +(* forward dependency analysis for computing set of variables that + affect the control flow at each program point + + 1. perform a control flow dependency analysis by getting all the + variables that appear in the control flow path up to that node. + 2. perform a data dependency analysis - 3. for each control dependency per node, find its respective data dependencies *) + + 3. for each control dependency per node, find its respective data + dependencies *) module VarSet = AbstractDomain.FiniteSet (Var) module DataDepSet = VarSet @@ -71,41 +76,71 @@ module TransferFunctionsDataDeps (CFG : ProcCfg.S) = struct end module ControlDepSet = VarSet +module GuardNodes = AbstractDomain.FiniteSet (Procdesc.Node) + +(** Map exit node -> prune nodes in the loop guard *) +module ExitNodeToGuardNodes = AbstractDomain.Map (Procdesc.Node) (GuardNodes) + +(** Map loop header node -> prune nodes in the loop guard *) +module LoopHeaderToGuardNodes = AbstractDomain.Map (Procdesc.Node) (GuardNodes) + +type loop_control_maps = + {exit_map: ExitNodeToGuardNodes.astate; loop_header_map: LoopHeaderToGuardNodes.astate} (* forward transfer function for control dependencies *) module TransferFunctionsControlDeps (CFG : ProcCfg.S) = struct module CFG = CFG module Domain = ControlDepSet - type extras = ProcData.no_extras + type extras = loop_control_maps - let exec_instr astate _ _ instr = - match instr with - | Sil.Prune (exp, _, true_branch, if_kind) -> - (* Only keep track of control flow variables for loop prune nodes with the true branch *) - (* For false branches, remove the var from the set for fixpoint *) - let astate' = - Exp.free_vars exp |> Sequence.map ~f:Var.of_id |> Sequence.to_list - |> ControlDepSet.of_list - |> - if (true_branch && Sil.is_loop if_kind) || Language.curr_language_is Java then - Domain.union astate - else Domain.diff astate - in - Exp.program_vars exp |> Sequence.map ~f:Var.of_pvar |> Sequence.to_list - |> ControlDepSet.of_list - |> - if (true_branch && Sil.is_loop if_kind) || Language.curr_language_is Java then - Domain.union astate' - else Domain.diff astate' - | Sil.Load _ - | Sil.Store _ - | Sil.Call _ - | Declare_locals _ - | Remove_temps _ - | Abstract _ - | Nullify _ -> - astate + let get_vars_in_exp exp = + let aux f_free_vars f_to_var = + f_free_vars exp |> Sequence.map ~f:f_to_var |> Sequence.to_list |> ControlDepSet.of_list + in + assert (Domain.is_empty (aux Exp.program_vars Var.of_pvar)) ; + (* We should never have program variables in prune nodes *) + aux Exp.free_vars Var.of_id + + + (* extract vars from the prune instructions in the node *) + let get_control_vars loop_nodes = + GuardNodes.fold + (fun loop_node acc -> + let instrs = Procdesc.Node.get_instrs loop_node in + Instrs.fold ~init:acc + ~f:(fun astate instr -> + match instr with + | Sil.Prune (exp, _, _, _) -> + Domain.union (get_vars_in_exp exp) astate + | _ -> + (* prune nodes include other instructions like REMOVE_TEMPS *) + astate ) + instrs ) + loop_nodes Domain.empty + + + (* Each time we pass through + - a loop header, add control variables of its guard nodes + - a loop exit node, remove control variables of its guard nodes + This is correct because the CVs are only going to be temporaries. *) + let exec_instr astate {ProcData.extras= {exit_map; loop_header_map}} (node: CFG.Node.t) _ = + let node = CFG.Node.underlying_node node in + let astate' = + match LoopHeaderToGuardNodes.find_opt node loop_header_map with + | Some loop_nodes -> + L.(debug Analysis Medium) "@\n>>> Loop header %a \n" Procdesc.Node.pp node ; + Domain.union astate (get_control_vars loop_nodes) + | _ -> + astate + in + match ExitNodeToGuardNodes.find_opt node exit_map with + | Some loop_nodes -> + L.(debug Analysis Medium) + "@\n>>>Exit node %a loop nodes=%a @\n\n" Procdesc.Node.pp node GuardNodes.pp loop_nodes ; + get_control_vars loop_nodes |> Domain.diff astate' + | _ -> + astate' let pp_session_name node fmt = diff --git a/infer/src/checkers/cost.ml b/infer/src/checkers/cost.ml index 6aaaa0cae..00661d376 100644 --- a/infer/src/checkers/cost.ml +++ b/infer/src/checkers/cost.ml @@ -553,6 +553,8 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Summary.t = in let proc_data = ProcData.make_default proc_desc tenv in let node_cfg = NodeCFG.from_pdesc proc_desc in + (* collect all prune nodes that occur in loop guards, needed for ControlDepAnalyzer *) + let control_maps = Loop_control.get_control_maps node_cfg in (* computes the data dependencies: node -> (var -> var set) *) let data_dep_invariant_map = Control.DataDepAnalyzer.exec_cfg node_cfg proc_data ~initial:Control.DataDepMap.empty @@ -560,6 +562,7 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Summary.t = in (* computes the control dependencies: node -> var set *) let control_dep_invariant_map = + let proc_data = ProcData.make proc_desc tenv control_maps in Control.ControlDepAnalyzer.exec_cfg node_cfg proc_data ~initial:Control.ControlDepSet.empty ~debug:true in diff --git a/infer/src/checkers/loop_control.ml b/infer/src/checkers/loop_control.ml new file mode 100644 index 000000000..96668f535 --- /dev/null +++ b/infer/src/checkers/loop_control.ml @@ -0,0 +1,130 @@ +(* + * 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. + *) + +open! IStd +module L = Logging + +let nid_int n = (Procdesc.Node.get_id n :> int) + +type edge_type = {source: Procdesc.Node.t; target: Procdesc.Node.t} [@@deriving compare] + +(* Find back-edges by using Tarjan's DFS traversal *) +(* instead of marking, we keep track of the pred node we came from *) +let get_back_edges pdesc = + let rec aux visited back_edges wl = + match wl with + | [] -> + back_edges + | (n, pred, ancestors) :: wl' -> + if Procdesc.NodeSet.mem n visited then + if Procdesc.NodeSet.mem n ancestors then + let back_edges' = + match pred with + | Some n_parent -> + {source= n_parent; target= n} :: back_edges + | None -> + assert false + in + aux visited back_edges' wl' + else aux visited back_edges wl' + else + let ancestors = Procdesc.NodeSet.add n ancestors in + let works = + List.fold ~init:wl' + ~f:(fun acc m -> (m, Some n, ancestors) :: acc) + (Procdesc.Node.get_succs n) + in + aux (Procdesc.NodeSet.add n visited) back_edges works + in + let start_wl = [(Procdesc.get_start_node pdesc, None, Procdesc.NodeSet.empty)] in + aux Procdesc.NodeSet.empty [] start_wl + + +(* Get a set of nodes, `exit_nodes`, that themselves are not in the loop but their predecessors are + + Visually: + + target + /| + / . + / | + . node_in_loop + . |\ + . . \ + . . exit_node + \ . + \ | + \| + source + + Often, exit_node is a prune node. *) +let get_exit_nodes_in_loop loop_nodes = + let succs_of_loop_nodes = + Control.GuardNodes.fold + (fun n acc -> + Procdesc.Node.get_succs n |> Control.GuardNodes.of_list |> Control.GuardNodes.union acc ) + loop_nodes Control.GuardNodes.empty + in + Control.GuardNodes.diff succs_of_loop_nodes loop_nodes |> Control.GuardNodes.elements + + +(* Starting from the start_nodes, find all the nodes upwards until the + target is reached, i.e picking up predecessors which have not been + already added to the found_nodes *) +let get_all_nodes_upwards_until target start_nodes = + let rec aux found_nodes = function + | [] -> + found_nodes + | node :: wl' -> + if Control.GuardNodes.mem node found_nodes then aux found_nodes wl' + else + let preds = Procdesc.Node.get_preds node in + aux (Control.GuardNodes.add node found_nodes) (List.append preds wl') + in + aux (Control.GuardNodes.singleton target) start_nodes + + +let is_prune node = + match Procdesc.Node.get_kind node with Procdesc.Node.Prune_node _ -> true | _ -> false + + +(* Get a pair of two maps (exit_to_guard_map, loop_header_to_guard_map) where + exit_to_guard_map : exit_node -> guard_nodes + loop_header_to_guard_map : loop_header (i.e. target of the back edge) -> guard_nodes and + guard_nodes contains the nodes that may affect the looping behavior, i.e. + occur in the guard of the loop conditional. *) +let get_control_maps cfg = + (* get back edges*) + let back_edge_set = get_back_edges cfg in + List.fold_left + ~f:(fun Control.({exit_map; loop_header_map}) {source; target} -> + L.(debug Analysis Medium) + "Back-edge source: %i -> target: %i\n" (nid_int source) (nid_int target) ; + let loop_nodes = get_all_nodes_upwards_until target [source] in + let exit_nodes = get_exit_nodes_in_loop loop_nodes in + (* find all the prune nodes in the loop guard *) + let guard_prune_nodes = + get_all_nodes_upwards_until target exit_nodes |> Control.GuardNodes.filter is_prune + in + let exit_map' = + (List.fold_left ~init:exit_map ~f:(fun acc exit_node -> + (*Make sure an exit node only belongs to a single loop *) + assert (not (Control.ExitNodeToGuardNodes.mem exit_node acc)) ; + Control.ExitNodeToGuardNodes.add exit_node guard_prune_nodes acc )) + exit_nodes + in + let loop_map' = + (*Make sure a loop header only belongs to a single loop *) + assert (not (Control.LoopHeaderToGuardNodes.mem target loop_header_map)) ; + Control.LoopHeaderToGuardNodes.add target guard_prune_nodes loop_header_map + in + Control.{exit_map= exit_map'; loop_header_map= loop_map'} ) + back_edge_set + ~init: + Control. + { exit_map= Control.ExitNodeToGuardNodes.empty + ; loop_header_map= Control.LoopHeaderToGuardNodes.empty } diff --git a/infer/src/jbuild.common.in b/infer/src/jbuild.common.in index 8e69d2f79..f1579a19d 100644 --- a/infer/src/jbuild.common.in +++ b/infer/src/jbuild.common.in @@ -28,7 +28,9 @@ let facebook = is_yes "@IS_FACEBOOK_TREE@" let extra_cflags = if "@EXTRA_CFLAGS" = "" then [] else ["@EXTRA_CFLAGS@"] let common_cflags = - let fatal_warnings = "+3+5+6+8+10+11+12+18+19+20+21+23+26+29+27+32+33+34+35+37+38+39+50+52+57+60" in + let fatal_warnings = + "+3+5+6+8+10+11+12+18+19+20+21+23+26+29+27+32+33+34+35+37+38+39+50+52+57+60" + in let warnings = fatal_warnings ^ "-4-9-40-41-42-45-48" in let common_flags = [ "-g" diff --git a/infer/tests/codetoanalyze/c/performance/break.c b/infer/tests/codetoanalyze/c/performance/break.c new file mode 100644 index 000000000..b6559c66a --- /dev/null +++ b/infer/tests/codetoanalyze/c/performance/break.c @@ -0,0 +1,36 @@ +/* + * 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. + */ +/* t is also in control variables but once we have invariant analysis, it + * shouldn't be */ +int break_loop(int p, int t) { + for (int i = 0; i < p; i++) { + // do something + if (t < 0) + break; + // do something + } + return 0; +} + +/* t will be in control variables but once we have invariant analysis, + * it shouldn't be. */ +int break_loop_with_t(int p, int t) { + for (int i = 0; i < p; i++) { + // do something + if (t < 0) { + t++; + break; + } + // do something + } + return 0; +} + +/* calling break_loop with a negative t should give constant + cost. Currently, this doesn't work since we can't do case analysis + on the domain. */ +int break_constant(int p) { return break_loop(p, -1); } diff --git a/infer/tests/codetoanalyze/c/performance/compound_loop_guard.c b/infer/tests/codetoanalyze/c/performance/compound_loop_guard.c index 4514642eb..a31d9b058 100644 --- a/infer/tests/codetoanalyze/c/performance/compound_loop_guard.c +++ b/infer/tests/codetoanalyze/c/performance/compound_loop_guard.c @@ -15,9 +15,8 @@ int compound_while(int m) { return j; } -/* B will be in the loop and executed ~100 times-- we get infinity due to - * control variable problem with gotos */ -int simulated_while_with_and(int p) { +/* this should give Theta(100) once we have extract_post in the range */ +int simplified_simulated_while_with_and(int p) { int k = 0; int j = 0; B: @@ -28,6 +27,23 @@ B: return k; } +/* simulated goto that contains && */ +int simulated_while_with_and(int p) { + int i = 0; + int k = 0; +LOOP_COND: + if (k == 0 && i < p) { + goto INCR; + } else { + goto RETURN; + } +INCR: + i++; + goto LOOP_COND; +RETURN: + return i; +} + /* shortcut in the conditional, hence we won't loop, and get constant cost */ int simulated_while_shortcut(int p) { int k = 0; @@ -43,18 +59,17 @@ B: /* p should be in control vars */ void while_and_or(int p) { int i = 0; - while (p == 1 || (i < 30 && i > 0)) { + while (p == 1 || (i < 30 && i >= 0)) { i++; } } -// should be constant cost, but due to p occuring in control vars, we would get -// +oo for p +// should be constant cost int nested_while_and_or(int p) { int i = 0; int j = 3 * i; - while (p == 1 || (i < 30 && i > 0)) { - while (p == 1 || (j < 5 && j > 0)) { + while (p == 1 || (i < 30 && i >= 0)) { + while (p == 1 || (j < 5 && j >= 0)) { return j; } @@ -62,3 +77,19 @@ int nested_while_and_or(int p) { } return j; } + +/* k,j and i will be control variables for B */ +int simulated_nested_loop_with_and(int p) { + int k = 0; + int t = 5; + int j = 0; + for (int i = 0; i < 5; i++) { + B: + t = 3; + j++; + if (k == 0 && j < 100) { + goto B; // continue; + } + } + return k; +} diff --git a/infer/tests/codetoanalyze/c/performance/cost_test_deps.c b/infer/tests/codetoanalyze/c/performance/cost_test_deps.c index 0f7383ca8..886e40406 100644 --- a/infer/tests/codetoanalyze/c/performance/cost_test_deps.c +++ b/infer/tests/codetoanalyze/c/performance/cost_test_deps.c @@ -149,3 +149,56 @@ int simulated_nested_loop_more_expensive(int p) { } return k; } + +int real_while() { + int i = 0; + int j = 3 * i; + while (i < 30) { + j = j + i; + i++; + } + return j; +} + +// Examples with gotos + +/* The following program is the version of real_while() with gotos */ + +int simulated_while() { + int i = 0; + int j = 3 * i; +LOOP_COND: + if (i < 30) { + goto INCR; + } else { + goto RETURN; + } +INCR: + j = j + i; + i++; + goto LOOP_COND; +RETURN: + return j; +} + +/* Conditional inside goto loop */ +int simulated_nested_loop_cond_in_goto(int p) { + int k = 0; + int t = 5; + int j = 0; + for (int i = 0; i < 5; i++) { + B: + if (i > 2) { + t = 3; + } else { + t = 4; + } + j++; + if (j >= 100) + j = 0; + else { + goto B; // continue; + } + } + return k; +} diff --git a/infer/tests/codetoanalyze/c/performance/issues.exp b/infer/tests/codetoanalyze/c/performance/issues.exp index 5fe76e685..803101fab 100644 --- a/infer/tests/codetoanalyze/c/performance/issues.exp +++ b/infer/tests/codetoanalyze/c/performance/issues.exp @@ -1,14 +1,37 @@ +codetoanalyze/c/performance/break.c, break_constant, 0, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 7 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop_with_t, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop_with_t, 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop_with_t, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 7 * s$1] +codetoanalyze/c/performance/break.c, break_loop_with_t, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * s$1] codetoanalyze/c/performance/compound_loop_guard.c, compound_while, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] codetoanalyze/c/performance/compound_loop_guard.c, compound_while, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 7 + 7 * s$1] codetoanalyze/c/performance/compound_loop_guard.c, compound_while, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 7 + 7 * s$1] codetoanalyze/c/performance/compound_loop_guard.c, compound_while, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 7 + 7 * s$1] codetoanalyze/c/performance/compound_loop_guard.c, compound_while, 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 9 + 7 * s$1] -codetoanalyze/c/performance/compound_loop_guard.c, nested_while_and_or, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/c/performance/compound_loop_guard.c, nested_while_and_or, 4, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, nested_while_and_or, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, nested_while_and_or, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] codetoanalyze/c/performance/compound_loop_guard.c, nested_while_and_or, 4, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, nested_while_and_or, 4, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, simplified_simulated_while_with_and, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 601] +codetoanalyze/c/performance/compound_loop_guard.c, simplified_simulated_while_with_and, 5, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, simplified_simulated_while_with_and, 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 602] +codetoanalyze/c/performance/compound_loop_guard.c, simplified_simulated_while_with_and, 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 601] +codetoanalyze/c/performance/compound_loop_guard.c, simplified_simulated_while_with_and, 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 601] +codetoanalyze/c/performance/compound_loop_guard.c, simplified_simulated_while_with_and, 8, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 603] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_nested_loop_with_and, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_nested_loop_with_and, 8, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_shortcut, 5, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [] -codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_with_and, 5, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_with_and, 4, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_with_and, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 7 * s$1] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_with_and, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 7 * s$1] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_with_and, 10, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 7 * s$1] +codetoanalyze/c/performance/compound_loop_guard.c, simulated_while_with_and, 13, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 8 + 7 * s$1] codetoanalyze/c/performance/compound_loop_guard.c, while_and_or, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/c/performance/compound_loop_guard.c, while_and_or, 2, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] codetoanalyze/c/performance/cost_test.c, loop0_bad, 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1002] codetoanalyze/c/performance/cost_test.c, loop0_bad, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1002] codetoanalyze/c/performance/cost_test.c, loop0_bad, 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1004] @@ -35,8 +58,15 @@ codetoanalyze/c/performance/cost_test_deps.c, loop_no_dep2, 3, EXPENSIVE_EXECUTI codetoanalyze/c/performance/cost_test_deps.c, loop_no_dep2, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 609] codetoanalyze/c/performance/cost_test_deps.c, loop_no_dep2, 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 611] codetoanalyze/c/performance/cost_test_deps.c, nested_loop, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/c/performance/cost_test_deps.c, real_while, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 214] +codetoanalyze/c/performance/cost_test_deps.c, real_while, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 214] +codetoanalyze/c/performance/cost_test_deps.c, real_while, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 216] codetoanalyze/c/performance/cost_test_deps.c, simulated_nested_loop, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/c/performance/cost_test_deps.c, simulated_nested_loop_cond_in_goto, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] codetoanalyze/c/performance/cost_test_deps.c, simulated_nested_loop_more_expensive, 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/c/performance/cost_test_deps.c, simulated_while, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 214] +codetoanalyze/c/performance/cost_test_deps.c, simulated_while, 10, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 214] +codetoanalyze/c/performance/cost_test_deps.c, simulated_while, 14, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 216] codetoanalyze/c/performance/cost_test_deps.c, two_loops, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 545] codetoanalyze/c/performance/cost_test_deps.c, two_loops, 8, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 545] codetoanalyze/c/performance/cost_test_deps.c, two_loops, 10, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 547] @@ -52,6 +82,17 @@ codetoanalyze/c/performance/invariant.c, do_k_times, 2, EXPENSIVE_EXECUTION_TIME codetoanalyze/c/performance/jump_inside_loop.c, jump_inside_loop, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2002] codetoanalyze/c/performance/jump_inside_loop.c, jump_inside_loop, 9, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2002] codetoanalyze/c/performance/jump_inside_loop.c, jump_inside_loop, 11, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2004] +codetoanalyze/c/performance/loops.c, if_in_loop, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 8, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 9, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 320] +codetoanalyze/c/performance/loops.c, if_in_loop, 13, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 322] +codetoanalyze/c/performance/loops.c, if_out_loop, 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 508] +codetoanalyze/c/performance/loops.c, if_out_loop, 8, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 508] +codetoanalyze/c/performance/loops.c, if_out_loop, 11, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 513] codetoanalyze/c/performance/two_loops_symbolic.c, two_loops_symb, 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 4 + 6 * s$1] codetoanalyze/c/performance/two_loops_symbolic.c, two_loops_symb, 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 4 + 6 * s$1] codetoanalyze/c/performance/two_loops_symbolic.c, two_loops_symb, 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 8 + 12 * s$1] diff --git a/infer/tests/codetoanalyze/c/performance/jump_inside_loop.c b/infer/tests/codetoanalyze/c/performance/jump_inside_loop.c index f863a44fa..f6f35c7ba 100644 --- a/infer/tests/codetoanalyze/c/performance/jump_inside_loop.c +++ b/infer/tests/codetoanalyze/c/performance/jump_inside_loop.c @@ -1,12 +1,30 @@ /* - * Copyright (c) 2018 - present Facebook, Inc. - * All rights reserved. + * Copyright (c) 2018-present, Facebook, Inc. * - * This source code is licensed under the BSD style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ +/* With the dominator approach, we can't find any back-edges here + since there are two entry points to the loop and there is no single + back edge to a single loop entry point, but only to the beginning + of the Loop label. With Tarjan's DFS approach, we can identify the + back-edge to the Loop label, and we are able to detect two + exit-edges correctly. + */ +int loop_always(int p) { + int i = 0; + if (p > 0) { + goto Loop; + } + + while (i < 5) { + Loop: + i++; + } + return 1; +} + int jump_inside_loop(int p) { int i = 0; if (p > 0) { diff --git a/infer/tests/codetoanalyze/c/performance/loops.c b/infer/tests/codetoanalyze/c/performance/loops.c new file mode 100644 index 000000000..0cf976fb5 --- /dev/null +++ b/infer/tests/codetoanalyze/c/performance/loops.c @@ -0,0 +1,37 @@ +/* + * 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. + */ +// j is not a control var, so shouldn't affect the bound +int if_in_loop(int t) { + int p = 0; + int j = t + 1; + for (int i = 0; i < 5; i++) { + if (j < 2) { + p++; + } else { + p = 3; + for (int k = 0; k < 10; k++) { + int m = 0; + } + } + } + return p; +} + +// j is not a control var, so shouldn't affect the bound +int if_out_loop(int t) { + int p = 10; + int j = t + 10; + if (j < 2) { + p++; + } else { + p = 3; + for (int k = 0; k < 100; k++) { + int m = 0; + } + } + return p; +} diff --git a/infer/tests/codetoanalyze/java/performance/Break.java b/infer/tests/codetoanalyze/java/performance/Break.java new file mode 100644 index 000000000..1eff5071f --- /dev/null +++ b/infer/tests/codetoanalyze/java/performance/Break.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package codetoanalyze.java.performance; + +public class Break{ +/* t is also in control variables but once we have invariant analysis, it shouldn't be */ +private static int break_loop(int p, int t){ +for (int i = 0; i < p; i++) { + // do something + if (t < 0) + break; + // do something +} + return 0; +} + + +/* calling break_loop with a negative t should give constant + cost. Currently, this doesn't work because parameters are removed + when computing the env size :( */ +private static int break_constant(int p) +{ + return break_loop(p, -1); +} + +} diff --git a/infer/tests/codetoanalyze/java/performance/Compound_loop.java b/infer/tests/codetoanalyze/java/performance/Compound_loop.java new file mode 100644 index 000000000..2b0cfe02b --- /dev/null +++ b/infer/tests/codetoanalyze/java/performance/Compound_loop.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package codetoanalyze.java.performance; + +public class Compound_loop{ + +/* while loop that contains && in the guard. It gives the correct bound */ +private static int compound_while(int m) { + int i = 0; + int j = 3 * i; + while (j == 0 && i < m) { + i++; + } + return j; +} + +/* p should be in control vars */ +private static void while_and_or(int p) { + int i = 0; + while (p == 1 || (i < 30 && i >= 0)) { + i++; + } +} + +// should be constant cost +int nested_while_and_or(int p) { + int i = 0; + int j = 3 * i; + while (p == 1 || (i < 30 && i >= 0)) { + while (p == 1 || (j < 5 && j >= 0)) { + + return j; + } + i++; + } + return j; +} + +} diff --git a/infer/tests/codetoanalyze/java/performance/Cost_test.java b/infer/tests/codetoanalyze/java/performance/Cost_test.java new file mode 100644 index 000000000..cf8088804 --- /dev/null +++ b/infer/tests/codetoanalyze/java/performance/Cost_test.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015-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. + */ + +package codetoanalyze.java.performance; + +public class Cost_test{ + +// Cost: 5 +private static int foo_OK() { + int i, j; + i = 17; + j = 31; + + return i + j + 3 + 7; +} + +// Cost: 17 +private static int bar_OK() { + + int j = 0; + + j++; + j++; + j++; + j = foo_OK(); + j++; + + return j; +} + +// Cost: 25 +private static int cond_OK(int i) { + int x; + + if (i < 0) { + x = bar_OK(); + } else { + x = 1; + } + return x; +} + +// Cost: 5 +private static void alias_OK() { + + int i = 0, j; + + j = i; + i = ++i; +} + +// Cost: 7 +private static void alias2_OK() { + + int i = 0, j, z; + + j = 1; + z = 2; + + j = i; + i = z; +} + +// Cost: 1101 +private static int loop0_bad() { + + for (int i = 0; i < 100; i++) { + alias2_OK(); + } + return 0; +} + +// Cost: 1203 +private static int loop1_bad() { + + int k = 100; + for (int i = 0; i < k; i++) { + alias2_OK(); + } + return 0; +} + +// Expected: Linear bound +private static int FN_loop2(int k) { + + for (int i = 0; i < k; i++) { + alias2_OK(); + } + return 0; +} + +// Expected: constant, but the bound is a polynomial since we can't +// currently map variables to polynomial symbols +private static int FN_loop3(int k) { + + for (int i = k; i < k + 15; i++) { + alias2_OK(); + } + return 0; +} + +// Cost: 218 +// Shows that calling many times non expensive function can +// result in an expensive computation +private static int main_bad() { + + int k1, k2, k3, k4; + + cond_OK(2); + k1 = bar_OK() + foo_OK() + cond_OK(15) * 2; + k2 = bar_OK() + foo_OK() + cond_OK(17) * 3; + k3 = bar_OK() + foo_OK() + cond_OK(11) * 3; + k4 = bar_OK() + foo_OK() + cond_OK(19) * 3; + return 0; +} + + +} diff --git a/infer/tests/codetoanalyze/java/performance/Cost_test_deps.java b/infer/tests/codetoanalyze/java/performance/Cost_test_deps.java new file mode 100644 index 000000000..c463eaea1 --- /dev/null +++ b/infer/tests/codetoanalyze/java/performance/Cost_test_deps.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015-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. + */ + +package codetoanalyze.java.performance; + +public class Cost_test_deps{ + + +// Loop's execution count doesn't depend on values of p,t,k +private static int loop_no_dep1(int k) { + int p = 0; + int t = 2 + k; + for (int i = 0; i < 100; i++) { + p++; + } + return p; +} + +private static int foo(int i, int j) { return i + j; } + + // Loop's execution count doesn't depend on values of p,t,k +private static int loop_no_dep2(int k) { + int p = 0; + int t = foo(p, k); + for (int i = 0; i < 100; i++) { + p++; + } + return p; +} + +private static void if_bad(int j) { + int p = 10; + if (p < 10 + j) { + p++; + } else { + p = j + 3; + for (int k = 0; k < 100; k++) { + j += 3; + } + } +} + +private static int if_bad_loop() { + int p = 10; + for (int j = 0; j < 5; j++) { + if (j < 2) { + p++; + } else { + p = 3; + for (int k = 0; k < 10; k++) { + int m = 0; + } + } + } + return p; +} + + + private static int two_loops() { + int p = 10; + int k = 3; + int t = 2 + k; + for (int j = 0; j < 6; j++) { + k++; + } + for (int i = 0; i < 100; i++) { + p = 3; + } + return p; +} + +private static int loop_despite_inferbo(int p) { + + int k = 100; + for (int i = 0; i < k; i++) { + int m = p + 3; + if (m < 14) { + p += 9; + } + } + return p; +} + + +private static int nested_loop() { + int k = 0; + for (int i = 0; i < 5; i++) { + A: + k = 0; + for (int j = 0; j < 100; j++) { + k = 3; + } + } + return k; +} + + +private static int real_while() +{ + int i = 0; + int j = 3 * i; + while (i < 30){ + j=j+i; + i++; + } + return j; +} + +} diff --git a/infer/tests/codetoanalyze/java/performance/issues.exp b/infer/tests/codetoanalyze/java/performance/issues.exp index 044791aca..a1107ea4c 100644 --- a/infer/tests/codetoanalyze/java/performance/issues.exp +++ b/infer/tests/codetoanalyze/java/performance/issues.exp @@ -1,16 +1,47 @@ -codetoanalyze/java/performance/ArrayCost.java, boolean ArrayCost.isPowOfTwo_FP(int), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/ArrayCost.java, boolean ArrayCost.isPowOfTwo_FP(int), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 883] +codetoanalyze/java/performance/ArrayCost.java, boolean ArrayCost.isPowOfTwo_FP(int), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 882] +codetoanalyze/java/performance/ArrayCost.java, boolean ArrayCost.isPowOfTwo_FP(int), 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 882] +codetoanalyze/java/performance/ArrayCost.java, boolean ArrayCost.isPowOfTwo_FP(int), 12, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 889] codetoanalyze/java/performance/ArrayCost.java, void ArrayCost.ArrayCost(int[]), 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 5 * s$7^2] codetoanalyze/java/performance/ArrayCost.java, void ArrayCost.ArrayCost(int[]), 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 5 * s$7^2] -codetoanalyze/java/performance/JsonArray.java, void JsonArray.addStringEntry(String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,JsonType), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,Object), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,boolean), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,double), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,long), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonMap.java, void JsonMap.addKeyToMap(String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonString.java, JsonString.(String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonUtils.java, StringBuilder JsonUtils.serialize(String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] -codetoanalyze/java/performance/JsonUtils.java, void JsonUtils.escape(StringBuilder,String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/Break.java, int Break.break_constant(int), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 8 + 7 * s$1] +codetoanalyze/java/performance/Break.java, int Break.break_loop(int,int), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1 + 7 * s$1] +codetoanalyze/java/performance/Break.java, int Break.break_loop(int,int), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 7 * s$1] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * s$1] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * s$1] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.nested_while_and_or(int), 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.nested_while_and_or(int), 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.nested_while_and_or(int), 4, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.nested_while_and_or(int), 4, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/java/performance/Compound_loop.java, void Compound_loop.while_and_or(int), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/Compound_loop.java, void Compound_loop.while_and_or(int), 2, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.FN_loop2(int), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 12 * s$1] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.FN_loop2(int), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1 + 12 * s$1] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.FN_loop3(int), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 12 * (-s$0 + s$1 + 15)] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.FN_loop3(int), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 3 + 12 * (-s$0 + s$1 + 15)] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.loop0_bad(), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1101] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.loop0_bad(), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1102] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.loop1_bad(), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1203] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.loop1_bad(), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1202] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.main_bad(), 8, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 237] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.main_bad(), 8, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 205] +codetoanalyze/java/performance/Cost_test.java, int Cost_test.main_bad(), 9, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 243] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.if_bad_loop(), 12, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 201] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_despite_inferbo(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1302] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_despite_inferbo(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1303] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_despite_inferbo(int), 5, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1302] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_no_dep1(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 604] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_no_dep1(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 605] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_no_dep2(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 608] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.loop_no_dep2(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 609] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.nested_loop(), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.real_while(), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 213] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.real_while(), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 214] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.real_while(), 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 213] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.two_loops(), 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 544] +codetoanalyze/java/performance/Cost_test_deps.java, int Cost_test_deps.two_loops(), 7, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 545] +codetoanalyze/java/performance/Cost_test_deps.java, void Cost_test_deps.if_bad(int), 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 608] +codetoanalyze/java/performance/Cost_test_deps.java, void Cost_test_deps.if_bad(int), 6, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 607] +codetoanalyze/java/performance/JsonMap.java, void JsonMap.addEntry(String,String), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 239] codetoanalyze/java/performance/JsonUtils.java, void JsonUtils.escape(StringBuilder,String), 1, BUFFER_OVERRUN_U5, no_bucket, ERROR, [Unknown value from: char[] String.toCharArray(),Assignment,ArrayAccess: Offset: [-oo, +oo] Size: [0, +oo]] -codetoanalyze/java/performance/JsonUtils.java, void JsonUtils.serialize(StringBuilder,String), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, []