[absint] Give instr index to `exec_instr` to get inferbo result

Summary:
In order to use Inferbo's analysis result, a checker should know current instruction index.
However, for the checkers using `ProcCfg.Normal` CFG, it was impossible to get the instruction
index.  To solve the issue, this diff changes the AbsInt framework to give the index together to
`exec_instr`.

Reviewed By: ezgicicek

Differential Revision: D27680894

fbshipit-source-id: 1dc8ff0fb
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent 14fb38c0da
commit fd219ae457

@ -22,6 +22,8 @@ module RevArray : sig
val last_opt : 'a t -> 'a option val last_opt : 'a t -> 'a option
val fold : ('a t, 'a, 'accum) Container.fold val fold : ('a t, 'a, 'accum) Container.fold
val foldi : 'a t -> init:'accum -> f:(int -> 'accum -> 'a -> 'accum) -> 'accum
end = struct end = struct
type 'a t = 'a Array.t type 'a t = 'a Array.t
@ -38,6 +40,13 @@ end = struct
let fold a ~init ~f = let fold a ~init ~f =
let f = Fn.flip f in let f = Fn.flip f in
Array.fold_right a ~init ~f Array.fold_right a ~init ~f
let foldi a ~init ~f =
let idx = ref (Array.length a) in
Array.fold_right a ~init ~f:(fun elt acc ->
decr idx ;
f !idx acc elt )
end end
type reversed type reversed
@ -168,6 +177,18 @@ let fold (type r) (t : r t) ~init ~f =
RevArray.fold rev_instrs ~init ~f RevArray.fold rev_instrs ~init ~f
let foldi (type r) (t : r t) ~init ~f =
match t with
| Empty ->
init
| Singleton instr ->
f 0 init instr
| NotReversed instrs ->
Array.foldi instrs ~init ~f
| Reversed rev_instrs ->
RevArray.foldi rev_instrs ~init ~f
let iter t ~f = Container.iter ~fold t ~f let iter t ~f = Container.iter ~fold t ~f
let exists t ~f = Container.exists ~iter t ~f let exists t ~f = Container.exists ~iter t ~f
@ -228,8 +249,3 @@ let instrs_get_normal_vars instrs =
|> Ident.hashqueue_of_sequence ~init:res ) |> Ident.hashqueue_of_sequence ~init:res )
in in
fold ~init:(Ident.HashQueue.create ()) ~f:do_instr instrs |> Ident.HashQueue.keys fold ~init:(Ident.HashQueue.create ()) ~f:do_instr instrs |> Ident.HashQueue.keys
let find_instr_index instrs instr =
let instrs = get_underlying_not_reversed instrs in
Array.findi instrs ~f:(fun _index i -> Sil.equal_instr i instr) |> Option.map ~f:fst

