You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
3.7 KiB

(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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
module BasicCost = CostDomain.BasicCost
(* CFG modules used in several other modules *)
module InstrCFG = ProcCfg.NormalOneInstrPerNode
module NodeCFG = ProcCfg.Normal
module Node = ProcCfg.DefaultNode
let print_upper_bound_map bound_map =
L.(debug Analysis Medium)
"@\n\n******* Bound Map : [node -> bound] ITV **** @\n %a @\n"
(Node.IdMap.pp ~pp_value:BasicCost.pp)
bound_map ;
L.(debug Analysis Medium) "@\n******* END Bound Map ITV **** @\n\n"
let filter_loc vars_to_keep = function
| BufferOverrunField.Prim (AbsLoc.Loc.Var (Var.LogicalVar _)) ->
None
| BufferOverrunField.Prim (AbsLoc.Loc.Var var) ->
Control.ControlMap.find_opt var vars_to_keep
| _ ->
None
let compute_upperbound_map node_cfg inferbo_invariant_map control_invariant_map loop_inv_map =
let compute_node_upper_bound bound_map node =
let node_id = NodeCFG.Node.id node in
match Procdesc.Node.get_kind node with
| Procdesc.Node.Exit_node ->
Node.IdMap.add node_id BasicCost.one bound_map
| _ -> (
let exit_state_opt =
let instr_node_id = InstrCFG.last_of_underlying_node node |> InstrCFG.Node.id in
BufferOverrunAnalysis.extract_post instr_node_id inferbo_invariant_map
in
match exit_state_opt with
| Some entry_mem ->
(* compute control vars, i.e. set of variables that affect the execution count *)
let control_map =
Control.compute_control_vars control_invariant_map loop_inv_map node
in
L.(debug Analysis Medium)
"@\n>>> All dependencies for node = %a : %a @\n\n" Procdesc.Node.pp node
(Control.ControlMap.pp ~pp_value:Location.pp)
control_map ;
(* bound = env(v1) *... * env(vn) *)
let bound =
match entry_mem with
| Unreachable ->
let node_loc = NodeCFG.Node.loc node in
L.debug Analysis Medium
"@\n\
[COST ANALYSIS INTERNAL WARNING:] No 'env' found. This location is \
unreachable returning cost 0 \n" ;
BasicCost.of_unreachable node_loc
| ExcRaised ->
BasicCost.one
| Reachable mem ->
let cost =
BufferOverrunDomain.MemReach.range ~filter_loc:(filter_loc control_map) ~node_id
mem
in
(* The zero number of executions for a node
(corresponding to getting the range of bottom
values) does not make sense especially when the
abstract memory is non-bottom. This is a source
of unsoundness in the analysis. *)
if BasicCost.is_zero cost then BasicCost.one else cost
in
L.(debug Analysis Medium)
"@\n>>>Setting bound for node = %a to %a@\n\n" Node.pp_id node_id BasicCost.pp bound ;
Node.IdMap.add node_id bound bound_map
| _ ->
Node.IdMap.add node_id BasicCost.zero bound_map )
in
let bound_map = NodeCFG.fold_nodes node_cfg ~f:compute_node_upper_bound ~init:Node.IdMap.empty in
print_upper_bound_map bound_map ;
bound_map
let lookup_upperbound bound_map nid =
match Node.IdMap.find_opt nid bound_map with
| Some bound ->
bound
| None ->
L.(debug Analysis Medium)
"@\n\n[WARNING] Bound not found for node %a, returning Top @\n" Node.pp_id nid ;
BasicCost.top