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.
322 lines
11 KiB
322 lines
11 KiB
(*
|
|
* Copyright (c) 2009 - 2013 Monoidics ltd.
|
|
* Copyright (c) 2013 - present Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* 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.
|
|
*)
|
|
|
|
(** Control Flow Graph for Interprocedural Analysis *)
|
|
|
|
(** {2 ADT node and proc_desc} *)
|
|
|
|
type node
|
|
type cfg
|
|
|
|
(** Load a cfg from a file *)
|
|
val load_cfg_from_file: DB.filename -> cfg option
|
|
|
|
(** Save a cfg into a file, and save a copy of the source files if the boolean is true *)
|
|
val store_cfg_to_file: DB.filename -> bool -> cfg -> unit
|
|
|
|
(** proc description *)
|
|
module Procdesc : sig
|
|
(** proc description *)
|
|
type t
|
|
|
|
(** Compute the distance of each node to the exit node, if not computed already *)
|
|
val compute_distance_to_exit_node : t -> unit
|
|
|
|
(** Create a procdesc *)
|
|
val create : cfg -> ProcAttributes.t -> t
|
|
|
|
(** [remove cfg name remove_nodes] remove the procdesc [name] from the control flow graph [cfg]. *)
|
|
(** It also removes all the nodes from the procedure from the cfg if remove_nodes is true *)
|
|
val remove: cfg -> Procname.t -> bool -> unit
|
|
|
|
(** Find the procdesc given the proc name. Return None if not found. *)
|
|
val find_from_name : cfg -> Procname.t -> t option
|
|
|
|
(** Get the attributes of the procedure. *)
|
|
val get_attributes : t -> ProcAttributes.t
|
|
|
|
val get_err_log : t -> Errlog.t
|
|
|
|
val get_exit_node : t -> node
|
|
|
|
(** Get flags for the proc desc *)
|
|
val get_flags : t -> proc_flags
|
|
|
|
(** Return name and type of formal parameters *)
|
|
val get_formals : t -> (Mangled.t * Sil.typ) list
|
|
|
|
(** Return loc information for the procedure *)
|
|
val get_loc : t -> Location.t
|
|
|
|
(** Return name and type of local variables *)
|
|
val get_locals : t -> (Mangled.t * Sil.typ) list
|
|
|
|
(** Return name and type of block's captured variables *)
|
|
val get_captured : t -> (Mangled.t * Sil.typ) list
|
|
|
|
(** Return the visibility attribute *)
|
|
val get_access : t -> Sil.access
|
|
|
|
val get_nodes : t -> node list
|
|
|
|
(** Get the procedure's nodes up until the first branching *)
|
|
val get_slope : t -> node list
|
|
|
|
(** Get the sliced procedure's nodes up until the first branching *)
|
|
val get_sliced_slope : t -> (node -> bool) -> node list
|
|
|
|
val get_proc_name : t -> Procname.t
|
|
|
|
(** Return the return type of the procedure and type string *)
|
|
val get_ret_type : t -> Sil.typ
|
|
|
|
val get_ret_var : t -> Sil.pvar
|
|
|
|
val get_start_node : t -> node
|
|
|
|
(** Return [true] iff the procedure is defined, and not just declared *)
|
|
val is_defined : t -> bool
|
|
|
|
(** iterate over all the nodes of a procedure *)
|
|
val iter_nodes : (node -> unit) -> t -> unit
|
|
|
|
(** fold over the calls from the procedure: (callee, location) pairs *)
|
|
val fold_calls : ('a -> Procname.t * Location.t -> 'a) -> 'a -> t -> 'a
|
|
|
|
(** iterate over the calls from the procedure: (callee, location) pairs *)
|
|
val iter_calls : (Procname.t * Location.t -> unit) -> t -> unit
|
|
|
|
(** iterate over all nodes and their instructions *)
|
|
val iter_instrs : (node -> Sil.instr -> unit) -> t -> unit
|
|
|
|
(** fold over all nodes and their instructions *)
|
|
val fold_instrs : ('a -> node -> Sil.instr -> 'a) -> 'a -> t -> 'a
|
|
|
|
(** iterate over all nodes until we reach a branching structure *)
|
|
val iter_slope : (node -> unit) -> t -> unit
|
|
|
|
(** iterate over all calls until we reach a branching structure *)
|
|
val iter_slope_calls : (Procname.t -> unit) -> t -> unit
|
|
|
|
(** iterate between two nodes or until we reach a branching structure *)
|
|
val iter_slope_range : (node -> unit) -> node -> node -> unit
|
|
|
|
val set_exit_node : t -> node -> unit
|
|
|
|
(** Set a flag for the proc desc *)
|
|
val set_flag : t -> string -> string -> unit
|
|
|
|
val set_start_node : t -> node -> unit
|
|
|
|
(** append a list of new local variables to the existing list of local variables *)
|
|
val append_locals : t -> (Mangled.t * Sil.typ) list -> unit
|
|
|
|
end
|
|
|
|
(** node of the control flow graph *)
|
|
module Node : sig
|
|
type t = node (** type of nodes *)
|
|
|
|
(** kind of cfg node *)
|
|
type nodekind =
|
|
| Start_node of Procdesc.t
|
|
| Exit_node of Procdesc.t
|
|
| Stmt_node of string
|
|
| Join_node
|
|
| Prune_node of bool * Sil.if_kind * string (** (true/false branch, if_kind, comment) *)
|
|
| Skip_node of string
|
|
|
|
(** kind of Stmt_node for an exception handler. *)
|
|
val exn_handler_kind : nodekind
|
|
|
|
(** kind of Stmt_node for an exceptions sink. *)
|
|
val exn_sink_kind : nodekind
|
|
|
|
(** kind of Stmt_node for a throw instruction. *)
|
|
val throw_kind : nodekind
|
|
|
|
(** Append the instructions and temporaries to the list of instructions to execute *)
|
|
val append_instrs_temps : t -> Sil.instr list -> Ident.t list -> unit
|
|
|
|
(** Add the instructions and temporaries at the beginning of the list of instructions to execute *)
|
|
val prepend_instrs_temps : t -> Sil.instr list -> Ident.t list -> unit
|
|
|
|
(** Add declarations for local variables and return variable to the node *)
|
|
val add_locals_ret_declaration : t -> (Mangled.t * Sil.typ) list -> unit
|
|
|
|
(** Compare two nodes *)
|
|
val compare : t -> t -> int
|
|
|
|
(** [create cfg loc kind instrs proc_desc temps] create a new cfg node
|
|
with the given location, kind, list of instructions,
|
|
procdesc and list of temporary variables *)
|
|
val create : cfg -> Location.t -> nodekind -> Sil.instr list -> Procdesc.t -> Ident.t list -> t
|
|
|
|
(** create a new empty cfg *)
|
|
val create_cfg : unit -> cfg
|
|
|
|
(** Dump extended instructions for the node *)
|
|
val d_instrs : sub_instrs: bool -> Sil.instr option -> t -> unit
|
|
|
|
(** Create a dummy node *)
|
|
val dummy : unit -> t
|
|
|
|
(** Check if two nodes are equal *)
|
|
val equal : t -> t -> bool
|
|
|
|
(** Get all the nodes *)
|
|
val get_all_nodes : cfg -> t list
|
|
|
|
(** Get the (after/before) dead program variables. After/before indicated with the true/false flag. *)
|
|
val get_dead_pvars: t -> bool -> Sil.pvar list
|
|
|
|
(** Get the distance to the exit node, if it has been computed *)
|
|
val get_distance_to_exit: t -> int option
|
|
|
|
(** Return a description of the node *)
|
|
val get_description : printenv -> t -> string
|
|
|
|
(** Get the exception nodes from the current node *)
|
|
val get_exn : t -> t list
|
|
|
|
(** Get the unique id of the node *)
|
|
val get_id : t -> int
|
|
|
|
(** Get the source location of the node *)
|
|
val get_loc : t -> Location.t
|
|
|
|
(** Get the source location of the last instruction in the node *)
|
|
val get_last_loc : t -> Location.t
|
|
|
|
(** Get the kind of the current node *)
|
|
val get_kind : t -> nodekind
|
|
|
|
(** Get the predecessor nodes of the current node *)
|
|
val get_preds : t -> t list
|
|
|
|
(** Get a list of unique nodes until the first branch starting from a node with subsequent applications of a generator function *)
|
|
val get_generated_slope : t -> (t -> t list) -> t list
|
|
|
|
(** Get the proc desc associated to the node *)
|
|
val get_proc_desc : t -> Procdesc.t
|
|
|
|
(** Get the instructions to be executed *)
|
|
val get_instrs : t -> Sil.instr list
|
|
|
|
(** Get the list of callee procnames from the node *)
|
|
val get_callees : t -> Procname.t list
|
|
|
|
(** Get the successor nodes of the current node *)
|
|
val get_succs : t -> t list
|
|
|
|
(** Get the successor nodes of a node where the given predicate evaluates to true *)
|
|
val get_sliced_succs : t -> (t -> bool) -> t list
|
|
|
|
(** Get the predecessor nodes of a node where the given predicate evaluates to true *)
|
|
val get_sliced_preds : t -> (t -> bool) -> t list
|
|
|
|
(** Get the temporary variables introduced for the instructions stored in the node *)
|
|
val get_temps: t -> Ident.t list
|
|
|
|
(** Hash function for nodes *)
|
|
val hash : t -> int
|
|
|
|
(** Comparison for node kind *)
|
|
val kind_compare : nodekind -> nodekind -> int
|
|
|
|
(** Pretty print the node *)
|
|
val pp : Format.formatter -> t -> unit
|
|
|
|
(** Print extended instructions for the node, highlighting the given subinstruction if present *)
|
|
val pp_instr : printenv -> sub_instrs: bool -> Sil.instr option -> Format.formatter -> t -> unit
|
|
|
|
(** Replace the instructions to be executed. *)
|
|
val replace_instrs : t -> Sil.instr list -> unit
|
|
|
|
(** Set the (after/before) dead program variables. After/before indicated with the true/false flag. *)
|
|
val set_dead_pvars : t -> bool -> Sil.pvar list -> unit
|
|
|
|
(** Set the node kind *)
|
|
val set_kind : t -> nodekind -> unit
|
|
|
|
(** Set the source location of the node *)
|
|
val set_loc : t -> Location.t -> unit
|
|
|
|
(** Set the proc desc associated to the node *)
|
|
val set_proc_desc : t -> Procdesc.t -> unit
|
|
|
|
(** Set the successor nodes and exception nodes, and build predecessor links *)
|
|
val set_succs_exn : t -> t list -> t list -> unit
|
|
|
|
(** Set the temporary variables *)
|
|
val set_temps : t -> Ident.t list -> unit
|
|
(*
|
|
(** Replace the instructions to be executed. *)
|
|
val replace_instrs : t -> Sil.instr list -> unit
|
|
*)
|
|
end
|
|
|
|
(** Hash table with nodes as keys. *)
|
|
module NodeHash : Hashtbl.S with type key = Node.t
|
|
|
|
(** Set of nodes. *)
|
|
module NodeSet : Set.S with type elt = Node.t
|
|
|
|
val pp_node_list : Format.formatter -> Node.t list -> unit
|
|
|
|
(** {2 Functions for manipulating an interprocedural CFG} *)
|
|
|
|
(** Iterate over all the procdesc's *)
|
|
val iter_proc_desc : cfg -> (Procname.t -> Procdesc.t -> unit) -> unit
|
|
|
|
(** Get all the procedures (defined and declared) *)
|
|
val get_all_procs : cfg -> Procdesc.t list
|
|
|
|
(** Get the procedures whose body is defined in this cfg *)
|
|
val get_defined_procs : cfg -> Procdesc.t list
|
|
|
|
(** get the function names which should be analyzed before the other ones *)
|
|
val get_priority_procnames : cfg -> Procname.Set.t
|
|
|
|
(** set the function names whose address has been taken in this file *)
|
|
val set_procname_priority : cfg -> Procname.t -> unit
|
|
|
|
(** add instructions to remove temporaries *)
|
|
val add_removetemps_instructions : cfg -> unit
|
|
|
|
(** add instructions to perform abstraction *)
|
|
val add_abstraction_instructions : cfg -> unit
|
|
|
|
(** remove the return variable from the prop *)
|
|
val remove_ret : Procdesc.t -> Prop.normal Prop.t -> Prop.normal Prop.t
|
|
|
|
(** remove locals and return variable from the prop *)
|
|
val remove_locals_ret : Procdesc.t -> Prop.normal Prop.t -> Prop.normal Prop.t
|
|
|
|
(** Deallocate the stack variables in [pvars], and replace them by normal variables.
|
|
Return the list of stack variables whose address was still present after deallocation. *)
|
|
val remove_locals_formals : Procdesc.t -> Prop.normal Prop.t -> Sil.pvar list * Prop.normal Prop.t
|
|
|
|
(** remove seed vars from a prop *)
|
|
val remove_seed_vars : 'a Prop.t -> Prop.normal Prop.t
|
|
|
|
(** checks whether a cfg is connected or not *)
|
|
val check_cfg_connectedness : cfg -> unit
|
|
|
|
(** Removes seeds variables from a prop corresponding to captured variables in an objc block *)
|
|
val remove_seed_captured_vars_block : Mangled.t list -> Prop.normal Prop.t -> Prop.normal Prop.t
|
|
|
|
(** Creates a copy of a procedure description and a list of type substitutions of the form
|
|
(name, typ) where name is a parameter. The resulting procedure CFG is isomorphic but
|
|
all the type of the parameters are replaced in the instructions according to the list.
|
|
The virtual calls are also replaced to match the parameter types *)
|
|
val specialize_types :
|
|
cfg -> Procname.t -> Procname.t -> (Sil.exp * Sil.typ) list -> Procdesc.t option
|