@ -65,12 +65,12 @@ val last : _ t -> Sil.instr option
val find_map : _ t -> f:(Sil.instr -> 'a option) -> 'a option val find_map : _ t -> f:(Sil.instr -> 'a option) -> 'a option
val find_instr_index : not_reversed t -> Sil.instr -> int option
val pp : Pp.env -> Format.formatter -> _ t -> unit val pp : Pp.env -> Format.formatter -> _ t -> unit
val fold : (_ t, Sil.instr, 'a) Container.fold val fold : (_ t, Sil.instr, 'a) Container.fold
val foldi : _ t -> init:'a -> f:(int -> 'a -> Sil.instr -> 'a) -> 'a
val iter : (_ t, Sil.instr) Container.iter val iter : (_ t, Sil.instr) Container.iter
val get_underlying_not_reversed : not_reversed t -> Sil.instr array val get_underlying_not_reversed : not_reversed t -> Sil.instr array

@ -90,7 +90,7 @@ module type NodeTransferFunctions = sig
val exec_node_instrs : val exec_node_instrs :
Domain.t State.t option Domain.t State.t option
-> exec_instr:(Domain.t -> Sil.instr -> Domain.t) -> exec_instr:(ProcCfg.InstrNode.instr_index -> Domain.t -> Sil.instr -> Domain.t)
-> Domain.t -> Domain.t
-> _ Instrs.t -> _ Instrs.t
-> Domain.t -> Domain.t
@ -103,7 +103,7 @@ module SimpleNodeTransferFunctions (T : TransferFunctions.SIL) = struct
include T include T
let exec_node_instrs _old_state_opt ~exec_instr pre instrs = let exec_node_instrs _old_state_opt ~exec_instr pre instrs =
Instrs.fold ~init:pre instrs ~f:exec_instr Instrs.foldi ~init:pre instrs ~f:exec_instr
end end
(** build a disjunctive domain and transfer functions *) (** build a disjunctive domain and transfer functions *)
@ -181,7 +181,7 @@ struct
F.fprintf f "@[<v>%d disjuncts:@;%a@]" (List.length disjuncts) pp_disjuncts disjuncts F.fprintf f "@[<v>%d disjuncts:@;%a@]" (List.length disjuncts) pp_disjuncts disjuncts
end end
let exec_instr pre_disjuncts analysis_data node instr = let exec_instr pre_disjuncts analysis_data node _ instr =
List.foldi pre_disjuncts ~init:[] ~f:(fun i post_disjuncts pre_disjunct -> List.foldi pre_disjuncts ~init:[] ~f:(fun i post_disjuncts pre_disjunct ->
let should_skip = let should_skip =
let (`UnderApproximateAfter n) = DConfig.join_policy in let (`UnderApproximateAfter n) = DConfig.join_policy in
@ -211,7 +211,7 @@ struct
List.foldi pre ~init:current_post ~f:(fun i post_disjuncts pre_disjunct -> List.foldi pre ~init:current_post ~f:(fun i post_disjuncts pre_disjunct ->
if is_new_pre pre_disjunct then ( if is_new_pre pre_disjunct then (
L.d_printfln "@[<v2>Executing node from disjunct #%d@;" i ; L.d_printfln "@[<v2>Executing node from disjunct #%d@;" i ;
let disjuncts' = Instrs.fold ~init:[pre_disjunct] instrs ~f:exec_instr in let disjuncts' = Instrs.foldi ~init:[pre_disjunct] instrs ~f:exec_instr in
L.d_printfln "@]@\n" ; L.d_printfln "@]@\n" ;
Domain.join post_disjuncts disjuncts' ) Domain.join post_disjuncts disjuncts' )
else ( else (
@ -294,11 +294,11 @@ module AbstractInterpreterCommon (TransferFunctions : NodeTransferFunctions) = s
let exec_node_instrs old_state_opt ~pp_instr proc_data node pre = let exec_node_instrs old_state_opt ~pp_instr proc_data node pre =
let instrs = CFG.instrs node in let instrs = CFG.instrs node in
if Config.write_html then L.d_printfln_escaped "PRE STATE:@\n@[%a@]@\n" Domain.pp pre ; if Config.write_html then L.d_printfln_escaped "PRE STATE:@\n@[%a@]@\n" Domain.pp pre ;
let exec_instr pre instr = let exec_instr idx pre instr =
AnalysisState.set_instr instr ; AnalysisState.set_instr instr ;
let result = let result =
try try
let post = TransferFunctions.exec_instr pre proc_data node instr in let post = TransferFunctions.exec_instr pre proc_data node idx instr in
(* don't forget to reset this so we output messages for future errors too *) (* don't forget to reset this so we output messages for future errors too *)
logged_error := false ; logged_error := false ;
Ok post Ok post

@ -40,7 +40,7 @@ module Make (TransferFunctions : TransferFunctions.HIL) (HilConfig : HilConfig)
&& match ConcurrencyModels.get_lock_effect pname actuals with Unlock _ -> true | _ -> false && match ConcurrencyModels.get_lock_effect pname actuals with Unlock _ -> true | _ -> false
let exec_instr_actual analysis_data bindings node hil_instr actual_state = let exec_instr_actual analysis_data bindings node idx hil_instr actual_state =
match (hil_instr : HilInstr.t) with match (hil_instr : HilInstr.t) with
| Call (_, Direct callee_pname, actuals, _, loc) as hil_instr | Call (_, Direct callee_pname, actuals, _, loc) as hil_instr
when is_java_unlock callee_pname actuals -> when is_java_unlock callee_pname actuals ->
@ -53,11 +53,11 @@ module Make (TransferFunctions : TransferFunctions.HIL) (HilConfig : HilConfig)
let dummy_assign = let dummy_assign =
HilInstr.Assign (lhs_access_path, HilExp.AccessExpression access_expr, loc) HilInstr.Assign (lhs_access_path, HilExp.AccessExpression access_expr, loc)
in in
TransferFunctions.exec_instr astate_acc analysis_data node dummy_assign ) TransferFunctions.exec_instr astate_acc analysis_data node idx dummy_assign )
in in
(TransferFunctions.exec_instr actual_state' analysis_data node hil_instr, Bindings.empty) (TransferFunctions.exec_instr actual_state' analysis_data node idx hil_instr, Bindings.empty)
| hil_instr -> | hil_instr ->
(TransferFunctions.exec_instr actual_state analysis_data node hil_instr, bindings) (TransferFunctions.exec_instr actual_state analysis_data node idx hil_instr, bindings)
let append_bindings = IList.append_no_duplicates ~cmp:Var.compare |> Staged.unstage let append_bindings = IList.append_no_duplicates ~cmp:Var.compare |> Staged.unstage
@ -84,13 +84,13 @@ module Make (TransferFunctions : TransferFunctions.HIL) (HilConfig : HilConfig)
(Some instr, bindings) (Some instr, bindings)
let exec_instr ((actual_state, bindings) as astate) analysis_data node instr = let exec_instr ((actual_state, bindings) as astate) analysis_data node idx instr =
let actual_state', bindings' = let actual_state', bindings' =
match hil_instr_of_sil bindings instr with match hil_instr_of_sil bindings instr with
| None, bindings -> | None, bindings ->
(actual_state, bindings) (actual_state, bindings)
| Some hil_instr, bindings -> | Some hil_instr, bindings ->
exec_instr_actual analysis_data bindings node hil_instr actual_state exec_instr_actual analysis_data bindings node idx hil_instr actual_state
in in
if phys_equal bindings bindings' && phys_equal actual_state actual_state' then astate if phys_equal bindings bindings' && phys_equal actual_state actual_state' then astate
else (actual_state', bindings') else (actual_state', bindings')

@ -29,7 +29,13 @@ module Make (TransferFunctions : TransferFunctions.HIL) (HilConfig : HilConfig)
type analysis_data = TransferFunctions.analysis_data type analysis_data = TransferFunctions.analysis_data
val exec_instr : Domain.t -> analysis_data -> CFG.Node.t -> Sil.instr -> Domain.t val exec_instr :
Domain.t
-> analysis_data
-> CFG.Node.t
-> ProcCfg.InstrNode.instr_index
-> Sil.instr
-> Domain.t
val pp_session_name : CFG.Node.t -> Format.formatter -> unit val pp_session_name : CFG.Node.t -> Format.formatter -> unit
end end

@ -12,7 +12,7 @@ module F = Format
file). Defines useful wrappers that allows us to do tricks like turn a forward cfg into a file). Defines useful wrappers that allows us to do tricks like turn a forward cfg into a
backward one, or view a cfg as having a single instruction per node. *) backward one, or view a cfg as having a single instruction per node. *)
module type Node = sig module type NodeCommonS = sig
type t type t
type id type id
@ -38,26 +38,37 @@ module type Node = sig
module IdSet : PrettyPrintable.PPSet with type elt = id module IdSet : PrettyPrintable.PPSet with type elt = id
end end
module DefaultNode : Node with type t = Procdesc.Node.t and type id = Procdesc.Node.id = struct module InstrNode : sig
type t = Procdesc.Node.t type instr_index = int
type id = Procdesc.Node.id include
NodeCommonS
with type t = Procdesc.Node.t * instr_index
and type id = Procdesc.Node.id * instr_index
let kind = Procdesc.Node.get_kind val compare : t -> t -> int
let id = Procdesc.Node.get_id val to_instr : instr_index -> t -> t
end = struct
type instr_index = int [@@deriving compare]
let hash = Procdesc.Node.hash type t = Procdesc.Node.t * instr_index [@@deriving compare]
let loc = Procdesc.Node.get_loc type id = Procdesc.Node.id * instr_index [@@deriving compare]
let underlying_node t = t let kind (t, _) = Procdesc.Node.get_kind t
let of_underlying_node t = t let underlying_node (t, _) = t
let compare_id = Procdesc.Node.compare_id let of_underlying_node t = (t, 0)
let pp_id = Procdesc.Node.pp_id let id (t, index) = (Procdesc.Node.get_id t, index)
let hash node = Hashtbl.hash (id node)
let loc (t, _) = Procdesc.Node.get_loc t
let pp_id fmt (id, index) = F.fprintf fmt "(%a: %d)" Procdesc.Node.pp_id id index
module OrderedId = struct module OrderedId = struct
type t = id [@@deriving compare] type t = id [@@deriving compare]
@ -65,35 +76,38 @@ module DefaultNode : Node with type t = Procdesc.Node.t and type id = Procdesc.N
let pp = pp_id let pp = pp_id
end end
module IdMap = Procdesc.IdMap module IdMap = PrettyPrintable.MakePPMap (OrderedId)
module IdSet = PrettyPrintable.MakePPSet (OrderedId) module IdSet = PrettyPrintable.MakePPSet (OrderedId)
let to_instr _ t = t
end end
module InstrNode : sig module type Node = sig
type instr_index = int include NodeCommonS
include val to_instr : InstrNode.instr_index -> t -> InstrNode.t
Node with type t = Procdesc.Node.t * instr_index and type id = Procdesc.Node.id * instr_index end
end = struct
type instr_index = int [@@deriving compare]
type t = Procdesc.Node.t * instr_index module DefaultNode : Node with type t = Procdesc.Node.t and type id = Procdesc.Node.id = struct
type t = Procdesc.Node.t
type id = Procdesc.Node.id * instr_index [@@deriving compare] type id = Procdesc.Node.id
let kind (t, _) = Procdesc.Node.get_kind t let kind = Procdesc.Node.get_kind
let underlying_node (t, _) = t let id = Procdesc.Node.get_id
let of_underlying_node t = (t, 0) let hash = Procdesc.Node.hash
let id (t, index) = (Procdesc.Node.get_id t, index) let loc = Procdesc.Node.get_loc
let hash node = Hashtbl.hash (id node) let underlying_node t = t
let loc (t, _) = Procdesc.Node.get_loc t let of_underlying_node t = t
let pp_id fmt (id, index) = F.fprintf fmt "(%a: %d)" Procdesc.Node.pp_id id index let compare_id = Procdesc.Node.compare_id
let pp_id = Procdesc.Node.pp_id
module OrderedId = struct module OrderedId = struct
type t = id [@@deriving compare] type t = id [@@deriving compare]
@ -101,8 +115,10 @@ end = struct
let pp = pp_id let pp = pp_id
end end
module IdMap = PrettyPrintable.MakePPMap (OrderedId) module IdMap = Procdesc.IdMap
module IdSet = PrettyPrintable.MakePPSet (OrderedId) module IdSet = PrettyPrintable.MakePPSet (OrderedId)
let to_instr index node = (node, index)
end end
module type S = sig module type S = sig
@ -325,8 +341,6 @@ module OneInstrPerNode (Base : S with module Node = DefaultNode) : sig
S with type t = Base.t and module Node = InstrNode and type instrs_dir = Instrs.not_reversed S with type t = Base.t and module Node = InstrNode and type instrs_dir = Instrs.not_reversed
val last_of_underlying_node : Procdesc.Node.t -> Node.t val last_of_underlying_node : Procdesc.Node.t -> Node.t
val of_instr_opt : Procdesc.Node.t -> Sil.instr -> Node.t option
end = struct end = struct
type t = Base.t type t = Base.t
@ -343,11 +357,6 @@ end = struct
let last_of_node node = (node, max 0 (Instrs.count (Base.instrs node) - 1)) let last_of_node node = (node, max 0 (Instrs.count (Base.instrs node) - 1))
let of_instr_opt node instr =
let instrs = Procdesc.Node.get_instrs node in
Instrs.find_instr_index instrs instr |> Option.map ~f:(fun index -> (node, index))
let last_of_underlying_node = last_of_node let last_of_underlying_node = last_of_node
let fold_normal_succs _ _ ~init:_ ~f:_ = (* not used *) assert false let fold_normal_succs _ _ ~init:_ ~f:_ = (* not used *) assert false

@ -11,7 +11,7 @@ open! IStd
file). Defines useful wrappers that allows us to do tricks like turn a forward cfg to into a file). Defines useful wrappers that allows us to do tricks like turn a forward cfg to into a
backward one, or view a cfg as having a single instruction per block *) backward one, or view a cfg as having a single instruction per block *)
module type Node = sig module type NodeCommonS = sig
type t type t
type id type id
@ -37,6 +37,26 @@ module type Node = sig
module IdSet : PrettyPrintable.PPSet with type elt = id module IdSet : PrettyPrintable.PPSet with type elt = id
end end
module InstrNode : sig
(* NOTE: The type is not abstracted since it is used in the [Instrs] module. *)
type instr_index = int
include
NodeCommonS
with type t = Procdesc.Node.t * instr_index
and type id = Procdesc.Node.id * instr_index
val compare : t -> t -> int
val to_instr : instr_index -> t -> t
end
module type Node = sig
include NodeCommonS
val to_instr : InstrNode.instr_index -> t -> InstrNode.t
end
module type S = sig module type S = sig
type t type t
@ -82,13 +102,6 @@ end
module DefaultNode : Node with type t = Procdesc.Node.t and type id = Procdesc.Node.id module DefaultNode : Node with type t = Procdesc.Node.t and type id = Procdesc.Node.id
module InstrNode : sig
type instr_index
include
Node with type t = Procdesc.Node.t * instr_index and type id = Procdesc.Node.id * instr_index
end
(** Forward CFG with no exceptional control-flow *) (** Forward CFG with no exceptional control-flow *)
module Normal : module Normal :
S with type t = Procdesc.t and module Node = DefaultNode and type instrs_dir = Instrs.not_reversed S with type t = Procdesc.t and module Node = DefaultNode and type instrs_dir = Instrs.not_reversed
@ -109,8 +122,6 @@ module OneInstrPerNode (Base : S with module Node = DefaultNode) : sig
S with type t = Base.t and module Node = InstrNode and type instrs_dir = Instrs.not_reversed S with type t = Base.t and module Node = InstrNode and type instrs_dir = Instrs.not_reversed
val last_of_underlying_node : Procdesc.Node.t -> Node.t val last_of_underlying_node : Procdesc.Node.t -> Node.t
val of_instr_opt : Procdesc.Node.t -> Sil.instr -> Node.t option
end end
module NormalOneInstrPerNode : module type of OneInstrPerNode (Normal) module NormalOneInstrPerNode : module type of OneInstrPerNode (Normal)

@ -16,7 +16,8 @@ module type S = sig
type instr type instr
val exec_instr : Domain.t -> analysis_data -> CFG.Node.t -> instr -> Domain.t val exec_instr :
Domain.t -> analysis_data -> CFG.Node.t -> ProcCfg.InstrNode.instr_index -> instr -> Domain.t
val pp_session_name : CFG.Node.t -> Format.formatter -> unit val pp_session_name : CFG.Node.t -> Format.formatter -> unit
end end

@ -22,12 +22,13 @@ module type S = sig
(** type of the instructions the transfer functions operate on *) (** type of the instructions the transfer functions operate on *)
type instr type instr
val exec_instr : Domain.t -> analysis_data -> CFG.Node.t -> instr -> Domain.t val exec_instr :
(** [exec_instr astate proc_data node instr] should usually return [astate'] such that Domain.t -> analysis_data -> CFG.Node.t -> ProcCfg.InstrNode.instr_index -> instr -> Domain.t
(** [exec_instr astate proc_data node idx instr] should usually return [astate'] such that
[{astate} instr {astate'}] is a valid Hoare triple. In other words, [exec_instr] defines how [{astate} instr {astate'}] is a valid Hoare triple. In other words, [exec_instr] defines how
executing an instruction from a given abstract state changes that state into a new one. This executing an instruction from a given abstract state changes that state into a new one. This
is usually called the {i transfer function} in Abstract Interpretation terms. [node] is the is usually called the {i transfer function} in Abstract Interpretation terms. [node] is the
node containing the current instruction. *) node containing the current instruction and [idx] is the index of the instruction in the node. *)
val pp_session_name : CFG.Node.t -> Format.formatter -> unit val pp_session_name : CFG.Node.t -> Format.formatter -> unit
(** print session name for HTML debug *) (** print session name for HTML debug *)

@ -58,7 +58,7 @@ module TransferFunctions = struct
type analysis_data = unit type analysis_data = unit
let exec_instr astate _ _node instr = eval_instr astate instr let exec_instr astate _ _node _ instr = eval_instr astate instr
let pp_session_name node fmt = let pp_session_name node fmt =
Format.fprintf fmt "Closure Subst Specialized Method %a" CFG.Node.pp_id (CFG.Node.id node) Format.fprintf fmt "Closure Subst Specialized Method %a" CFG.Node.pp_id (CFG.Node.id node)

@ -67,7 +67,7 @@ module TransferFunctions = struct
type analysis_data = unit type analysis_data = unit
let exec_instr astate _ _node instr = eval_instr astate instr let exec_instr astate _ _node _ instr = eval_instr astate instr
let pp_session_name node fmt = let pp_session_name node fmt =
Format.fprintf fmt "Closures Substitution %a" CFG.Node.pp_id (CFG.Node.id node) Format.fprintf fmt "Closures Substitution %a" CFG.Node.pp_id (CFG.Node.id node)

@ -80,7 +80,7 @@ module TransferFunctions = struct
type analysis_data = unit type analysis_data = unit
let exec_instr astate _ _node instr = eval_instr astate instr let exec_instr astate _ _node _ instr = eval_instr astate instr
let pp_session_name node fmt = let pp_session_name node fmt =
Format.fprintf fmt "devirtualizer analysis %a" CFG.Node.pp_id (CFG.Node.id node) Format.fprintf fmt "devirtualizer analysis %a" CFG.Node.pp_id (CFG.Node.id node)

@ -326,7 +326,7 @@ module Liveness = struct
let is_last_instr_in_node instr node = phys_equal (last_instr_in_node node) instr let is_last_instr_in_node instr node = phys_equal (last_instr_in_node node) instr
let exec_instr ((active_defs, to_nullify) as astate) extras node instr = let exec_instr ((active_defs, to_nullify) as astate) extras node _ instr =
let astate' = let astate' =
match instr with match instr with
| Sil.Load {id= lhs_id} -> | Sil.Load {id= lhs_id} ->

@ -314,10 +314,16 @@ module TransferFunctions = struct
Dom.Mem.add_unknown ret ~location mem Dom.Mem.add_unknown ret ~location mem
let exec_instr : Dom.Mem.t -> analysis_data -> CFG.Node.t -> Sil.instr -> Dom.Mem.t = let exec_instr :
Dom.Mem.t
-> analysis_data
-> CFG.Node.t
-> ProcCfg.InstrNode.instr_index
-> Sil.instr
-> Dom.Mem.t =
fun mem fun mem
({interproc= {proc_desc; tenv}; get_summary; oenv= {integer_type_widths}} as analysis_data) ({interproc= {proc_desc; tenv}; get_summary; oenv= {integer_type_widths}} as analysis_data)
node instr -> node _ instr ->
match instr with match instr with
| Load {id} when Ident.is_none id -> | Load {id} when Ident.is_none id ->
mem mem

@ -577,7 +577,7 @@ module TransferFunctions = struct
let exec_instr ({Dom.mem} as astate) let exec_instr ({Dom.mem} as astate)
({InterproceduralAnalysis.tenv; analyze_dependency} as analysis_data) _node instr = ({InterproceduralAnalysis.tenv; analyze_dependency} as analysis_data) _node _ instr =
match (instr : Sil.instr) with match (instr : Sil.instr) with
| Load {id; e= Lvar pvar} -> | Load {id; e= Lvar pvar} ->
Dom.load_config id pvar astate Dom.load_config id pvar astate

@ -38,7 +38,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
with Caml.Not_found -> false with Caml.Not_found -> false
let exec_instr astate id_table _ instr = let exec_instr astate id_table _ _ instr =
match instr with match instr with
| Sil.Load {id; e= exp} -> | Sil.Load {id; e= exp} ->
Ident.Hash.add id_table id exp ; Ident.Hash.add id_table id exp ;

@ -143,7 +143,7 @@ module TransferFunctions = struct
let modified_global ae = HilExp.AccessExpression.get_base ae |> fst |> Var.is_global let modified_global ae = HilExp.AccessExpression.get_base ae |> fst |> Var.is_global
let exec_instr (astate : Domain.t) {tenv; inferbo_invariant_map; formals; get_callee_summary} let exec_instr (astate : Domain.t) {tenv; inferbo_invariant_map; formals; get_callee_summary}
(node : CFG.Node.t) (instr : HilInstr.t) = (node : CFG.Node.t) _ (instr : HilInstr.t) =
let (node_id : InstrCFG.Node.id) = let (node_id : InstrCFG.Node.id) =
CFG.Node.underlying_node node |> InstrCFG.last_of_underlying_node |> InstrCFG.Node.id CFG.Node.underlying_node node |> InstrCFG.last_of_underlying_node |> InstrCFG.Node.id
in in

@ -211,7 +211,7 @@ module TransferFunctions = struct
Domain.assume_null access_path astate Domain.assume_null access_path astate
let exec_instr astate {interproc= {proc_desc; tenv}; get_proc_summary_and_formals} _ let exec_instr astate {interproc= {proc_desc; tenv}; get_proc_summary_and_formals} _ _
(instr : HilInstr.t) : Domain.t = (instr : HilInstr.t) : Domain.t =
let caller_pname = Procdesc.get_proc_name proc_desc in let caller_pname = Procdesc.get_proc_name proc_desc in
match instr with match instr with

@ -343,7 +343,7 @@ module TransferFunctions = struct
report_on_non_nullable_arg ?annotations domain args report_on_non_nullable_arg ?annotations domain args
let exec_instr (astate : Domain.t) {IntraproceduralAnalysis.proc_desc; err_log} _cfg_node let exec_instr (astate : Domain.t) {IntraproceduralAnalysis.proc_desc; err_log} _cfg_node _
(instr : Sil.instr) = (instr : Sil.instr) =
let attributes = Procdesc.get_attributes proc_desc in let attributes = Procdesc.get_attributes proc_desc in
let astate = report_unchecked_strongself_issues_on_exps proc_desc err_log astate instr in let astate = report_unchecked_strongself_issues_on_exps proc_desc err_log astate instr in

@ -129,7 +129,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let at_least_nonbottom = Domain.join (NonBottom SiofTrace.bottom, Domain.VarNames.empty) let at_least_nonbottom = Domain.join (NonBottom SiofTrace.bottom, Domain.VarNames.empty)
let exec_instr astate let exec_instr astate
({InterproceduralAnalysis.proc_desc; analyze_dependency; _} as analysis_data) _ ({InterproceduralAnalysis.proc_desc; analyze_dependency; _} as analysis_data) _ _
(instr : Sil.instr) = (instr : Sil.instr) =
match instr with match instr with
| Store {e1= Lvar global; typ= Typ.{desc= Tptr _}; e2= Lvar _; loc} | Store {e1= Lvar global; typ= Typ.{desc= Tptr _}; e2= Lvar _; loc}

@ -35,7 +35,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
astate astate
let exec_instr astate () _ = function let exec_instr astate () _ _ = function
| Sil.Store {typ= {desc= Tptr _}; e2= rhs_exp} -> | Sil.Store {typ= {desc= Tptr _}; e2= rhs_exp} ->
add_address_taken_pvars rhs_exp astate add_address_taken_pvars rhs_exp astate
| Sil.Call (_, _, actuals, _, _) -> | Sil.Call (_, _, actuals, _, _) ->

@ -533,7 +533,7 @@ module MakeTransferFunctions (CFG : ProcCfg.S) = struct
callee_call_map astate callee_call_map astate
let exec_instr astate ({analysis_data= {proc_desc; tenv}; specs} as analysis_data) _ = function let exec_instr astate ({analysis_data= {proc_desc; tenv}; specs} as analysis_data) _ _ = function
| Sil.Call (_, Const (Cfun callee_pname), _, call_loc, _) -> | Sil.Call (_, Const (Cfun callee_pname), _, call_loc, _) ->
let caller_pname = Procdesc.get_proc_name proc_desc in let caller_pname = Procdesc.get_proc_name proc_desc in
let call_site = CallSite.make callee_pname call_loc in let call_site = CallSite.make callee_pname call_loc in

@ -133,7 +133,7 @@ module TransferFunctionsControlDeps (CFG : ProcCfg.S) = struct
along with the loop header that CV is originating from along with the loop header that CV is originating from
- a loop exit node, remove 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. *) This is correct because the CVs are only going to be temporaries. *)
let exec_instr astate (nodes, {exit_map; loop_head_to_guard_nodes}) (node : CFG.Node.t) _ = let exec_instr astate (nodes, {exit_map; loop_head_to_guard_nodes}) (node : CFG.Node.t) _ _ =
let node = CFG.Node.underlying_node node in let node = CFG.Node.underlying_node node in
let astate' = let astate' =
match LoopHeadToGuardNodes.find_opt node loop_head_to_guard_nodes with match LoopHeadToGuardNodes.find_opt node loop_head_to_guard_nodes with

@ -16,7 +16,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
type analysis_data = unit type analysis_data = unit
let exec_instr astate () _ = function let exec_instr astate () _ _ = function
| Sil.Load {id= lhs_id} when Ident.is_none lhs_id -> | Sil.Load {id= lhs_id} when Ident.is_none lhs_id ->
astate astate
| Sil.Load {id= lhs_id; e= Exp.Lvar rhs_pvar; typ= Typ.{desc= Tptr ({desc= Tfun}, _)}} -> | Sil.Load {id= lhs_id; e= Exp.Lvar rhs_pvar; typ= Typ.{desc= Tptr ({desc= Tfun}, _)}} ->

@ -183,7 +183,7 @@ module TransferFunctions (LConfig : LivenessConfig) (CFG : ProcCfg.S) = struct
List.fold actuals ~f:(fun acc_ exp -> exp_add_live exp acc_) ~init:live_acc List.fold actuals ~f:(fun acc_ exp -> exp_add_live exp acc_) ~init:live_acc
let exec_instr astate proc_desc _ = function let exec_instr astate proc_desc _ _ = function
| Sil.Load {id= lhs_id} when Ident.is_none lhs_id -> | Sil.Load {id= lhs_id} when Ident.is_none lhs_id ->
(* dummy deref inserted by frontend--don't count as a read *) (* dummy deref inserted by frontend--don't count as a read *)
astate astate
@ -268,7 +268,7 @@ module PassedByRefTransferFunctions (CFG : ProcCfg.S) = struct
proc_name_of_expr expr |> Option.exists ~f:CheckerMode.is_dangerous_proc_name proc_name_of_expr expr |> Option.exists ~f:CheckerMode.is_dangerous_proc_name
let exec_instr astate () _ (instr : Sil.instr) = let exec_instr astate () _ _ (instr : Sil.instr) =
let astate = let astate =
match instr with match instr with
| Call (_ret, f, actuals, _loc, _flags) when not (is_dangerous f) -> | Call (_ret, f, actuals, _loc, _flags) when not (is_dangerous f) ->

@ -27,7 +27,7 @@ module TransferFunctionsReachingDefs (CFG : ProcCfg.S) = struct
type analysis_data = unit type analysis_data = unit
(* for each x := e at node n, remove x's definitions and introduce x -> n *) (* for each x := e at node n, remove x's definitions and introduce x -> n *)
let exec_instr astate () (node : CFG.Node.t) instr = let exec_instr astate () (node : CFG.Node.t) _ instr =
let node = CFG.Node.underlying_node node in let node = CFG.Node.underlying_node node in
let strong_update_def astate var = Domain.add var (Defs.singleton node) astate in let strong_update_def astate var = Domain.add var (Defs.singleton node) astate in
let weak_update_def astate var = let weak_update_def astate var =

@ -209,7 +209,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let exec_instr (astate : Domain.t) {analysis_data= {proc_desc; tenv} as analysis_data; formals} _ let exec_instr (astate : Domain.t) {analysis_data= {proc_desc; tenv} as analysis_data; formals} _
(instr : HilInstr.t) = _ (instr : HilInstr.t) =
let check_access_expr ~loc rhs_access_expr = let check_access_expr ~loc rhs_access_expr =
if should_report_var proc_desc tenv astate.maybe_uninit_vars rhs_access_expr then if should_report_var proc_desc tenv astate.maybe_uninit_vars rhs_access_expr then
report_intra rhs_access_expr loc analysis_data report_intra rhs_access_expr loc analysis_data

@ -195,7 +195,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
astate astate
let exec_instr astate ({interproc= {proc_desc; tenv}; formals} as analysis_data) _ instr = let exec_instr astate ({interproc= {proc_desc; tenv}; formals} as analysis_data) _ _ instr =
match (instr : HilInstr.t) with match (instr : HilInstr.t) with
| Call (ret_base, Direct callee_pname, actuals, call_flags, loc) -> | Call (ret_base, Direct callee_pname, actuals, call_flags, loc) ->
let astate = Domain.add_reads_of_hilexps tenv formals actuals loc astate in let astate = Domain.add_reads_of_hilexps tenv formals actuals loc astate in

@ -259,7 +259,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
astate astate
let exec_instr (astate : Domain.t) ({interproc= {proc_desc; tenv}; formals} as analysis_data) _ let exec_instr (astate : Domain.t) ({interproc= {proc_desc; tenv}; formals} as analysis_data) _ _
instr = instr =
let open ConcurrencyModels in let open ConcurrencyModels in
let open StarvationModels in let open StarvationModels in

@ -482,7 +482,7 @@ module TransferFunctions = struct
fun tenv pname -> dispatch tenv pname |> Option.is_some fun tenv pname -> dispatch tenv pname |> Option.is_some
let exec_instr astate {interproc= {tenv; analyze_dependency}; get_is_cheap_call} node instr = let exec_instr astate {interproc= {tenv; analyze_dependency}; get_is_cheap_call} node idx instr =
match (instr : Sil.instr) with match (instr : Sil.instr) with
| Load {id; e= Lvar pvar} -> | Load {id; e= Lvar pvar} ->
Dom.load_config id pvar astate Dom.load_config id pvar astate
@ -505,7 +505,10 @@ module TransferFunctions = struct
astate astate
| None -> | None ->
(* normal function calls *) (* normal function calls *)
let call = CostInstantiate.Call.{instr; loc= location; pname= callee; node; args; ret} in let call =
CostInstantiate.Call.
{loc= location; pname= callee; node= CFG.Node.to_instr idx node; args; ret}
in
let is_cheap_call = get_is_cheap_call call in let is_cheap_call = get_is_cheap_call call in
Dom.call tenv analyze_dependency ~is_cheap_call callee args location astate ) Dom.call tenv analyze_dependency ~is_cheap_call callee args location astate )
| Prune (e, _, _, _) -> | Prune (e, _, _, _) ->

@ -6,14 +6,12 @@
*) *)
open! IStd open! IStd
module F = Format module F = Format
module InstrCFG = ProcCfg.NormalOneInstrPerNode
module Call = struct module Call = struct
type t = type t =
{ instr: Sil.instr { loc: Location.t
; loc: Location.t
; pname: Procname.t ; pname: Procname.t
; node: Procdesc.Node.t ; node: ProcCfg.InstrNode.t
; args: (Exp.t * Typ.t) list ; args: (Exp.t * Typ.t) list
; ret: Ident.t * Typ.t } ; ret: Ident.t * Typ.t }
[@@deriving compare] [@@deriving compare]
@ -40,13 +38,12 @@ let get_symbolic_cost
; get_callee_cost_summary_and_formals ; get_callee_cost_summary_and_formals
; inferbo_invariant_map ; inferbo_invariant_map
; inferbo_get_summary ; inferbo_get_summary
; call= Call.{instr; pname; node; ret; args} } = ; call= Call.{pname; node; ret; args} } =
let last_node = Option.value_exn (InstrCFG.of_instr_opt node instr) in
let inferbo_mem = let inferbo_mem =
let instr_node_id = InstrCFG.Node.id last_node in Option.value_exn
Option.value_exn (BufferOverrunAnalysis.extract_pre instr_node_id inferbo_invariant_map) (BufferOverrunAnalysis.extract_pre (ProcCfg.InstrNode.id node) inferbo_invariant_map)
in in
let loc = InstrCFG.Node.loc last_node in let loc = ProcCfg.InstrNode.loc node in
let get_symbolic cost = let get_symbolic cost =
if CostDomain.BasicCost.is_symbolic cost then `SymbolicCost cost else `Cheap if CostDomain.BasicCost.is_symbolic cost then `SymbolicCost cost else `Cheap
in in
@ -68,7 +65,7 @@ let get_symbolic_cost
CostModels.Call.dispatch tenv pname fun_arg_list CostModels.Call.dispatch tenv pname fun_arg_list
|> Option.value_map ~default:`NoModel ~f:(fun model -> |> Option.value_map ~default:`NoModel ~f:(fun model ->
let model_env = let model_env =
let node_hash = InstrCFG.Node.hash last_node in let node_hash = ProcCfg.InstrNode.hash node in
BufferOverrunUtils.ModelEnv.mk_model_env pname ~node_hash loc tenv BufferOverrunUtils.ModelEnv.mk_model_env pname ~node_hash loc tenv
integer_type_widths inferbo_get_summary integer_type_widths inferbo_get_summary
in in

@ -9,10 +9,9 @@ open! IStd
module Call : sig module Call : sig
type t = type t =
{ instr: Sil.instr { loc: Location.t
; loc: Location.t
; pname: Procname.t ; pname: Procname.t
; node: Procdesc.Node.t ; node: ProcCfg.InstrNode.t
; args: (Exp.t * Typ.t) list ; args: (Exp.t * Typ.t) list
; ret: Ident.t * Typ.t } ; ret: Ident.t * Typ.t }
[@@deriving compare] [@@deriving compare]

@ -19,14 +19,16 @@ module LoopHeadToHoistInstrs = Procdesc.NodeMap
* 1. C is guaranteed to execute, i.e. N dominates all loop sources * 1. C is guaranteed to execute, i.e. N dominates all loop sources
* 2. args are loop invariant *) * 2. args are loop invariant *)
let add_if_hoistable inv_vars instr node source_nodes idom hoistable_calls = let add_if_hoistable inv_vars instr node idx source_nodes idom hoistable_calls =
match instr with match instr with
| Sil.Call (((ret_id, _) as ret), Exp.Const (Const.Cfun pname), args, loc, _) | Sil.Call (((ret_id, _) as ret), Exp.Const (Const.Cfun pname), args, loc, _)
when (* Check condition (1); N dominates all loop sources *) when (* Check condition (1); N dominates all loop sources *)
List.for_all ~f:(fun source -> Dominators.dominates idom node source) source_nodes List.for_all ~f:(fun source -> Dominators.dominates idom node source) source_nodes
&& (* Check condition (2); id should be invariant already *) && (* Check condition (2); id should be invariant already *)
LoopInvariant.InvariantVars.mem (Var.of_id ret_id) inv_vars -> LoopInvariant.InvariantVars.mem (Var.of_id ret_id) inv_vars ->
HoistCalls.add {instr; pname; loc; node; args; ret} hoistable_calls HoistCalls.add
{pname; loc; node= ProcCfg.DefaultNode.to_instr idx node; args; ret}
hoistable_calls
| _ -> | _ ->
hoistable_calls hoistable_calls
@ -35,8 +37,8 @@ let get_hoistable_calls inv_vars loop_nodes source_nodes idom =
LoopNodes.fold LoopNodes.fold
(fun node hoist_calls -> (fun node hoist_calls ->
let instr_in_node = Procdesc.Node.get_instrs node in let instr_in_node = Procdesc.Node.get_instrs node in
Instrs.fold ~init:hoist_calls Instrs.foldi ~init:hoist_calls
~f:(fun acc instr -> add_if_hoistable inv_vars instr node source_nodes idom acc) ~f:(fun idx acc instr -> add_if_hoistable inv_vars instr node idx source_nodes idom acc)
instr_in_node ) instr_in_node )
loop_nodes HoistCalls.empty loop_nodes HoistCalls.empty

@ -61,7 +61,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakCSDomain.t) let exec_instr (astate : ResourceLeakCSDomain.t)
{InterproceduralAnalysis.proc_desc; tenv; analyze_dependency; _} _ (instr : HilInstr.t) = {InterproceduralAnalysis.proc_desc; tenv; analyze_dependency; _} _ _ (instr : HilInstr.t) =
let assign_type_map = type_map := ResourceLeakCSDomain.get_type_map in let assign_type_map = type_map := ResourceLeakCSDomain.get_type_map in
assign_type_map ; assign_type_map ;
let is_not_enumerable = let is_not_enumerable =

@ -46,7 +46,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv= _; analyze_dependency= _; _} _ {InterproceduralAnalysis.proc_desc= _; tenv= _; analyze_dependency= _; _} _ _
(instr : HilInstr.t) = (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct _callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct _callee_procname, _actuals, _, _loc) ->

@ -46,8 +46,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ (instr : HilInstr.t) {InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ _
= (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)

@ -46,8 +46,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ (instr : HilInstr.t) {InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ _
= (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)

@ -46,8 +46,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ (instr : HilInstr.t) {InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency= _; _} _ _
= (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) ->
(* function call [return_opt] := invoke [callee_procname]([actuals]) *) (* function call [return_opt] := invoke [callee_procname]([actuals]) *)

@ -46,7 +46,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency; _} _ (instr : HilInstr.t) = {InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency; _} _ _ (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> ( | Call (_return_opt, Direct callee_procname, _actuals, _, _loc) -> (
if if

@ -46,7 +46,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency; _} _ (instr : HilInstr.t) = {InterproceduralAnalysis.proc_desc= _; tenv; analyze_dependency; _} _ _ (instr : HilInstr.t) =
match instr with match instr with
| Call (_return, Direct callee_procname, HilExp.AccessExpression allocated :: _, _, _loc) | Call (_return, Direct callee_procname, HilExp.AccessExpression allocated :: _, _, _loc)
when acquires_resource tenv callee_procname -> when acquires_resource tenv callee_procname ->

@ -46,7 +46,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(** Take an abstract state and instruction, produce a new abstract state *) (** Take an abstract state and instruction, produce a new abstract state *)
let exec_instr (astate : ResourceLeakDomain.t) let exec_instr (astate : ResourceLeakDomain.t)
{InterproceduralAnalysis.proc_desc= _; tenv= _; analyze_dependency= _; _} _ {InterproceduralAnalysis.proc_desc= _; tenv= _; analyze_dependency= _; _} _ _
(instr : HilInstr.t) = (instr : HilInstr.t) =
match instr with match instr with
| Call (_return_opt, Direct _callee_procname, _actuals, _, _loc) -> | Call (_return_opt, Direct _callee_procname, _actuals, _, _loc) ->

@ -671,7 +671,7 @@ module Make (TaintSpecification : TaintSpec.S) = struct
let exec_instr (astate : Domain.t) ({analysis_data= {proc_desc}; formal_map} as analysis_data) _ let exec_instr (astate : Domain.t) ({analysis_data= {proc_desc}; formal_map} as analysis_data) _
(instr : HilInstr.t) = _ (instr : HilInstr.t) =
match instr with match instr with
| Assign (Base (Var.ProgramVar pvar, _), HilExp.Exception _, _) when Pvar.is_return pvar -> | Assign (Base (Var.ProgramVar pvar, _), HilExp.Exception _, _) when Pvar.is_return pvar ->
(* the Java frontend translates `throw Exception` as `return Exception`, which is a bit (* the Java frontend translates `throw Exception` as `return Exception`, which is a bit

@ -52,7 +52,7 @@ module PathCountTransferFunctions (CFG : ProcCfg.S) = struct
type analysis_data = unit type analysis_data = unit
(* just propagate the current path count *) (* just propagate the current path count *)
let exec_instr astate _ _ _ = astate let exec_instr astate _ _ _ _ = astate
let pp_session_name _node _fmt = () let pp_session_name _node _fmt = ()
end end

@ -38,6 +38,8 @@ module MockNode = struct
module IdMap = PrettyPrintable.MakePPMap (OrderedId) module IdMap = PrettyPrintable.MakePPMap (OrderedId)
module IdSet = PrettyPrintable.MakePPSet (OrderedId) module IdSet = PrettyPrintable.MakePPSet (OrderedId)
let to_instr _ _ = assert false
end end
module MockProcCfg = struct module MockProcCfg = struct

Loading…
Cancel
Save